var _gallery = function(id){
	//Retrieve object already created
	var obj = _gallery.objects[id];
	if (!obj){
	//Object doesn't exist yet
		if (this instanceof _gallery){
		//The function was called like an object, it is saved and returned
			this.id = id;
			_gallery.objects[id] = obj = this;
			$(function(){obj.init();});
		}else{
		//The function wasn't called like an object, it is called by now
			obj = new _gallery(id);
		};
	};
	return obj;
};
//All objects created with this gallery indexed by id.
_gallery.objects = {};
_gallery.prototype = {
	URLimg: '',
	data: [],
	initialize: 0,
	mouseOverTime: null,
	fadeTime: 0,
	opacity: 1,
	sliderStickClassName: '',
	imageSpacing: 5,
	msSlowSpeed: 10,
	msFastSpeed: 5,
	overSlider: false,
	downSlider: false,
	sliderSense: null,
	i: -1,
	decoder: null,
	set: function (param){
		//Set parameters given by user
		for (setting in param){
			this[setting] = param[setting];
		};
		return true;
	},
	init: function (){
		//For referening in functions
		thisG = this;
		this.decoder = CE('textarea');
		//A slider for this gallery is required
		if (this.sliderStickClassName){
			this.slider = true;
			$('#_gallerySlider' + this.id)
				//position relative required for the main TD that contains the slider
				.css('position', 'relative')
				//float left required for the main TD that contains the slider
				.css('float', 'left')
				//Add slider for this td
				.slider({
					handle: '.' + this.sliderStickClassName,
					max: 1000,
					//The function this.slide cannot  be passed directly, because the reference to the object is lost.
					slide: function(e, ui){thisG.slide(e, ui)}	
				});
			//Save width and left offset of the div that contains the carrousel
			var jQueryDiv = $('#_galleryThumbs' + this.id);
			this.divThumbLeft = jQueryDiv.offset().left;
			this.divThumbWidth = jQueryDiv.width();
		};
		//Set previous image
		this.i = this.initialize;
		this.slideView();
		return true;
	},
	showImage: function (i, moveSlider){
		if (!this.data[i]) return false;
		if (1 != this.opacity){
			if (this.data[this.i]){
				//Set opacity to the last selected thumbnails
				$('#_galleryThumb' + this.id + this.i).fadeTo(this.fadeTime, this.opacity);
			};
			//No opacity is needed for the new current image
			$('#_galleryThumb' + this.id + i).fadeTo(this.fadeTime, 1);
		};
		oGalleryTitle = GE('_galleryTitle' + this.id);
		//Set title
		if (oGalleryTitle){
			oGalleryTitle.innerHTML = this.data[i][1].replace('\\n', '<br>');
		};
		//Set description
		GE('_galleryText' + this.id).innerHTML = this.data[i][2].replace('\\n', '<br>');
		var oImage = GE('_galleryImage' + this.id);
		//Set image and properties
		oImage.setAttribute('src', this.URLimg + this.data[i][0]);
		oImage.setAttribute('alt', this.data[i][1]);
		oImage.setAttribute('width', this.data[i][3]);
		oImage.setAttribute('height', this.data[i][4]);
		if (!this.data[i][4]){
			//Not using jquery methods, because it tends to change scrolling
			oImage.removeAttribute('width');
		};
		if (!this.data[i][3]){
			//Not using jquery methods, because it tends to change scrolling
			oImage.removeAttribute('height');
		};
		this.i = i;
		return true;
	},
	slideView: function(){
		if (!this.slider || -1 == this.i) return true;
		//Information
		var jQueryThumb = $('#_galleryThumb' + this.id + this.i);
		var offsetThumb = jQueryThumb.offset();
		var widthThumb = jQueryThumb.width();
		var slideWidth = this.slideWidth();
		var slidedPixels = this.slidedPixels();
		var slideQuantity = 0;
		//Top vision is the last pixel on the right that should be visible
		var topVision = widthThumb + offsetThumb.left - this.divThumbLeft;
		if (topVision > this.divThumbWidth){
			//The screen must be scrolled to the position where the topVision is the last pixel on the right.
			slideQuantity = topVision - this.divThumbWidth + this.imageSpacing;
		};
		var minVision = offsetThumb.left - this.divThumbLeft;
		//Min vision is the first pixel on the left of a thumbnail that should be visible
		if (minVision < 0){
			//minVision is just the amount of pixels the scroller should be moved to the left.
			//The actual slided pixels are reduced by this amount and 5 pixels (because of paddings, borders or margins)
			slideQuantity = minVision - this.imageSpacing;
		};
		this.moveSlider(slideQuantity + slidedPixels);
		return true;
	},
	mouseOverThumb: function(i){
		this.timer = setTimeout("_gallery('"+this.id+"').showImage("+i+");", this.mouseOverTime);
	},
	mouseOutThumb: function(){
		clearTimeout(this.timer);
	},
	first: function(){
		this.showImage(0);
		this.slideView();
	},
	previous: function(){
		var i = this.i - 1;
		//If less than null, show the last one
		if (i < 0) this.last();
		//Show previous image
		else{
			this.showImage(i);
			this.slideView();
		};
	},
	next: function(){
		var i = this.i + 1;
		//If more than existent images, show the first one
		if (i > this.data.length - 1) this.first();
		//Show the next one
		else{
			this.showImage(i);
			this.slideView();
		};
	},
	last: function(){
		this.showImage(this.data.length - 1, true);
		this.slideView();
	},
	slideWidth: function(){
		//Netscape doesn't know the size of the table when images are not loaded, it is easier to call it each time
		return $('#_gallerySliderTable' + this.id).width() - $('#_galleryThumbs' + this.id).width() + this.imageSpacing * 2//image borders, paddings or borders
	},
	moveSlider: function(pixels){
		//Move the slider to the given position
		$('#_gallerySlider' + this.id).slider('moveTo', (pixels * 1000 / this.slideWidth()).toFixed(0));
	},
	slidedPixels: function (){
		//This value may not be set (that's why we give zero like an option
		return - parseInt(GE('_gallerySliderTable' + this.id).style.marginLeft) || 0;
	},
	slide: function(e, ui){
		//Move thumbnails
		var val = ui.value;
		if (0 != val){
			val = val * this.slideWidth() / 1000;
		};
		GE('_gallerySliderTable' + this.id).style.marginLeft = - val.toFixed(0) + 'px';
	},
	jQuerySlider: function(){
		//There are two tables
		return 	$('#_galleryThumbs' + this.id + ' > table').eq(0);
	},
	intevalSlider: function(){
		clearInterval(this.sliderInterval);
		var move = 5;
		if ('left' == this.sliderSense){
			move *= -1;
		};
		var msSpeed = 0;
		if (this.downSlider){
			msSpeed = this.msFastSpeed;
		}else if (this.overSlider){
			msSpeed = this.msSlowSpeed;
		}else{
			return;
		};
		this.sliderInterval = setInterval("with(_gallery('" + this.id + "')){moveSlider(slidedPixels() + " + move + ");}", msSpeed);
	},
	mouseOverSlider: function(sense){
		this.overSlider = true;
		this.sliderSense = sense;
		this.intevalSlider();
	},
	mouseOutSlider: function(){
		this.overSlider = false;
		this.downSlider = false;
		this.intevalSlider();
	},
	mouseDownSlider: function(sense){
		this.overSlider = true;
		this.downSlider = true;
		this.sliderSense = sense;
		this.intevalSlider();
	},
	mouseUpSlider: function(sense){
		this.downSlider = false;
		this.sliderSense = sense;
		this.intevalSlider();
	}
};
