/**
 * @constructor
 */
function Slideshow(){
	
	var _imgUrl = "image.php?id={url}&w={w}&h={h}";
	var _configUrl = "slideshow_config.json";
	var _imagesUrl = "slideshow_images.json";
	
	// Default image index
	var _imageIndex = -1;
	// Default config values.
	// Transition speed (ms).
	var _tSpeed = 1000;
	// Transition type (slide, fade).
	var _tType = "slide";
	// Transition delay
	var _tDelay = 1000;
	// Auto play.
	var _tAuto = true;
	// Stop playing when the user navigates.
	var _tStopOnNav = true;
	// Order of slides.
	var _order = "random";
	// Display the captions.
	var _displayCaption = true;
	// Display the descriptions.
	var _displayDescription = true;
	// The z-index counter.
	var _tZIndex = 0;
	// The last displayed image.
	var _lastImg;

	// References to dom elements.
	// The slideshow container.
	var _slideshow;
	// The container for slieshow_images
	var _frame;
	// Next button
	var _navPrev;
	// Previous button
	var _navNext;
	// Selector panel
	var _selector;
	// Image container.
	var _imagePanel;
	// Caption container.
	var _caption;
	// Description container.
	var _description;
	// The dummy selector button (gets copied).
	var _selectorButton;
	// List of selector buttons.
	var _selectorButtons;
	// Pause button
	var _pauseButton;
	// Width of the viewport
	var _viewHeight;
	// Height of the viewport.
	var _viewWidth;
	// Array of image objects.
	var _images;
	// True if paused.
	var _paused;
	// Transition interval.
	var _tInt;
	// Currently selected selector button.
	var _currentSelectorButton;
	// Preloader container.
	var _loader;
	// True if image is currently loading.
	var _loading;

	var _throw = function(msg){
		throw new Error(msg);
	};
		
	var _createSelectorButton = function(index){
		var image = _images[index];
		var element = index == 0 ? _selectorButton : _selectorButton.clone();
		var button = {
			image:image,
			index:index,
			element:element
		};
		_enableSelectorButton(button);
		return button;
	};

	/**
	* Initialize the slideshow and references to dom elements.
	*/
	var _init = function(){
		_imageIndex = -1;
		// Default config values.
		_tSpeed = 1000;
		_tType = "slide";
		_tDelay = 1000;
		_tAuto = true;
		_tStopOnNav = true;
		_order = "random";
		_displayCaption = true;
		_displayDescription = true;
		// Get references to dom elements.
		if(!(_slideshow = $("#slideshow")))
			_throw("Slideshow container not found.");
		_navPrev = $("#slideshow_nav_prev");
		_navNext = $("#slideshow_nav_next");
		_selector = $("#slideshow_selector");
		if(!(_frame = $("#slideshow_frame")))
			_throw("Frame not found.");
		if(!(_imagePanel = $("#slideshow_images")))
			_throw("Image panel not found.");
		_caption = $("#slideshow_caption");
		_description = $("#slideshow_description");
		if(_selector && !(_selectorButton = $("#slideshow_selector_button")))
			_throw("Selector panel found, but no selector button.");
		_pauseButton = $("#slideshow_pause");
		_loader = $("#slideshow_loader");
		_viewHeight = _frame.height();
		_viewWidth = _frame.width();
		_loadConfig();
	};
	
	/**
	* Load the configuration file.
	*/
	var _loadConfig = function(){
		$.ajax( _configUrl, {
			complete:function(xhr, status){
				_configLoaded(xhr);
			}
		});
	};
	
	/**
	* Called when configuration is loaded.
	*/
	var _configLoaded = function(xhr){
		var response = null;
		try{
			response = $.parseJSON(xhr.responseText);
			if(response.transition){
				_tSpeed = response.transition.speed;
				_tType = response.transition.type;
				_tDelay = response.transition.delay;
				_tAuto = response.transition.autoStart;
				_tStopOnNav = response.transition.stopOnNav;
				switch(_tType){
					case "slide":
						_imagePanel.css("left", _viewWidth + "px");
						break;
				}
			}
			if(response.order){
				_order = response.order;
			}
			if(response.caption){
				_displayCaption = response.caption.display;
			}
			if(response.description){
				_displayDescription = response.description.display;
			}
		}catch(err){
			err;
		}
		_initViewer();
		_loadImages();
	};
	
	/**
	* Load the image list.
	*/
	var _loadImages = function(){
		$.ajax(_imagesUrl, {
			complete:function(xhr, status){
				_imagesLoaded(xhr);
			}
		});
	};

	/**
	* Called when the image list has loaded.
	*/
	var _imagesLoaded = function(xhr){
		try{
			_images = $.parseJSON(xhr.responseText);
		}catch(err){
			err;
		}
		_initSelector();
		_next();
		if(_tAuto && !_paused)
			_startTimer();
	};
	
	/**
	* Start the slideshow timer.
	*/
	var _startTimer = function(){
		clearInterval(_tInt);
		_tInt = setInterval(function(){
			_next();
		}, _tDelay < 1 ? 1000 : _tDelay);
	};

	/**
	* Stop the slideshow timer.
	*/
	var _stopTimer = function(){
		clearInterval(_tInt);
	};

	/**
	* Initialize the selector panel.
	*/
	var _initSelector = function(){
		if(_selector && _selectorButton){
			var button = null;
			_selectorButtons = [];
			if(_images){
				for(var i=0;i<_images.length;++i){
					button = _createSelectorButton(i);
					_selectorButtons.push(button);
					_selector.append(button.element);
				}
			}
		}
	};

	/**
	* Sets the selector button to the enabled state
	*/
	var _enableSelectorButton = function(button){
		if(button){
			button.element.click(function(){
				_selectorClicked(button);
			});
			button.element.removeClass("disabled");
		}	
	};

	/**
	* Sets the selector button to the disabled state
	*/
	var _disableSelectorButton = function(button){
		if(button){
			button.element.click(null);
			button.element.addClass("disabled");
		}
	};

	/**
	* Called when a selector button is clicked.
	*/
	var _selectorClicked = function(button){
		if(button){
			_selectImage(button.index);
			if(_tStopOnNav){
				_stopTimer();
			}else if(!_paused){
				// resets timer.
				_startTimer();
			}
		}
	};

	/**
	* Selects the selector button corresponding to the given index.
	*/
	var _selectSelectorButton = function(index){
		_enableSelectorButton(_currentSelectorButton);
		_currentSelectorButton = _selectorButtons[index];
		_disableSelectorButton(_currentSelectorButton);
	};

	/**
	* Initializes the viewer UI.
	*/
	var _initViewer = function(){
		if(_navNext){
			_navNext.click(function(){
				_nextClicked();
			});
		}
		if(_navPrev){
			_navPrev.click(function(){
				_prevClicked();
			});
		}
		if(_pauseButton){
			_pauseButton.click(function(){
				_pauseClicked();
			});
		}
	};

	var _pauseClicked = function(){
		if(!_paused){
			_paused = true;
			_stopTimer();
			_pauseButton.removeClass("playing");
			_pauseButton.addClass("paused");
		}else{
			_paused = false;
			_startTimer();
			_pauseButton.removeClass("paused");
			_pauseButton.addClass("playing");
			_next();
		}
	};

	var _nextClicked = function(){
		_next();
		if(_tStopOnNav){
			_stopTimer();
		}else if(!_paused){
			// reset timer
			_startTimer();
		}
	};

	var _prevClicked = function(){
		_prev();
		if(_tStopOnNav){
			_stopTimer();
		}else if(!_paused){
			// reset timer
			_startTimer();
		}
	};
	
	var _next = function(){
		if(_images && !_loading){
			var idx = _imageIndex;
			if(idx>=_images.length-1)
				idx = -1;
			_selectImage(idx+1);
		}
	};

	var _prev = function(){
		if(_images && !_loading){
			var idx = _imageIndex;
			if(idx<=0)
				idx = _images.length;
			_selectImage(idx-1);
		}
	};

	var _selectImage = function(index){
		_imageIndex = index;
		var image = _images[index];
		if(!image.img)
			image.img = _createSlide(index, image);
		if(!image.loaded){
			_loading = true;
			_loader.stop();
			_loader.fadeTo(500, 1);
			setTimeout(function(){
				_selectImage(index);
			}, 100);
		}else{
			_loading = false;
			_loader.stop();
			_loader.fadeTo(_tSpeed, 0);
			_imageIndex = index;
			_selectSelectorButton(index);
			switch(_tType){
				case "fade":
					_selectImageFade(image, index);
					break;
				default:
					_selectImageSlide(image, index);
			}
		}
	};

	var _selectImageFade = function(image, index){
		var img = image.img;
		_setToTop(image);
		if(!image.initialized){
			_imagePanel.append(img);
			image.initialized = true;
		}
		if(_caption)
			_caption.html(image.caption);
		if(_description)
			_description.html(image.description);
		img.css("opacity", "0");
		img.css("left", "0");
		if(_lastImg){
			_lastImg.fadeTo(_tSpeed, 0);
			_lastImg = null;
		}
		_lastImg = img;
		if(!image.loaded){
			var lint = setInterval(function(){
				if(image.loaded){
					clearInterval(lint);
					img.stop();
					img.fadeTo(_tSpeed, 1);
				}
			}, 100);
		}else{
			img.stop();
			img.fadeTo(_tSpeed, 1);
		}
	};

	var _selectImageSlide = function(image, index){
		var img = image.img;
		if(!image.initialized){
			img.css("left", (index * _viewWidth) + "px");
			img.css("top", "0");
			_imagePanel.append(img);
			image.initialized = true;
		}
		if(_caption)
			_caption.html(image.caption);
		if(_description)
			_description.html(image.description);
		_imagePanel.animate({left:(-index * _viewWidth) + "px"}, {duration:_tSpeed,queue: false});
	};

	var _setToTop = function(image){
		for(var i=0;i<_images.length;++i){
			if(_images[i] != image && _images[i].img)
				_images[i].img.css("zIndex", parseInt(_images[i].img.css("zIndex"))-1);
		}
		if(image.img)
			image.img.css("zIndex", _images.length-1);
	};

	var _formatImgUrl = function(url, image){
		return url.replace("{url}", image.image.url).replace("{w}", _viewWidth).replace("{h}", _viewHeight);
	};
		
	var _createSlide = function(index, image){
		if(image.html){
			return _createHtmlSlide(index, image);
		}else{
			return _createImageSlide(index, image);
		}
	}
	
	var _createImageSlide = function(index, image){
		var div = document.createElement("div");
		var img = document.createElement("img");
		img.onload = function(){
			if(this.complete){
				image.loaded = true;
			}else{
				// Here, this refers to the image element.
				var i = this;
				setTimeout(function(){
					i.onload();
				}, 100);
			}
		}
		img.alt = image.caption;
		img.src = _formatImgUrl(_imgUrl, image);
		var link = image.image.link;
		if(link){
			var a = document.createElement("a");
			a.href = link.url;
			a.target = link.target;
			a.title = link.title;
			a.appendChild(img);
			img = a;
		}
		div.appendChild(img);
		div = $(div);
		div.css({
			position:"absolute",
			top:"0px",
			left:"0px",
			width:_viewWidth + "px",
			height:_viewHeight + "px",
			overflow:"hidden",
			zIndex:_tZIndex++
		});
		return div;
	}
		
	var _createHtmlSlide = function(index, image){
		var div = document.createElement("div");
		div.innerHTML = image.html;
		div = $(div);
		div.css({
			position:"absolute",
			top:"0px",
			left:"0px",
			width:_viewWidth + "px",
			height:_viewHeight + "px",
			overflow:"hidden",
			zIndex:_tZIndex++
		});
		image.loaded = true;
		return div;
	}

	_init();

};

var slideshow = null;
$(document).ready(function(){
	slideshow = new Slideshow();
});
