/**
 * sfPhotoGallery
 *
 * @version: 1.0
 * @author SimpleFlame http://www.simpleflame.com/
 *
 * Available options:
 *  transition - by default "fade", can also use FALSE to disable transition or any of the jQuery UI effects if UI is included. !NOTICE - will throw an exception if you try to use an effect without including UI
 *  transitionSpeed - photo transition speed, by default 300 ms
 *  transitionInOptions - options used on the "in" transition if one of the UI effects is used 
 *  transitionOutOptions - options used on the "out" transition if one of the UI effects is used 
 *  goodbarry - boolean flag, by default "true". If turned on and no ".thumb" element is present in the data list, then GB image resize utility will be used
 *  thumbsLocation - top|right|bottom|left - location of thumbs slider in reference to the main image area, by default "left"
 *  descriptionLocation - top|right|bottom|left - location of the description area in reference to the main image area, by default bottom
 *  autorotate - boolean, if true will add an option to start/top autorotation, by default false
 *  autorotateDuration - if "autorotate" option is set to true, it determines how long image is visilbe, by default 3000 ms
 *  thumbsPerPage - number of thumbnails visible at once, by default 8
 *  numbersPerPaginationPage - number of items visible on one page in the pagination list. This option has to be set depending on the layout, as it won't work otherwise
 *  thumbWidth - width of thumbnail to show/generate
 *  thumbHeight - height of thumbnail to show/generate
 */ 
(function(){
	
	/**
	 * Constructor for this item
	 */
	var sfPhotoGallery = function(el, options){
		//hide the list from which data is being read
		this.dataList = jQuery(el).hide();		
		this.options = {};
		
		//initial setup
		this.options.transition = typeof options.transition === "undefined" ? 'fade' : options.transition;
		this.options.transitionSpeed = options.transitionSpeed || 300;
		this.options.transitionInOptions = options.transitionInOptions || {};
		this.options.transitionOutOptions = options.transitionOutOptions || {};		
		
		this.options.goodbarry = typeof options.goodbarry === 'boolean' ? options.goodbarry : true;
		
		this.options.thumbsLocation = options.thumbsLocation || 'left';
		this.options.descriptionLocation = options.descriptionLocation || 'bottom';
		
		this.options.autorotate = typeof options.autorotate === 'boolean' ? options.autorotate : false;
		this.options.autorotateDuration = options.autorotateDuration || 3000;
		
		this.options.thumbsPerPage = options.thumbsPerPage || 8;
		this.options.numbersPerPaginationPage = options.numbersPerPaginationPage || 20;
		
		this.options.thumbWidth = options.thumbWidth || 120;
		this.options.thumbHeight = options.thumbHeight || 80;
		
		//read all data items
		this.dataItems = this.dataList.find('li').map(function(index,item){
			item = jQuery(item);
			return {
				index : index,
				media : item.find('.media').html(),
				thumb : item.find('.thumb').attr('src'),
				title : item.find('.title').html(),
				description : item.find('.description').html()
			};
		});
		this.count = this.dataItems.length;				
  };

	/** 
	 * Run functions creating all important parts of the structure 
	 */
	sfPhotoGallery.prototype.build = function(){
		
		//create main areas in the structure
		this.thumbsSlider = this.createThumbsSlider();		
		this.paginationWrapper = this.createPagination();		
		this.mediaWrapper = this.createMediaWrapper();		
		this.descriptionWrapper = this.createDescriptionWrapper();
				
		//replace the data list with newly constructed structures		
		this.dataList.replaceWith(this.buildStructure());
		
		//activate first element
		this.show(0);		
		
		//update width of the sliding wrappers			
		this.thumbsContainerWidth = this.thumbsSlider.width();
		this.$slider.width(this.thumbsContainerWidth * this.thumbPagesCount);
		
		//we want to move by the width of n - 2 elements in case of the pagination
		this.paginationContainerWidth = Math.floor(this.paginationWrapper.find('.sfmg-pagination-pages').width() - this.paginationWrapper.find('.sfmg-pagination-pages li').width() * 2);
		this.$pagination.width(this.paginationContainerWidth * this.paginationPagesCount);
	};
	
	/**
	 * Positions create components depending on the options provided by the user
	 */
	sfPhotoGallery.prototype.buildStructure = function(){
		var container = jQuery('<div class="sfmg"/>'),
		    colA = jQuery('<div class="sfmg-wrapper-a"/>'),
		    colB = jQuery('<div class="sfmg-wrapper-b"/>'),				
				t = this.thumbsSlider,
				m = jQuery('<div class="sfmg-wrapper-c"/>').append(this.mediaWrapper, this.paginationWrapper),
				d = this.descriptionWrapper;
		
		container.append(colA, colB);

		colA.append(t);
		colB.append(m,d);
		
		var location = this.options.descriptionLocation + '-' + this.options.thumbsLocation;
		
		switch(location) {
			case 'top-top':
			case 'left-left':
				colA.append(d,t);
				colB.append(m);
				break;
			case 'top-right':
			case 'top-bottom':
				colA.append(d,m);
				colB.append(t);
				break;
			case 'top-left':
			  colA.append(t);
			  colB.append(d,m);
				break;
			case 'right-right':
			case 'bottom-bottom':
			  colA.append(m);
				colB.append(d,t);
				break;
			case 'right-bottom':
				colA.append(m,t);
				colB.append(d);
				break;
			case 'right-top':
			case 'right-left':
			  colA.append(t,m);
				colB.append(d);
				break;
			case 'bottom-top':
			case 'bottom-left':
				colA.append(t);
				colB.append(m,d);
				break;
			case 'bottom-right':
			  colA.append(m,d);
				colB.append(t);
				break;
			case 'left-top':
				colA.append(d);
				colB.append(t,m);
				break;
			case 'left-right':
			case 'left-bottom':
				colA.append(d);
				colB.append(m,t);
				break;
		}
				
		//this floats columns
		if (location.match(/(left|right)/)){
			colA.addClass('sfmg-col-left');
			colB.addClass('sfmg-col-right');			
		}
		
		return container;
	};
	
	/** 
	 * Start timer that cycles over all thumbs automatically over a set period of miliseconds
	 */
	sfPhotoGallery.prototype.restartAutorotate = function(){
		var self = this;
		this.stopAutorotate();
		
		//duration includes in and out transitions for each slide
		var duration = this.options.autorotateDuration + 2 * this.options.transitionSpeed;
		
		this.$autorotate = window.setInterval(function(){
			var nextItem = self.currentItem + 1;
			if (nextItem === self.count){
				nextItem = 0;
			}
			self.show(nextItem);			
		}, duration);		
	};
	
	/**
	 * Disables autorotation
	 */
	sfPhotoGallery.prototype.stopAutorotate = function(){
		window.clearInterval(this.$autorotate);
	};
	
	/**
	 * Media wrapper is where the images/videos are being displayed
	 */ 
	sfPhotoGallery.prototype.createMediaWrapper = function(){
		//media wrapper
		var media = jQuery('<div class="sfmg-main"/>');
		this.$media = jQuery('<div class="sfmg-main-media"/>');
		media.append(this.$media);
		return media;		
	};
	
	/**
	 * Creates wrappers for description and title
	 */ 
	sfPhotoGallery.prototype.createDescriptionWrapper = function(){
		var description = jQuery('<div class="sfmg-description"/>"');
		this.$title = jQuery('<h3 class="sfmg-title"/>');
		this.$description = jQuery('<p class="sfmg-content"/>');
		description.append(this.$title, this.$description);
		return description;
	};
	
	/**
	 * Creates thumbnail slider
	 */
	sfPhotoGallery.prototype.createThumbsSlider = function(){
		var self = this;
		// THUMBS
		this.thumbPagesCount	= Math.ceil(this.count / this.options.thumbsPerPage);
		this.thumbsContainerWidth = 0;
		this.currentThumbPage = 0;		
		
		var slider = jQuery('<div class="sfmg-thumbs"><ul class="sfmg-thumbs-nav"><li class="sfmg-thumbs-nav-prev"/><li class="sfmg-thumbs-nav-next"/></ul></div>');
		//thumbnail slider navigation

		this.$slider = jQuery('<div class="sfmg-thumbs-wrapper"/>');
		slider.prepend(this.$slider);
		
		this.$thumbPrev = jQuery('<a href="#">Previous</a>').click(function(e){
			e.preventDefault();
			self.cycleThumbs(self.currentThumbPage - 1);
		});

		this.$thumbNext = jQuery('<a href="#">Next</a>').click(function(e){
			e.preventDefault();
			self.cycleThumbs(self.currentThumbPage + 1);
		});
		
		slider.find('.sfmg-thumbs-nav-prev').append(this.$thumbPrev);
		slider.find('.sfmg-thumbs-nav-next').append(this.$thumbNext);

		//this function is utilized a few lines below
		var appendItem = function(index, item){
			var li = self.createThumbnail(item);
			slider.find('.sfmg-thumbs-wrapper ul:last').append(li);			
		};
				
		/* create thumbnail pages */
		for(var i = 0, start, end; i < this.thumbPagesCount; i++){
			slider.find('.sfmg-thumbs-wrapper').append('<ul/>');
			
			start = i * this.options.thumbsPerPage;
			end = start + this.options.thumbsPerPage;
			//fetch data items for every page
			jQuery.each(this.dataItems.slice( start, end ), appendItem);
		}		

		//append autorotate options if this options is active
		if (this.options.autorotate) {
			var ar = jQuery('<p class="sfmg-autorotate"/>'),
			    arTrigger = jQuery('<a href="#">Start</a>').click(function(e){
				e.preventDefault();
				if (jQuery(this).hasClass('active')) {
					jQuery(this).removeClass('active').html('Start');
					self.stopAutorotate();
				}
				else {
					jQuery(this).addClass('active').html('Stop');
					self.restartAutorotate();
				}
			});
			ar.append(arTrigger);
			slider.prepend(ar);
		}

		//thumbnails slider
		return slider;		
	};
	
	/**
	 * Creates pagination under the media file
	 */
	sfPhotoGallery.prototype.createPagination = function(){
		var self = this;
		// Pagination
		this.paginationPagesCount	= Math.ceil((this.count-2)/( this.options.numbersPerPaginationPage - 2));
		this.paginationContainerWidth = 0;
		this.currentPaginationPage = 0;
		
		var pagination = jQuery('<div class="sfmg-pagination"><ul class="sfmg-pagination-steps"><li class="sfmg-pagination-steps-prev"/><li class="sfmg-pagination-steps-next"/></ul><div class="sfmg-pagination-pages"></div></div>');
		
		this.$pagination = jQuery('<ul/>');
		pagination.find('.sfmg-pagination-pages').append(this.$pagination);
		
		//on click on one of the items show corresponding media file
		var paginationItemClick = function(e){
			e.preventDefault();
			self.show(e.data.index);
		};
		
		//add pagination numbers for each data item
		jQuery.each(this.dataItems,function(index, item){
			var li = jQuery('<li />');			
			var trigger = jQuery('<a href="#">'+(index+1)+'</a>').bind('click', { "index" : index }, paginationItemClick);
			li.append(trigger);
			pagination.find('.sfmg-pagination-pages ul').append(li);
		});
		
		//previous link in the pagination
		this.$paginationPrev = jQuery('<a href="#">&laquo;</a>').click(function(e){
			e.preventDefault();
			self.show(self.currentItem - 1);
		});
		pagination.find('.sfmg-pagination-steps-prev').append(this.$paginationPrev);
		
		//next link in the pagination
		this.$paginationNext = jQuery('<a href="#">&raquo;</a>').click(function(e){
			e.preventDefault();
			self.show(self.currentItem + 1);
		});
		pagination.find('.sfmg-pagination-steps-next').append(this.$paginationNext);

		return pagination;
	};
	
	/**
	 * Builds a single thumbnail
	 */
	sfPhotoGallery.prototype.createThumbnail = function(item){
		var li = jQuery('<li/>'), trigger, thumb, self = this, thumbURL;

		//check if thumb url is set, if not, try to fetch it from inside the media HTML		
		if (item.thumb) {
			thumbURL = item.thumb;
		}
		else {
			thumbURL = jQuery(item.media).attr('src');
			//if there is no thumb set and we are in goodbarry environment, try to utilize teh automatic image resize function in GB
			if (this.options.goodbarry) {
				thumbURL = '/Utilities/ShowThumbnail.aspx?'+jQuery.param({ 
					"USM" : 1,
					"W" : this.options.thumbWidth,
					"H" : this.options.thumbHeight,
					"R" : 1,
					"Img" : thumbURL
				});
			}
		}	
		
		trigger = jQuery('<a href="#"/>').bind('click', { index : item.index }, function(e){
			e.preventDefault();
			self.show(e.data.index);			
		});
		
		thumb = jQuery('<img src="' + thumbURL + '" alt="' + item.title + '" width="' + this.options.thumbWidth + '" height="' + this.options.thumbHeight + '" />');
		trigger.append(thumb);
		li.append(trigger);
		
		return li;
	};
	
	/**
	 * Show a new item in the main area
	 */
	sfPhotoGallery.prototype.show = function(index){
		//check if it's not out of bounds
		if(index === this.currentItem || index < 0 || index >= this.count) {
			return false;
		}
		
		//check for animation
		if (this.$media.is(':animated') || this.$slider.is(':animated')){
			return false;
		}
		
		this.currentItem = index;
				
		var item = this.dataItems[index];
		
		//run transitions on media, title and description
		this.switchItem(item);
							
		//change states on active pagination and thumbs list items 
		this.$pagination.find('li').removeClass('active').eq(index).addClass('active');
		this.$slider.find('li').removeClass('active').eq(index).addClass('active');
									
		//restart autorotate if it's on
		if (this.options.autorotate && this.$autorotate) {
			this.restartAutorotate();
		}
									
		// slide to proper thumbs page
		this.cycleThumbs( Math.floor(index / this.options.thumbsPerPage) );
		
		// change paging
		this.cyclePaging(index);
	};
	
	/**
	 * Runs transitions on all changing wrappers with media file, title and description
	 */
	sfPhotoGallery.prototype.switchItem = function(i){
		var $ui = (typeof jQuery.fn.effect === 'function'),
		    s = this.options.transitionSpeed,
		    t = this.options.transition,
				media = this.$media,
				title = this.$title,
				desc = this.$description;
		
		switch(t){
		//no transition
		case false:
			media.html(i.media);		
			title.html(i.title);
			desc.html(i.description);		
			break;

		//fade supported by jQuery
		case 'fade':
			media.fadeOut(s,function(){
				media.html(i.media).fadeIn(s);
			});
			title.fadeOut(s,function(){
				title.html(i.title).fadeIn(s);
			});
			desc.fadeOut(s,function(){
				desc.html(i.description).fadeIn(s);
			});
			break;

		//jQuery UI effect	
		default:
			if ($ui === false) {
				throw "Unable to load jQuery UI";
			}

			media.hide(t, s, function(){				
				media.html(i.media).show(t,s);
			});
			
			title.hide(t, s, function(){
				title.html(i.title).show(t, s);				
			});
			
			desc.hide(t, s, function(){				
				desc.html(i.description).show(t, s);				
			});						
			break;
		}
		
	};
	
	/**
	 * Switch visibile thumbs page
	 */
	sfPhotoGallery.prototype.cycleThumbs = function(page){

		if(page !== this.currentThumbPage) { 
			this.$slider.animate({'marginLeft': -1 * page * this.thumbsContainerWidth },300);
			this.currentThumbPage = page;					
		}

		if (page === 0) {
			this.$thumbPrev.hide();
		}
		else {
			this.$thumbPrev.show();
		}

		if (page + 1 < this.thumbPagesCount) {
			this.$thumbNext.show();
		}
		else {
			this.$thumbNext.hide();
		}
 	};
	
	/**
	 * Change current item in the pagination component
	 */
	sfPhotoGallery.prototype.cyclePaging = function(index){
		
		// animate
		var page = Math.floor( (index-1) / (this.options.numbersPerPaginationPage - 2) );
		
		if (page < 0) { 
			page = 0; 
		}
		
		if (page !== this.currentPaginationPage && page < this.paginationPagesCount) {
			this.$pagination.animate({'marginLeft': -1 * page * this.paginationContainerWidth } , 300);
			this.currentPaginationPage = page;
		}
		
		if (index === 0) {
			this.$paginationPrev.hide();
		}
		else {
			this.$paginationPrev.show();
		}
		
		if (index + 1 < this.count) {
			this.$paginationNext.show();
		}
		else {
			this.$paginationNext.hide();
		}
	};
	
	//set this functionality as a plugin
	jQuery.fn.sfPhotoGallery = function(options){
		options = options || {};
		
		return this.each(function(){
			var pf = new sfPhotoGallery(this, options);
			pf.build();
		});
	};	
})();