function CloneListViewer() {
	var that = this;

	// Private properties

	this.viewer_box = null;
	this.viewer_content = null;
	this.viewer_slider = null;
	this.viewer_basket = null;

	this.list_idx = 0;

	this.next_idx = null;

	this.is_running = false;

	this.mousedown_viewer_box = false;
	this.mousedown_x = 0;

	// ajax_list: it's created automatically using ajax queries contained in list array

	this.ajax_list = null;
	
	this.backward_button = null;
	this.forward_button = null;

	this.timer = null;

	// Public properties

	this.list_type = LIST_VIEWER_IMAGE;

	this.slide_duration = DEFAULT_SLIDE_DURATION;
	this.slide_easing = DEFAULT_SLIDE_EASING;	// JQuery easing functions: "linear", "swing"
	this.visible_basket = DEFAULT_VISIBLE_BASKET;

	this.infinite = false;

	// To auto slide the list

	this.auto_slide = false;
	this.auto_slide_direction = SLIDE_FORWARD;
	this.auto_slide_interval = DEFAULT_AUTO_SLIDE_INTERVAL;
	this.auto_slide_stop_mouse_over = false;

	// To slide the list on mouse down

	this.mousedown_slide = false;

	// width: basket width
	// viewer_box.width: this.width * this.visible_basket

	this.width = null;
	this.height = null;

	// list: JS array(var arr = ['data1', 'data2', ...]) or JQuery element($(".data"))

	this.list = null;

	// Private methods

	this.disable_selection = function(element) {
                $(element).css({
                        	"cursor" : "default",
                        	"MozUserSelect" : "none"
                	})
                	.bind('selectstart', function() {
                	        return false;
                	})
                	.mousedown(function() {
                	        return false;
                	});
	};

	this.get_visible_length = function() {
		var len = that.list.length - that.visible_basket;

		return len;
	};

	this.start_auto_slide = function() {
		if(that.is_running)
			return;

                that.timer = setTimeout(function() {
			if(!that.infinite && that.list_idx == that.get_visible_length())
				that.auto_slide_direction = SLIDE_BACKWARD;

			if(!that.infinite && that.list_idx == 0)
				that.auto_slide_direction = SLIDE_FORWARD;

                        that.slide();
                }, that.auto_slide_interval);
	};

	this.stop_auto_slide = function() {
        	clearTimeout(that.timer);
        	that.timer = null;
	};

	this.mousedown_move = function(e) {
		if(that.is_running)
			return;

		if(that.mousedown_viewer_box) {
			if(e.clientX < that.mousedown_x) {
				if(!that.infinite && that.list_idx == that.get_visible_length())
					return;

				that.slide(SLIDE_FORWARD);
			}
			else {
				if(!that.infinite && that.list_idx == 0)
					return;

				that.slide(SLIDE_BACKWARD);
			}
		}
	};

	this.get_list_element = function(parent_element, idx) {
		var basket = null;

		if(that.list_type == LIST_VIEWER_IMAGE)
			basket = $(that.list[idx]).clone();
		else {
			if(that.ajax_list != null && that.ajax_list[idx] != null && that.ajax_list[idx] != undefined)
				basket = that.ajax_list[idx];
			else {
				basket = "<div class=\"" + VIEWER_AJAX_LOADER_BG + "\" style=\"background: " + LOADER_BACKGROUND + "; width: " + that.width + "; height: " + that.height + ";\">";
				basket += "</div>";
				basket += "<div class=\"" + VIEWER_AJAX_LOADER + "\" style=\"display: none; width: " + that.width + "; height: " + that.height + ";\"></div>";

				/* 
				   + Ajax query writes:
				   - that.ajax_list[idx]: for next request
				   - id element: for current empty element
				*/

				var ajax_setting = that.list[idx];
				var success_function = ajax_setting["success"];

				ajax_setting["dataType"] = "html";
                		ajax_setting["success"] = function(data) {
					if(success_function != null)
						success_function(); 

					if(that.ajax_list == null)
						that.ajax_list = new Array();

					that.ajax_list[idx] = data;

					parent_element.children("." + VIEWER_AJAX_LOADER_BG).fadeOut(800);
					parent_element.children("." + VIEWER_AJAX_LOADER)
						.html(data)
						.fadeIn(800);
                		};

                		$.ajax(ajax_setting);
			}
		}

		return basket;
	};

	this.set_viewer_content = function() {
		$(that.viewer_content).html("");

		for(var i = 0;i < that.visible_basket;i++) {
			var idx = that.list_idx + i;

			if(idx >= that.list.length)
				idx -= that.list.length;

			var element = that.get_list_element($(that.viewer_content), idx);
			element = $(element).css({"float" : "left"});

		        $(that.viewer_content).append(element);
		}
	};

        this.slide = function(direction) {
		if(that.list.length <= that.visible_basket)
			return;

		that.is_running = true;

                var button_name = "#" + $(this).attr("id");

		$(that.viewer_content).html("");

		if(that.backward_button != null)
	                $(that.backward_button).unbind("click", that.slide);

		if(that.forward_button != null)
	                $(that.forward_button).unbind("click", that.slide);

		that.stop_auto_slide();

		$(that.viewer_box).unbind("mousemove", that.mousedown_move);

                if(button_name == that.backward_button || 
		   (direction != null && direction == SLIDE_BACKWARD) ||
		   (direction == null && $(this).attr("id") == null && that.auto_slide_direction == SLIDE_BACKWARD)) {
			that.list_idx--;

			if(that.list_idx < 0)
				that.list_idx = that.list.length - 1;

                        $(that.viewer_slider).css({"left" : "-" + that.width});

			for(var i = 0;i < (that.visible_basket + 1);i++) {
				if(that.next_idx != null && i == 0)
					var idx = that.next_idx;
				else {
					var idx = that.list_idx + i;

					if(idx >= that.list.length)
						idx -= that.list.length;
				}

				var element = that.get_list_element($(that.viewer_basket).eq(i), idx);
                        	$(that.viewer_basket).eq(i).html(element);
			}

			if(that.next_idx != null)
				that.list_idx = that.next_idx;

                        var viewer_slider_left = "0px";

			if(that.forward_button != null && $(that.forward_button).css("display") == "none")
	                        $(that.forward_button).fadeIn();
                }
                else {
			that.list_idx++;

			if(that.list_idx == that.list.length)
				that.list_idx = 0;

                        $(that.viewer_slider).css({"left" : "0px"});

			for(var i = 0;i < (that.visible_basket + 1);i++) {
                                var idx = that.list_idx + i - 1;

                                if(idx < 0)
                                        idx = that.list.length - 1;
				else if(idx >= that.list.length)
					idx -= that.list.length;

				var element = that.get_list_element($(that.viewer_basket).eq(i), idx);
                        	$(that.viewer_basket).eq(i).html(element);

				if(that.next_idx != null && i == 0)
					that.list_idx = that.next_idx;
                        }

                        var viewer_slider_left = "-" + that.width;

			if(that.backward_button != null && $(that.backward_button).css("display") == "none")
                        	$(that.backward_button).fadeIn();
                }

		that.next_idx = null;

                if(that.backward_button != null && !that.infinite && that.list_idx == 0)
                        $(that.backward_button).fadeOut();

                if(that.forward_button != null && !that.infinite && that.list_idx == that.get_visible_length())
                        $(that.forward_button).fadeOut();

                $(that.viewer_slider)
			.css({"display" : "block"})
                	.animate({"left" : viewer_slider_left},
                        	that.slide_duration,
                        	that.slide_easing,
                        	function() {
					that.is_running = false;

					that.set_viewer_content();
                        	        $(that.viewer_slider).css({"display" : "none"});

					if(that.backward_button != null)
                				$(that.backward_button).bind("click", that.slide);

					if(that.forward_button != null)
	                			$(that.forward_button).bind("click", that.slide);

					if(that.auto_slide)
						that.start_auto_slide();

					if(that.mousedown_slide)
						$(that.viewer_box).bind("mousemove", that.mousedown_move);
                        	});
        };
}

CloneListViewer.prototype.get_list_idx = function() {
        var that = this;

        return that.list_idx;
}

CloneListViewer.prototype.set_viewer_box = function(list_viewer) {
	var that = this;
	
	var width = parseInt(that.width.replace("px", ""));

	// Set viewer box

	$(list_viewer)
		.append("<div class=\"" + VIEWER_BOX + "\"></div>")

	that.viewer_box = $(list_viewer).children("." + VIEWER_BOX);

	$(that.viewer_box)
		.css({"overflow" : "hidden",
			"position" : "relative",
        		"top" : "0px",
        		"left" : "0px",
			"width" : (width * that.visible_basket) + "px",
			"height" : that.height})
		.append("<div class=\"" + VIEWER_CONTENT + "\"></div>")
		.append("<div class=\"" + VIEWER_SLIDER + "\"></div>");

	that.viewer_content = $(that.viewer_box).children("." + VIEWER_CONTENT);
	that.viewer_slider = $(that.viewer_box).children("." + VIEWER_SLIDER);

	if(that.mousedown_slide) {
		$(that.viewer_box)
			.mousedown(function(e) {
				that.mousedown_viewer_box = true;
				that.mousedown_x = e.clientX;
			})
			.mouseup(function() {
				that.mousedown_viewer_box = false;
			})
			.mouseout(function() {
				that.mousedown_viewer_box = false;
			})
			.bind("mousemove", that.mousedown_move);

		that.disable_selection(that.viewer_box);
	}

	// Set viewer content

	$(that.viewer_content).css({"position" : "absolute",
        	"top" : "0px",
        	"left" : "0px",
		"width" : (width * that.visible_basket) + "px",
        	"height" : that.height});

	// Insert slider

	$(that.viewer_slider)
		.css({"position" : "absolute",
			"display" : "none",
        		"top" : "0px",
        		"left" : "0px",
			"width" : (width * (that.visible_basket + 1)) + "px",
        		"height" : that.height});

	// Insert slider baskets

	for(var i = 0;i < (that.visible_basket + 1);i++) {
		$(that.viewer_slider)
			.append("<div class=\"" + VIEWER_BASKET + "\"></div>");
 	}

	that.viewer_basket = $(that.viewer_slider).children("." + VIEWER_BASKET);

        $(that.viewer_basket).css({"float" : "left",
		"width" : that.width,
        	"height" : that.height});
}

CloneListViewer.prototype.set_buttons = function(backward_button, forward_button) {
	var that = this;

	if(backward_button != null) {
		that.backward_button = backward_button;
		$(that.backward_button)
			.css({"cursor" : "pointer"});

		if(!that.infinite) 
			$(that.backward_button).css({"display" : "none"});
	}

	if(forward_button != null) {
		that.forward_button = forward_button;
		$(that.forward_button)
			.css({"cursor" : "pointer"});
	}
}

// Set next list index programmatically 

CloneListViewer.prototype.set_list_idx = function(idx, direction) {
	var that = this;
	var idx = parseInt(idx);

	if(idx == that.list_idx || idx < 0 || idx > that.list.length)
		return false;

	that.next_idx = idx;

        if(!that.is_running) 
		that.slide(direction);
}

CloneListViewer.prototype.set_auto_slide = function(cmd) {
	var that = this;

	if(cmd == AUTO_SLIDE_START) {
		that.auto_slide = true;
		that.start_auto_slide();
	}
	else if(cmd == AUTO_SLIDE_STOP) {
		that.auto_slide = false;
		that.stop_auto_slide();
	}
}

/*
 * + preload usage example:
 *
 * - img_list: a list of image addresses
 *
 * list_viewer.preload(img_list,
 * 	LIST_VIEWER_PRELOAD_IMAGE,
 * 	function() {
 * 		list_viewer.start();
 * 	});
 *
 * - pre_ajax_list: a list of ajax queries
 *
 * list_viewer.preload(pre_ajax_list,
 *	LIST_VIEWER_PRELOAD_AJAX,
 *	function() {
 *		list_viewer.start();
 *	});
 */

CloneListViewer.prototype.preload = function(preload_list, type, loaded_function) {
	var that = this;

        $(that.viewer_content).html(LOADER_DIV);
	
	if(type == LIST_VIEWER_PRELOAD_IMAGE) {
		var list_idx = 0;

		$.each(preload_list, function(k, preload_e) {
			var img = new Image();

			img.onload = (
				function() {
					if((list_idx + 1) == preload_list.length) {
						if(loaded_function != null)
							loaded_function();
					}

					list_idx++;
				}
			);

			img.src = preload_e;
		});
	}
	else if(type == LIST_VIEWER_PRELOAD_AJAX) {
		var list_idx = 0;

		$.each(preload_list, function(k, ajax_setting) {
			var success_function = ajax_setting["success"];

                        ajax_setting["dataType"] = "html";
                        ajax_setting["success"] = function(data) {
				if(success_function != null)
					success_function();

                        	if(that.ajax_list == null)
                        		that.ajax_list = new Array();

                        	that.ajax_list[list_idx] = data;

				if((list_idx + 1) == preload_list.length) {
					if(loaded_function != null)
						loaded_function();
				}

				list_idx++;
                        };

                        $.ajax(ajax_setting);
		});
	}
}

CloneListViewer.prototype.start = function(first_idx) {
	var that = this;

	if(first_idx != null)
		that.list_idx = first_idx;

	that.set_viewer_content();

	if(that.backward_button != null)
        	$(that.backward_button).bind("click", that.slide);

	if(that.forward_button != null)
	        $(that.forward_button).bind("click", that.slide);

        if(that.auto_slide) {
		that.start_auto_slide();

		if(that.auto_slide_stop_mouse_over) {
	                $(that.viewer_box)
        	                .hover(function() {
                	                that.auto_slide = false;
                        	        that.stop_auto_slide();
                        	},
                        	function() {
                        	        that.auto_slide = true;
                        	        that.start_auto_slide();
                        	});
		}
        }
}

