// -----------------------------------------------------------------------------------
// 
// REQUIRES: Mootools v1.2
// MODULES: Core, Class, Native, Element, Window, Effects, Remote
//
// -----------------------------------------------------------------------------------
// --- version date: 2009.04.05 ------------------------------------------------------


/* Moopix Class
------------------------------------------------------------

PURPOSE: Injects a slideshow into an existing HTML page

USAGE:
	new Moopix({
		title: 'My Photo Gallery',
		width: '900'
	});
*/

var Moopix = new Class({
	
	Implements: [Chain, Events, Options],
	
	// default options, which can be overridden when instance is created
	options: {
		autoplay: 		false,									// Should we start the slideshow on load?
		thumbnails: 	false, 									// Should we show thumbnails?
		title: 			false,									// Should we include the title of the gallery?
		collection: 	null, 									// JSON object containing the list of galleries
		gallery: 		null,									// JSON object containing the array of photos
		gal: 			0, 										// Index of active gallery
		timer: 			5000,									// How long should each photo be shown?
		duration: 		750,									// Duration of transition
		width: 			'100%',									// Width of container
		template: 		'resources/templates/_portfolio.html',	// Include layout for images and thumbnails
		target: 		'moopix'								// DOM element where we should put the slideshow	
	},
    
	initialize: function(options){
				
		// load in the options above
		this.setOptions(options);
				
		// check to see if there's an anchor in the URL
		this.url = document.location.href;
		this.urlHash = this.url.split("#");
		this.bookmark = this.urlHash[1] - 1;
		
		// for later use inside this object
		this.template			= this.options.template;
		this.gal				= this.options.gal;
		this.galListing			= this.options.collection.galleries;
		this.imgArray			= this.options.gallery.photos;
		this.imgFolder			= this.options.gallery.folder;
		this.imgPaths 			= [];
		this.imgLoaded			= [];
		this.thumbPaths 		= [];
		this.thumbLoaded		= [];
		this.photoId 			= (!this.bookmark)? 0 : this.bookmark;
		this.pid				= this.photoId;
		this.playingInt			= null;
		this.stageSize			= 0;
		
		// for thumbnail views
		this.pageId				= 0;
		this.pgid				= 0;
		this.thumbSize			= 0;
		this.thumbListHeight 	= 0;
		this.thumbsPerPage		= 0;
		this.thumbScrollHeight	= 0;
		
		// now build wrapper and slideshow stage
		this.buildWrapper();
		this.buildStage();		
	},
	
	
	/* CONSTRUCT INTERFACE
	-------------------------------------------*/
	
	buildWrapper: function(){
		// build window wrapper and set its z-index and x/y position
		this.galWrapper = new Element('div').addClass('wrapper').set('styles', {
			'width': this.options.width
		}).injectInside(this.options.target);
	},
	
	buildStage: function(){
		// grab HTML fragment from server, inject inside the wrapper
		new Request.HTML({
			url: this.template,
			method: 'get',
			update: this.galWrapper,
			onComplete: function(){
				// generate images and slideshow controls
				(this.options.thumbnails == true) ? this.buildThumbs() : this.buildImages();
				
				// create play & pause controls
				this.buildControls();
				
				// conditionally build title
				if(this.options.title == true) this.buildTitle();
			}.bind(this)
		}).send();
	},
	
	buildControls: function(){
		// attach play/pause functionality to link
		var pause = this.galWrapper.getElement('li.pause a').addEvent('click', function(){
			this.toggleAutoPlay();
		}.bind(this));
		
		// attach play/pause functionality to link
		var next = this.galWrapper.getElement('li.next a').addEvent('click', function(){
			this.stopAutoPlay();
			this.nextPhoto();
		}.bind(this));
		
		// attach play/pause functionality to link
		var prev = this.galWrapper.getElement('li.prev a').addEvent('click', function(){
			this.stopAutoPlay();
			this.prevPhoto();
		}.bind(this));
		
		// manage hiding, showing the controller
		var controls = $$('.controls');
		controls.each(function(el){ el.setStyle('opacity', '0.0'); });
		$('moopix-stage').addEvents({
			mouseenter: function(){ controls.morph({ opacity: 1.0 }); },
			mouseleave: function(){ controls.morph({ opacity: 0.0 }); }
		});
		
		// set scrim to block right-click download of images
		var scrimSize = $('moopix-stage').getSize();
		$('moopix-scrim').set('styles', { 'height': scrimSize.y, 'width': scrimSize.x });
	},
	
	buildTitle: function(){
		// set the title of the gallery
		$('title').set('text', this.galListing[this.gal].title);
	},
	
	buildImages: function(){
		// construct the path to each image so they can be loaded up
		this.imgArray.each(function(img, i) { this.imgPaths.push(this.imgFolder + "/" + img.big); }.bind(this));
		this.preloadImages();
	},
	
	buildThumbs: function(){
		// construct paths to each thumbnail so they can be loaded up
		this.imgArray.each(function(img, i) { this.thumbPaths.push(this.imgFolder + "/" + img.thumb); }.bind(this));
		this.preloadThumbs();
	},
	
	buildThumbWrapper: function(){
		// set wrapper height to match the stage height
		var linkSize = $$('#moopix-thumbs a.prev').getSize();
		this.stageSize = $('moopix-stage').getSize();
		this.thumbListHeight = this.stageSize.y - (2 * linkSize[0].y);

		// set list to correct height
		$('moopix-thumbs-inner').set('styles', { 'height': this.thumbListHeight });
		$('moopix-thumbs').set('styles', { 'height': this.stageSize.y });
		
		// create the controls to change pages
		this.buildThumbControls();
	},
	
	buildThumbControls: function(){
		// set the inner wrapper height to match the stage minus the pagination links
		var thumbSize = $$('#moopix-thumbs-list li').getSize();
		
		// set thumb size and list height for later use
		this.thumbSize = thumbSize[0];
		
		// set container width to size of thumbnail
		$('moopix-thumbs-inner').set('styles', { 'width': this.thumbSize.x });
		
		// how many full thumbnails can you see at one time?
		this.thumbsPerPage = Math.floor(this.thumbListHeight / this.thumbSize.y);
		this.thumbScrollHeight = (this.thumbsPerPage * this.thumbSize.y);
				
		// jump to next full page of thumbnails
		$$('#moopix-thumbs a.next').addEvent('click', function(){
			this.nextPage();
		}.bind(this));
		
		// jump to previous full page of thumbnails
		$$('#moopix-thumbs a.prev').addEvent('click', function(){
			this.prevPage();
		}.bind(this));
		
		// scroll to the correct page based on the photoId
		this.setActivePage();
	},	
	
	blurLinks: function(){
		$$('a').addEvent('focus', function(){ this.blur(); });
	},
	
	/* LOAD IMAGES
	-------------------------------------------*/
	
	preloadThumbs: function(){		
		// preload each image and when that's done start the slideshow
		var img = new Asset.images(this.thumbPaths, {
			onProgress: function(i) {
				this.thumbLoaded.push(img[i]);
			}.bind(this),

			onComplete: function(){
				// inject the photos into the gallery container
				this.thumbLoaded.each(function(el, i) {												
					var link = this.buildThumbLink(i);
					el.inject(link);
				}.bind(this));
				
				// build a proper home for these thumbnails
				this.buildThumbWrapper();
				
				// having loaded thumbnails, preload the big images
				this.setActiveThumb(this.photoId);
				this.buildImages();
			}.bind(this)
		});
	},
	
	preloadImages: function(){		
		// preload each image and when that's done start the slideshow
		var img = new Asset.images(this.imgPaths, {
			onProgress: function(i) {
				this.imgLoaded.push(img[i]);
				this.setImgPosition(img[i],i);
				this.showProgress(i);
			}.bind(this),

			onComplete: function(){
				// hide the progress indicator
				$('moopix-progress').set('styles', { 'visibility': 'hidden' });
				
				// inject the photos into the gallery container
				this.imgLoaded.each(function(el, i) { el.inject('moopix-stage'); }.bind(this));
				
				// start the slideshow
				this.startSlideshow();
			}.bind(this)
		});
	},
	
	showProgress: function(i){
		// increment progress indicator by a percentage of the total
		var percent = ((i + 1) * $('moopix-progress').getStyle('width').toInt()) / this.imgPaths.length;
		$$('#moopix-progress .bar').set('styles', { 'width': percent });
	},
	
	buildThumbLink: function(i){
		var li = new Element('li').injectInside('moopix-thumbs-list');
		
		// construct image link for thumbnail and attach click event
		var link = new Element('a', {
			'href': 'javascript://',
			'events': {
				click: function(){
					this.stopAutoPlay();
					this.jumpToPhoto(i);
				}.bind(this)
			}
		}).injectInside(li);
		return(link);
	},
	
	setActiveThumb: function(i){		
		// toggle highlight onto the active thumbnail
		$$('#moopix-thumbs-list a').each(function(el, id){			
			el.removeClass('selected');
			if(id == this.photoId) { el.addClass('selected'); };
		}.bind(this));
	},
	
	setImgPosition: function(img,i){		
		// position images as they preload in the middle of the gallery
		img.set('styles', {
			'position': 'absolute',
			'opacity': 0,
			//'left': ($('moopix-stage').getCoordinates().width / 2) - (this.imgArray[i].width / 2),
			//'top': ($('moopix-stage').getCoordinates().height / 2) - (this.imgArray[i].height / 2)
			'left': ($('moopix-stage').getSize().x / 2) - (this.imgArray[i].width / 2),
			'top': ($('moopix-stage').getSize().y / 2) - (this.imgArray[i].height / 2)
		});
	},
	
	
	/* HANDLE PHOTOS
	-------------------------------------------*/
	
	startSlideshow: function(){
		// kick off slideshow by showing the first photo and then cycling through others		
		var fadeIn = new Fx.Tween(this.imgLoaded[this.photoId]).start('opacity', '1.0');		
		if(this.options.autoplay == true) this.startAutoPlay();
		
		// blur all links on the page when they're in focus to avoid the dotted outlines
		this.blurLinks();
	},
	
	getNext: function(){		
		// return next photo id
		(this.pid == (this.imgLoaded.length - 1)) ? this.pid = 0 : this.pid++;
		return this.pid;
	},
	
	getPrev: function(){		
		// return prev photo id
		(this.pid == 0) ? this.pid = this.imgLoaded.length - 1 : this.pid--;
		return this.pid;
	},
	
	nextPhoto: function(){
		// advance to next photo
		this.jumpToPhoto(this.getNext());
	},
	
	prevPhoto: function(){
		// advance to next photo
		this.jumpToPhoto(this.getPrev());
	},
	
	jumpToPhoto: function(pid){
		if(this.photoId == pid){
			return false;
		} else {
			// jump to a particular photo
			var fadeOut = new Fx.Tween(this.imgLoaded[this.photoId], {duration: this.options.duration}).start('opacity', '0.0');		
			var fadeIn = new Fx.Tween(this.imgLoaded[pid], {duration: this.options.duration}).start('opacity', '1.0');
			
			// set current photo id to the one passed into this method
			this.photoId = pid;
			this.pid = pid;
			
			// highlight the correct thumbnail if thumbnails exist
			if(this.options.thumbnails == true) {
				this.setActiveThumb(this.photoId);
				this.setActivePage();
			} 
			
			// set URL bar to correct anchor for bookmarking
			document.location.href = "#" + (this.photoId+1);
		}
	},
	
	
	/* HANDLE THUMBNAILS
	-------------------------------------------*/
	
	getNextPage: function(){		
		// return next page index
		if(this.pgid < ((this.thumbLoaded.length / this.thumbsPerPage) - 1)) this.pgid++;
		return this.pgid;
	},
	
	getPrevPage: function(){		
		// return prev page index
		if(this.pgid > 0) this.pgid--;
		return this.pgid;
	},
	
	nextPage: function(){
		// advance to next photo
		this.scrollToPage(this.getNextPage());
	},
	
	prevPage: function(){
		// advance to next photo
		this.scrollToPage(this.getPrevPage());
	},
	
	scrollToPage: function(pgid){
		// scroll thumbnails to specific page
		new Fx.Tween('moopix-thumbs-list', {transition: Fx.Transitions.Quart.easeInOut}).start('top', (-(pgid * this.thumbScrollHeight)));
		
		// set current page index to the one passed into this method
		this.pageId = pgid;
		this.pgid = pgid;
	},
	
	setActivePage: function(){
		// automatically scroll thumbnails so that current image is in view
		this.scrollToPage((Math.ceil((this.photoId+1) / this.thumbsPerPage)) - 1);
	},
	
	
	/* HANDLE PLAYING/PAUSING
	-------------------------------------------*/
	
	startAutoPlay: function(){
		// every timer interval, jump to the next photo
		this.playingInt = (function(){ this.nextPhoto(); }.bind(this)).periodical(this.options.timer);
		
		// make sure the play button is set to pause mode
		this.galWrapper.getElements('li.pause').addClass('playing');
		this.galWrapper.getElements('li.pause a').set('text', 'Pause');
	},
	
	stopAutoPlay: function(){
		// stop playing slideshow
		$clear(this.playingInt);
		this.playingInt = null;
		
		// make sure the play button is set to pause mode
		this.galWrapper.getElements('li.pause').removeClass('playing');
		this.galWrapper.getElements('li.pause a').set('text', 'Play');
	},
	
	toggleAutoPlay: function(){
		// toggle slideshow mode on/off
		if(this.playingInt){
			this.stopAutoPlay();
		} else {
			this.nextPhoto();
			this.startAutoPlay();
		}
	}
});