/**
 * @author <a href="mailto:lamtran@gmail.com">Lam Tran</a>
 */

/**
 * Image Gallery
 * @class Gallery class
 * @broadcasts <strong>page:change</strong> - event when a new page is clicked on<br/>
 * <span class="light">{Number}</span> <strong>Event.data.pageId</strong> page number
 * @broadcasts <strong>thumbnail:change</strong> - event when a new thumbnail is clicked on
 */
Gallery = new function(){
	/** @private flag to make paging operation atomic */
	this.paging=false;
	this.totalImageCount;
	/** @private Instantiates an object that contains the images for the gallery */
	var galleryData = new function(){
		/** array of images that are manipulated by the gallery */
		this.images = [];
		/** maximum number that can be displayed per page */
		this.MAX_THUMBNAILS_PER_PAGE = 7;
		
		/**
		 * Initialize gallery
		 * @param {String} galleryName name of the gallery mapped to images/galleryName/galleryName_xxx.jpg
		 * @param {int} totalImageCount  total number of images to display -- set this number to how
		 * many there are on the server or smaller to show less
		 * @param {Object} meta an object containing meta data for the images (such as alt value and link for the image)
		 * @param {String} meta[imageIndex].alt the alt value for the image
		 * @param {String} meta[imageIndex].link the link that the image points to
		 */
		this.init = function(galleryName, totalImageCount, meta){
			/** @private array to hold items in a page */
			var page = [];
			//reset images data since init assumes that this is empty
			this.images=[];
			meta = null;
			var scope = this;
			$.ajax( {
				type :"GET",
				url :"images/"+galleryName+"/meta.xml",
				dataType :"xml",
				success : function(retXml) {
					root = $(retXml).find('> meta');
					meta = root.find('image');
					for(var i=1;i<=totalImageCount;i++){
						page.push({
							thumbnailSrc:'images/'+galleryName.toLowerCase()+'/thumbnails/'+galleryName.substring(0,1).toUpperCase()+galleryName.substring(1,galleryName.length)+'_'+i+'.gif',
							src:'images/'+galleryName.toLowerCase()+'/'+galleryName.substring(0,1).toUpperCase()+galleryName.substring(1,galleryName.length)+'_'+i+'.jpg',
							alt: (meta[i-1]) ? $(meta[i-1]).attr('alt') : galleryName.substring(0,1).toUpperCase()+galleryName.substring(1,galleryName.length)+'_'+i+'.jpg'//,
//									link: (meta[i-1])? meta[i-1].link : '#'
						});
						//save a page 
						if(i%scope.MAX_THUMBNAILS_PER_PAGE==0){
							scope.images.push(page);
							page=[];
						}
					}
					//push the remaining ones in
					if(page.length>0){
						scope.images.push(page);
					}
					$(document).trigger('meta:loaded');
				},
				error : function(request){
					for(var i=1;i<=totalImageCount;i++){
						page.push({
							thumbnailSrc:'images/'+galleryName.toLowerCase()+'/thumbnails/'+galleryName.substring(0,1).toUpperCase()+galleryName.substring(1,galleryName.length)+'_'+i+'.gif',
							src:'images/'+galleryName.toLowerCase()+'/'+galleryName.substring(0,1).toUpperCase()+galleryName.substring(1,galleryName.length)+'_'+i+'.jpg',
							alt: galleryName.substring(0,1).toUpperCase()+galleryName.substring(1,galleryName.length)+'_'+i+'.jpg'//,
//									link: (meta[i-1])? meta[i-1].link : '#'
						});
						//save a page 
						if(i%scope.MAX_THUMBNAILS_PER_PAGE==0){
							scope.images.push(page);
							page=[];
						}
					}
					//push the remaining ones in
					if(page.length>0){
						scope.images.push(page);
					}
					$(document).trigger('meta:loaded');
				}
			});
			
		};
	};
	/** get images managed by gallery */
	this.getImages = function(){
		return galleryData.images;
	};
	/** get max thumbnails per page */
	this.getMaxThumbnailsPerPage = function(){
		return galleryData.MAX_THUMBNAILS_PER_PAGE;
	};
	/** @private parse page index out of id */
	var getPageId = function(idString){
		return Number(idString.split('_')[1]);
	};
	/** @private get index out of currently selected page */
	var getCurrentPageId = function(){
		return getPageId($('.currentPage').attr('id'));
	};
	var getCurrentThumbnailId = function(){
		return Number($($('.currentThumbnail')[0]).find('a')[0].id.split('_')[1]);
	};
	var isSamePage = function(index){
		return getCurrentPageId() == index;
	};
	var setCurrentPage = function(pageId){
		$('.currentPage').toggleClass('currentPage');
		$('#page_'+pageId).addClass('currentPage');
	};
	this.clickPage = function(pageId){
		if(!this.paging){
			if(isSamePage(pageId)){
				//same as page that has currently selected thumbnail
				//do nothing
			}else{
				this.paging=true;
				var oldPageId = getCurrentPageId();
				setCurrentPage(pageId);
				$(document).trigger('page:change',oldPageId);
			}
		}
	};
	/**  
	 * @private make pagination bar to traverse sets of images
	 * @param paginationParent html element containing the pagination
	 */
	var makePagination = function(paginationParent){
		var pagination = $('#'+paginationParent);
		//draw the HTML elements
		$.each(galleryData.images,function(index,value){
			$('<li>').appendTo(pagination).append('<a title="Page '+(index+1)+'" id=page_'+index+' href="#">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</a>');
		});
		//label the first page as current page
		pagination.find('li:first a').addClass('currentPage');
		//handler when a page is clicked
		pagination.find('li a').click(function(){
			Gallery.clickPage(getPageId(this.id));
			return false;
		});
		
	};
	var onMouseOutThumb = function(obj){
		if($(obj).parent().attr('class')!='currentThumbnail'){
			var span = $(obj).find('img').next();
			setTimeout(function(){
				span.stop().fadeTo(500, 0);
			},300);
		}
	};
	var onMouseOverThumb = function(obj){
		var scope = obj;
		var imgSrc = $(obj).find('img').attr('src');
		//load image
		var link = scope;
		var span = $(link).find('img').next();
		//set positioning first time around to move span over the image
		if(span.css('background-image')=='none'){
			span.css('opacity', 0);
			span.css('background-image','url('+imgSrc.replace('gif','jpg')+')');
			if ($.browser.msie){
				if($.browser.version >= 7){
					span.css('top','-109px');
				}
			}else{
				span.css('top','-114px');
			}
		}
		span.stop().fadeTo(200, 1);
	};
	
	/** @private local helper function to parse thumbnail id out of image path */
	var parseThumbnailId = function(thumbnailSrc){
		var parts = thumbnailSrc.split('_');
		var idPart = parts[parts.length-1];
		return idPart.substring(0,idPart.length-4);//thumbnailSrc.substring(0,thumbnailSrc.length-4);
	};
	/** @private local helper to figure out if the thumbnail is currently visible */
	var isThumbnailInView = function(thumbnailId,oldPageId){
		return (thumbnailId >= (oldPageId*Gallery.getMaxThumbnailsPerPage()+1) && thumbnailId <= (oldPageId*Gallery.getMaxThumbnailsPerPage()+Gallery.getMaxThumbnailsPerPage()));
	};
	var getThumbnailParent = function(thumbnailWrapperId){
		var query = $('#'+thumbnailWrapperId+' ul');
		return query.length > 0 ? query.get(0) : $('<ul>').appendTo($('#'+thumbnailWrapperId));
	};
	this.clickThumbnail = function(id){
		//show the big image
		var mainImage = $('#mainImage');
		
		if(Number(id)>this.totalImageCount){
			return false;
		}
		if(isThumbnailInView(id,getCurrentPageId())){
			//remove highlight on previously selected thumbnail
			var curr = $('.currentThumbnail');
			curr.toggleClass('currentThumbnail');
			onMouseOutThumb(curr);
			//highlight current thumbnail
			hoverThumbnail(id);
			if(Number(mainImage.attr('src').split('_')[1].split('.')[0])==id){
			}else{
				var data = galleryData.images[getCurrentPageId()][(id%Gallery.getMaxThumbnailsPerPage()!=0)?id%Gallery.getMaxThumbnailsPerPage()-1:6];
				mainImage.fadeOut('fast',function(){
					Util.loadImage(data.src,function(){
						setTimeout(function(){
							mainImage.fadeIn('fast',function(){
							});
						},10);
						return mainImage;
					})
				});
				mainImage.attr('alt',data.alt);
//				console.log(data.alt);
				var linkHref = $('#imageLink').attr('href');
				$('#imageLink').attr('title',data.alt);
				var indexStr = linkHref.substring(linkHref.indexOf('index='),linkHref.length);
				var index = indexStr.split('&')[0].split('=')[1];
				var newLink = linkHref.replace('index='+index,'index='+(id+1));
				$('#imageLink').attr('href',newLink);
			}
		}else{
			this.clickPage((id%7!=0)?Math.floor(id/Gallery.getMaxThumbnailsPerPage()):Math.floor(id/Gallery.getMaxThumbnailsPerPage())-1);
			$(document).one('page:change:done',function(){
				Gallery.clickThumbnail(id);
			});
		}
		$(document).trigger('thumbnail:change',id);
		return false;
	}
	var makeThumbnail = function(index,item){
		var id = 'thumb_'+(getCurrentPageId()*Gallery.getMaxThumbnailsPerPage()+index+1);
		var ret =  $('<li>').append('<a href="#" id="'+id+'"></a>')
		//drill down to the link element
		.find('a').hover(function(){
			onMouseOverThumb(this);
		},function(){
			onMouseOutThumb(this);
		})
		.click(function(){
			Gallery.clickThumbnail(getCurrentPageId()*Gallery.getMaxThumbnailsPerPage()+index+1);
			return false;
		})
		//attach image to the link
		.append('<img src="'+Util.loadImage(item.thumbnailSrc,function(){
			return $('#'+ id + ' img');
		})+'" /><span class="imageReplace"></span>').append('<a href="'+item.link+'" class="imageCaption">'+item.alt+'</a>')
		//attach to DOM tree
		.end();	
		return ret;
	};
	var getInsertionPoint = function(thumbnailParent){
		var point = getCurrentPageId()*Gallery.getMaxThumbnailsPerPage();
		while($('#thumb_'+point).length==0){
			point--;
			if(point==0){
				break;
			}
		}
		return $('#thumb_'+point).parent();
	};
	var hoverThumbnail = function(thumbnailId){
		$($('#thumb_'+thumbnailId).parent()).addClass('currentThumbnail');
		onMouseOverThumb($('#thumb_'+thumbnailId).get(0));
	};
	var scrollView = function(element,from,to){
		var diff = Math.abs(from)-to;
		if(diff<0){
			Util.startLoading();
			$(element).animate({left: ('-='+Math.abs(diff)+'px')}, "slow",function(){
				Util.finishLoading();
				Gallery.paging=false;
				$(document).trigger('page:change:done');
			});
		}else{
			Util.startLoading();
			$(element).animate({left: ('+='+diff+'px')}, "slow",function(){
				Util.finishLoading();
				Gallery.paging=false;
				$(document).trigger('page:change:done');
			});
		}
	};
	/**
	 * @private make thumbnails
	 * @param thumbnailParent html element containing the thumbnails
	 */
	var makeThumbnails = function(thumbnailWrapperId,oldPageId){
		var data = galleryData.images[getCurrentPageId()];
		//check to see if we had already drawn the thumbnails
		var firstThumbnailId = parseThumbnailId(data[0].thumbnailSrc);
		if($('#thumb_'+firstThumbnailId).length>0){
			//already drawn the thumbnails
			if(!isThumbnailInView(firstThumbnailId,oldPageId)){
				//thumbnails not in view, scroll to them
				var targetOffset = $('#thumb_'+firstThumbnailId).position().left;
				var thumbnailParent = $($('#'+thumbnailWrapperId).find('ul'));
				var currentViewOffset = thumbnailParent.position().left;
				scrollView(thumbnailParent,currentViewOffset,targetOffset);
			}else{
				// in view
			}
		}else{
			//draw the thumbnails
			var thumbnailWrapper = $('#'+thumbnailWrapperId);
			var thumbnailParent = getThumbnailParent(thumbnailWrapperId);
			$(thumbnailParent).width((118*Gallery.getMaxThumbnailsPerPage()*galleryData.images.length)+'px');
			//parent has nothing so attach to it
			if($(thumbnailParent).children().length==0){
				$.each(data,function(index,item){
					//append an li to parent
					makeThumbnail(index,item).appendTo(thumbnailParent);
				});
				setTimeout(function(){
					//hoverThumbnail(1);
				},1000);
			}else{//there are other thumbnails, insert in appropriate spot
				var target = getInsertionPoint(thumbnailParent);
				var targetOffset = target.position().left+/*offset*/5+/*thumb width*/+108;
				var currentViewOffset = $(thumbnailParent).position().left;
				$.each(data,function(index,item){
					//append an li to parent
					var thumbnail = makeThumbnail(index,item);
					thumbnail.css('width', 0);
					thumbnail.insertAfter(target);
					thumbnail.animate({width:'+=108px'},"slow");
					target=thumbnail;
				});
				scrollView(thumbnailParent,currentViewOffset,targetOffset);
			}
		}
		return false;
	};
	var makeLeftRightControls = function(leftId,rightId){
		$('#'+leftId).click(function(){
			var currentId = getCurrentThumbnailId();
			Gallery.clickThumbnail(currentId-1);
			return false;
		});
		$('#'+rightId).click(function(){
			var currentId = getCurrentThumbnailId();
			Gallery.clickThumbnail(currentId+1);
			return false;
		});
		$('#'+rightId).fadeIn('slow');
		$(document).bind('thumbnail:change',function(event,currentId){
			if((currentId-1)<=0){
				$('#'+leftId).fadeOut('slow');
			}else{
				$('#'+leftId).fadeIn('slow');
				if((currentId+1)>Gallery.totalImageCount){
					$('#'+rightId).fadeOut('slow');
				}else{
					$('#'+rightId).fadeIn('slow');
				}
			}
		});
	};
	/**
	 * Method to create a gallery
	 * Initialize gallery
	 * @param {Object} config Information about the gallery
	 * @param {String} config.galleryName name of the gallery mapped to images/galleryName/galleryName_xxx.jpg
	 * @param {int} config.totalImageCount  total number of images to display -- set this number to how
	 * many there are on the server or smaller to show less
	 * @param {String} config.imageParentId container that displays the main gallery image
	 * @param {String} config.paginationParentId container that displays the pagination
	 * @param {String} config.thumbnailParentId container that displays the thumbnails
	 * @param {Object} config.meta an object containing meta data for the images (such as alt value and link for the image)
	 * @param {String} config.meta[imageIndex].alt the alt value for the image
	 * @param {String} config.meta[imageIndex].link the link that the image points to
	 * @return
	 */
	this.initGallery = function(config){
		Util.require(config,['galleryName','totalImageCount','imageParentId','paginationParentId','thumbnailParentId']);
		
		this.totalImageCount=config.totalImageCount;
		//initialize the images
		galleryData.init(config.galleryName,config.totalImageCount,config.meta || []);
		
		$(document).bind('meta:loaded',function(){
			//build the pagination
			makePagination(config.paginationParentId);
			//build the thumbnails
			makeThumbnails(config.thumbnailParentId);
			$(document).bind('page:change',function(event,data){
				makeThumbnails(config.thumbnailParentId,data);
			});
			/*
		$(document).bind('page:change:done',function(event,data){
		    console.log('done too');
		    Gallery.clickThumbnail(2);			    
		});*/
			makeLeftRightControls('goLeft','goRight');
			$('#imageLink').hover(function(){
				
			},function(){
				
			});
		});
	};
};







/*
function makeGallery(galleryName, count){
	
	//makeGalleryWithPreparedData(images);
}
function makeGalleryWithPreparedData(images){
	//makePagination(images);
	makeThumbnails(document.getElementById('thumbnailsWrapper'),0);
	//makeLeftRightControls();
}


function makeThumbnails(wrapper,index){
	var parent = $(wrapper);
	var thumbList = $('ul id="thumbnails_'+index+'"></ul>');
	var currentClass;
	var data = images[index];
	$.each(data,function(index,item){
	});
}
*/

