/*
Version: 1.1.1
Copyright 2008, 2009 Marcello Mascia

This file is part of Kishlery.

Kishlery is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

Kishlery is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with Kishlery. If not, see <http://www.gnu.org/licenses/>
*/

var Kishlery = new Class({

	Implements: Options,

	// Cose varie
	nodes: null,
	owner_id: null,
	ownername: null,
	showOwner: null,
	mainContainer: null,
	previous: 0,
	current: 0,
	controllers: null,
	thumbsContainer: null,
	thumbsContainer2: null,
	myPictures: new Array(),
	isPicLoaded: new Array(),
	myThumbs: new Array(),
	isThumbLoaded: new Array(),
	myThumbs2: new Array(),
	stopLoading: null,
	scroll: null,
	scrollThumbs: null,
	title: null,
	footer: null,

	// Opzioni e inizializzazione ------------------------------------------------------------------ 
	options: {
		root: '.',
		mode: 'photoset',
		limit: '',
		tags: '',
		id: null,
		buffer: 5,
		showOwner: true,
		viewTitle: true,
		maxSize: 0,
		forceHeight: false,
		linkToFlickr: true,
		activateKeyboard: true,
		showThumbs2: true,
		singleMode: false,
		interval: 4000
	},

	initialize: function(element, options){
		this.element = $(element);
		if(!this.element){
			alert("I was looking for\n\n<div id=\"" + element + "\"></div>\n\nbut I can't find it.\nPlease check your html.");
			return false;		
		}
		
		this.setOptions(options);

		if(this.options.id == ''){
			alert('Photoset id required');
			return false;
		}

		// Normalizzo la dimensione
		if(this.options.maxSize)
			this.options.maxSize = this.options.maxSize.toInt();

		// Carico i css	
		new Asset.css(this.options.root + '/inc/kishlery.css');

		// Chiamo il file xml
		var kishlery = this;
		var params = 'id=' + this.options.id + '&per_page=' + this.options.limit + '&mode=' + this.options.mode + '&tags=' + this.options.tags;
		var url = this.options.root + '/inc/kishlery.php';

		new Request({
			url: url,
			onSuccess: function(txt, xml){
				if(xml)
					kishlery.nextStep(xml, kishlery.options.mode);
				else
					alert("Warning.\n\n" + txt);
			},
			onFailure: function(){
				if(this.status == 404)
					alert(url + ' not found');
			}
		}).send(params);

		// Associo comportamenti alla finestra
		if(this.options.singleMode){
			window.addEvent('resize', function(){
				this.adaptToContainer();
				this.moveTo(this.current);
			}.bind(this));
		}
	},
	
	nextStep: function(xml){
		var obj = this;

		// Recupero i nodi photo
		this.nodes = xml.documentElement.getElementsByTagName('photo');
		if(this.nodes.length == 0){
			var error = xml.documentElement.getAttribute('error')?xml.documentElement.getAttribute('error'):null;
			if(!error){
				var error = xml.documentElement.getElementsByTagName('err');
				if(error[0])
					error = error[0].getAttribute('msg');
				else
					error = 'Unknown error. Try again.';
			}
				
			alert(error);
			return false;
		}
		if(this.nodes.length <= this.options.buffer) this.options.buffer = this.nodes.length;

		// Determino il tipo di visualizzazione
		switch(this.options.mode){
			case 'photoset':
				var photoset = xml.documentElement.getElementsByTagName('photoset');
				if(!photoset){
					alert('Photoset id required. Xml error.');
					return false;
				}
				this.owner_id = photoset[0].getAttribute('owner');
				this.ownername = photoset[0].getAttribute('ownername');
				break;
			case 'user':
				this.owner_id = this.nodes[0].getAttribute('owner');
				this.showOwner = false;
				break;
			case 'group':
				break;
			case 'folder':
				this.options.linkToFlickr = false;
				break;
		}

		// Creo l'html
		this.doHTML();
		
		// Controlli da tastiera
		if(this.options.activateKeyboard)
			this.keyboardControls();

		// Scrolling delle immagini principali
		this.scroll = new Fx.Scroll(this.element, {
			wait: false,
			duration: 800,
			transition: Fx.Transitions.Quint.easeInOut
		});

		// Scrolling automatico (play)
		if(this.options.singleMode){
			this.play = new Slideshow2(this.element);
		}
		else{
			this.play = new Slideshow(this.element, {
				wait: true,
				transition: Fx.Transitions.linear,
				onStart: function(){
					obj.controllers.getElement('.KLplay').setProperty('src', obj.options.root + '/img/pause.gif');
				},
				onComplete: function(){
					obj.controllers.getElement('.KLplay').setProperty('src', obj.options.root + '/img/play.gif');
					setTimeout("myKishlery.replay();",2000);
				},
				onCancel: function(){ 
					obj.controllers.getElement('.KLplay').setProperty('src', obj.options.root + '/img/play.gif');
				}
			});
		}

		// Carico le immagini
		this.load(0);
	},
	
	replay:function(){
		var obj = this;
		obj.moveTo(0);
		setTimeout("myKishlery.play.go(myKishlery);",7000);
	},
	

	doHTML: function(){

		// Loading bar
		var span = new Element('span').addClass('KLpre_counter').inject(this.element);
		span.innerHTML = '<span>Loading...</span>';

		// Container delle immagini
		{
			this.mainContainer = this.element;
			this.element = new Element('div').addClass('KLpics_container');
			if(this.options.singleMode){
				var obj = this;
				obj.element.set('morph', {onComplete: function(){
					obj.myPictures[obj.current].tween('opacity', 1);
				}});

				this.mainContainer.addClass('KLsingle_mode');
			}
			if(this.options.maxSize) this.element.setStyle('height', this.options.maxSize + 'px');
			this.element.inject(this.mainContainer);
		}

		// Container del titolo
		{
			this.title = new Element('div').addClass('KLtitle').inject(this.mainContainer);
		}

		// Controllers
		{
			this.controllers = new Element('div').addClass('KLcontrollers').inject(this.mainContainer);
	
			var buttons = new Element('div').addClass('KLbuttons').inject(this.controllers);
	
			// Bottone back
			new Element('img', {'src': this.options.root + '/img/previous.gif', 'alt': 'Previous', 'title': 'Previous image'})
				.addClass('KLback')
				.addClass('button')
				.inject(buttons)
				.addEvent('click', function(){
					this.moveTo(this.current - 1);
				}.bind(this));

			// Bottone play
			new Element('img', {'src': this.options.root + '/img/play.gif', 'alt': 'Play', 'title': 'Start slideshow'})
				.addClass('KLplay')
				.addClass('button')
				.inject(buttons)
				.addEvent('click', function(){
					this.play.go(this);
				}.bind(this));
			
			// Bottone forward
			new Element('img', {'src': this.options.root + '/img/next.gif', 'alt': 'Next', 'title': 'Next image'})
				.addClass('KLnext')
				.addClass('button')
				.inject(buttons)
				.addEvent('click', function(){
					this.moveTo(this.current + 1);
				}.bind(this));
				
			// Counter delle immagini
			var div = new Element('div')
				.addClass('KLcounter')
				.inject(buttons)
				.addEvent('click', function(){
					this.toggleLoading();
				}.bind(this));
			div.innerHTML = '0/' + this.nodes.length;
	
		}

		// Thumbnails
		{
			// Mappa delle thumbs
			if(this.options.showThumbs2){
				this.thumbsContainer2 = new Element('div').addClass('KLthumbsContainer2').inject(this.mainContainer);
				new Element('div').inject(this.thumbsContainer2);
				this.thumbsContainer2.set('tween', {onComplete: function(){
					if(this.element.getStyle('opacity') == 0)
						this.element.setStyle('display', 'none');
				}});
			}

			// Creo il contenitore delle thumb e la relativa animazione
			this.thumbsContainer = new Element('div').addClass('KLthumbsContainer');
			this.scrollThumbs = new Fx.Scroll(
				this.thumbsContainer,
				{
					wait: false,
					duration: 1000,
					transition: Fx.Transitions.Quint.easeInOut
				}
			);

			// Bottone per scorrere indietro
			var a = new Element('a', {'href': './'})
				.addClass('KLthumbs_back')
				.inject(this.controllers)
				.addEvent('click', function(){
					new Fx.Scroll(this.thumbsContainer).start(this.thumbsContainer.scrollLeft - 1 * this.thumbsContainer.getWidth());
					return false;
				}.bind(this));
			a.innerHTML = '&nbsp;';

			// Appendo il contenitore delle thumb
			this.thumbsContainer.inject(this.controllers);
			
			// Bottone per scorrere avanti
			var a = new Element('a', {'href': './'})
				.addClass('KLthumbs_forward')
				.inject(this.controllers)
				.addEvent('click', function(){
					new Fx.Scroll(this.thumbsContainer).start(this.thumbsContainer.scrollLeft + 1 * this.thumbsContainer.getWidth());
					return false;
				}.bind(this));
			a.innerHTML = '&nbsp;';
		}

		// Footer
		{
			this.footer = new Element('div').addClass('KLfooter').set('html', '').inject(this.controllers);
		}
	},

	keyboardControls: function(){
		window.addEvent('keydown', function(event){
			var event = new Event(event);
			switch(event.key){
				case 'right':
					this.moveTo(this.current + 1);
					break;
				case 'left':
					this.moveTo(this.current - 1);
					break;
				case 'space':
					this.play.go(this);
					event.preventDefault();
					break;
				case 'esc':
					this.toggleLoading();
					break;
			}
		}.bind(this));
	},


	// Caricamento immagini e thumb relative -------------------------------------------------------
	load: function(i){
		// Fine del caricamento
		if(i >= this.nodes.length || this.stopLoading){
			return false;
		}
		// Mostro l'indicatore di caricamento durante il buffering
		if(i < this.options.buffer){
			var width = 200 * (i + 1) / this.options.buffer;
			if(this.mainContainer.getElement('.KLpre_counter'))
				this.mainContainer.getElement('.KLpre_counter span').setStyle('width', width + 'px');
		}
		
		// Mostro le prime foto caricate
		if(i + 1 == this.options.buffer) this.openCurtains();
		
		// Precarico thumb e immagine
		if(this.options.mode == 'folder')
			var urls = this.getPicUrlFromFolder(this.nodes[i]);
		else
			var urls = this.getPicUrl(this.nodes[i]);

		this.loadPic(urls, i);
	},

	getPicUrl: function(node){
		var id = node.getAttribute('id');
		var server = node.getAttribute('server');
		var secret = node.getAttribute('secret');
		var farm = node.getAttribute('farm');
		if(node.getAttribute('owner')){
			this.owner_id = node.getAttribute('owner');
			this.ownername = node.getAttribute('ownername');
		}
		
		return new Array(
			'http://farm' + farm + '.static.flickr.com/' + server + '/' + id + '_' + secret + '.jpg', // Image
			'http://farm' + farm + '.static.flickr.com/' + server + '/' + id + '_' + secret + '_s.jpg', // Thumb
			'http://www.flickr.com/photos/' + this.owner_id + '/' + id + '/', // Link all'immagine
			this.ownername, // Owner name
			'http://www.flickr.com/photos/' + this.owner_id + '/' // Link all'autore
		);
	},
	
	getPicUrlFromFolder: function(node){
		return new Array(
			node.getAttribute('url'), // Image
			node.getAttribute('url'), // Thumb
			null, // Link all'immagine
			node.getAttribute('copyright'), // Owner name
			null // Link all'autore
		);
	},

	loadPic: function(urls, i){
		var obj = this;

		obj.myPictures[i] = new Asset.image(urls[0], {
			alt: obj.nodes[i].getAttribute('title'),
			onload: function(){
				if(obj.isPicLoaded[i]) return false;

				// Ridimensionamento dell'immagine
				if(obj.options.maxSize){
					if(obj.options.forceHeight){
						// L'altezza viene forzata al valore specificato
						var max = this.height > obj.options.maxSize?obj.options.maxSize:this.height;
						var w = (this.width * max / this.height).round();
						var h = max;					
					}
					else{
						// Il lato più lungo prende il valore specificato se non eccede le dimensioni originali
						if(this.width > this.height){
							var max = this.width > obj.options.maxSize?obj.options.maxSize:this.width;
							var w = max;
							var h = (this.height * max / this.width).round();
						}
						else{
							var max = this.height > obj.options.maxSize?obj.options.maxSize:this.height;
							var w = (this.width * max / this.height).round();
							var h = max;
						}
					}
					
					this.setStyles({'width': w, 'height': h});
				}

				if(obj.options.singleMode)
					this.setStyle('opacity', 0);

				// Scroll verso questa immagine
				this.addEvent('click', function(){obj.moveTo(i);});

				obj.isPicLoaded[i] = true;

				// Carico le thumbs relative
				obj.loadThumb(urls, i);
			}
		});
	},

	loadThumb: function(urls, i){
		var obj = this;
		
		return new Asset.image(urls[1], {
			alt: obj.nodes[i].getAttribute('title'),
			onload: function(){
				if(obj.isThumbLoaded[i]) return false;
	
				// Prima thumb
				obj.myThumbs[i] = this;
				obj.myThumbs[i].addEvent('click', function(){
					obj.moveTo(i);
				});
				
				// Seconda thumb
				obj.myThumbs2[i] = this.clone();
				obj.myThumbs2[i].addEvent('click', function(){
					obj.moveTo(i);					
				});

				// Seleziono se sono le prime thumbs
				if(i == 0) obj.myThumbs[i].addClass('KLselected');
				if(i == 0) obj.myThumbs2[i].addClass('KLselected');
	
				// Mostro il numero di foto caricate
				obj.mainContainer.getElement('.KLcounter').innerHTML = (i + 1) + '/' + obj.nodes.length;
				var percentage = -100 + (i + 1) * 100 / obj.nodes.length;
				obj.mainContainer.getElement('.KLcounter').setStyle('background-position', percentage + 'px 0');

				obj.isThumbLoaded[i] = true;
				
				// Scrivo le immagini
				obj.injectImages(urls, i);

				// Carico la prossima immagine
				obj.load(i + 1);
			}
		});
	},

	injectImages: function(urls, i){
		// Scrivo l'immagine
		this.myPictures[i].inject(this.element);

		// Scrivo le thumbs
		this.myThumbs[i].setOpacity(0).inject(this.thumbsContainer);
		if(this.thumbsContainer2)
			this.myThumbs2[i].inject(this.thumbsContainer2.getElement('div'));
		
		// Faccio apparire le thumb con un'animazione
		this.myThumbs[i].tween('opacity', 1);
		this.myThumbs2[i].tween('opacity', 1);
	},

	toggleLoading: function(){
		if(this.myThumbs2.length < this.buffer) return false;
		
		var span = this.controllers.getElement('.KLcounter');
		if(this.stopLoading){
			span.removeClass('KLstopped');
			this.stopLoading = null;
			this.load(this.myThumbs2.length);
		}
		else{
			span.addClass('KLstopped');
			this.stopLoading = true;
		}
	},
	
	adaptToContainer: function(){
		if(!this.mainContainer) return false;
		
		var p = this.mainContainer.getParent();
		var h = p.getHeight() - p.getStyle('paddingTop').toInt() - p.getStyle('paddingBottom').toInt() - p.getStyle('marginTop').toInt() - p.getStyle('marginBottom').toInt() - this.mainContainer.offsetTop;

		this.mainContainer.setStyle('height', h);
	},


	// Animazioni e cazzi vari ---------------------------------------------------------------------
	openCurtains: function(){
		if(this.mainContainer.getElement('.KLpre_counter'))
			this.mainContainer.getElement('.KLpre_counter').destroy();
		
		// Faccio comparire tutto
		this.controllers.setStyle('display', 'block');
		this.element.setStyle('display', 'block');
		this.showTitle();

		if(this.options.singleMode)
			this.adaptToContainer();
		else if(this.options.forceHeight && this.options.maxSize){
			var h = this.options.maxSize + this.title.getHeight() + this.controllers.getHeight() + 20;
			this.mainContainer.tween('height', h);
		}
		else
			this.mainContainer.setStyle('height', 'auto');

		// Seleziono la prima foto		
		this.moveTo(0);
	},

	moveTo: function(num, periodical){
		if(!this.play) return false;
		
		// Interrompo il play automatico
		if(!periodical) this.play.cancel();

		// Chiudo l'eventuale pannello thumb
		if(this.thumbsContainer2 && this.thumbsContainer2.getOpacity())
			this.thumbsContainer2.tween('opacity', 0);

		// Determino l'immagine desiderata
		if(num < 0) num = 0;
		var pic = this.myPictures[num];
		if(!pic){
			this.play.cancel();
			return false;
		}

		this.previous = this.current;
		this.current = num;

		// Seleziono il bottone su cui ho cliccato
		this.selectButton(num);	

		// Mostro il titolo
		this.showTitle();

		// Scelgo il tipo di animazione	e avvio
		if(this.options.singleMode)
			this.singleMotion(pic);
		else
			this.slideMotion(pic);
	},

	singleMotion: function(pic){
		// Nascondo la precedente
		if(this.myPictures[this.previous])
			this.myPictures[this.previous].setOpacity(0);

		// Scrollo al punto in cui inizia la nuova immagine
		var amount = pic.offsetLeft;
		if(Browser.Engine.presto){
			amount += this.element.scrollLeft;
			pic.setStyle('vertical-align', 'middle');
		}
		this.scroll.set(amount, 0);

		// Calcolo il marginTop che l'immagine deve avere rispetto al contenitore
		var viewport = this.mainContainer.getHeight() - this.controllers.getHeight();
		var marginTop = (viewport - pic.getHeight() - this.title.getHeight()) / 2;
		
		// Avvio l'animazione
		this.element.morph({
			height: pic.getHeight(),
			width: pic.getWidth(),
			marginTop: marginTop
		});
	},

	slideMotion: function(pic){
		var w = this.element.getWidth();
		var offset = pic != this.element.getLast()?(w - pic.getWidth()) / 2:0;
	
		// Avvio l'animazione
		this.scroll.options.offset.x = -offset;
		var amount = Browser.Engine.presto?pic.offsetLeft + this.element.scrollLeft:pic.offsetLeft;
		this.scroll.start(amount);
	},

	selectButton: function(num){
		var thumb = this.myThumbs[num];
		if(!thumb) return false;

		// Seleziono il thumb1 corrente
		if(this.thumbsContainer.getElement('.KLselected'))
			this.thumbsContainer.getElement('.KLselected').removeClass('KLselected');
		thumb.addClass('KLselected');

		// Seleziono il thumb2 corrente
		if(this.thumbsContainer2){
			var thumb2 = this.myThumbs2[num];
			if(this.thumbsContainer2.getElement('.KLselected'))
				this.thumbsContainer2.getElement('.KLselected').removeClass('KLselected');
			thumb2.addClass('KLselected');
		}

		// Calcolo la posizione della thumb e l'offset
		var viewport = this.thumbsContainer.getWidth();
		var container = this.thumbsContainer.scrollWidth;
		var offset = (viewport / 2) - (thumb.getWidth() / 2);
		
		if(Browser.Engine.presto){
			if(container - thumb.offsetLeft + this.thumbsContainer.scrollLeft < viewport)
				offset -= viewport - (container - thumb.offsetLeft + this.thumbsContainer.scrollLeft);

			var amount = thumb.offsetLeft + this.thumbsContainer.scrollLeft;
		}
		else{
			if(container - thumb.offsetLeft < viewport)
				offset -= viewport - (container - thumb.offsetLeft);

			var amount = thumb.offsetLeft;			
		}		

		// Faccio partire l'animazione
		this.scrollThumbs.options.offset.x = -offset;
		this.scrollThumbs.start(amount);
	},

	showTitle: function(){
		if(!this.options.viewTitle) return false;
		var div = this.title;
		var currentPic = this.myPictures[this.current]
		if(!currentPic) return false;
		
		if(this.options.mode == 'folder')
			var urls = this.getPicUrlFromFolder(this.nodes[this.current]);
		else
			var urls = this.getPicUrl(this.nodes[this.current]);

		// Nascondo il titolo
		div.setOpacity(0);
		div.empty();

		// Link a flickr o titolo senza link
		if(this.options.linkToFlickr){
			var a = new Element('a', {href: urls[2], target: '_blank'}).inject(div);
			a.innerHTML = currentPic.alt;
		}
		else{
			var span = new Element('span').inject(div);
			span.innerHTML = currentPic.alt;
		}

		// Autore
		if(this.options.showOwner){
			var div2 = new Element('div').addClass('KLinfo').inject(div);

			if(this.options.linkToFlickr){
				var a = new Element('a', {href: urls[4], target: '_blank'}).inject(div2);
				a.innerHTML = urls[3];
			}
			else{
				var span = new Element('span').inject(div2);
				span.innerHTML = urls[3];
			}
		}	
		
		// Esco se non sono definiti ne autore ne 
		if(currentPic.alt == '' && urls[3] == '')
			return false;

		div.tween('opacity', 1);
	},

	toggleThumbs: function(){
		if(!this.thumbsContainer2) return false;
		var viewport = this.mainContainer.getHeight() - this.controllers.getHeight();

		this.thumbsContainer2.setStyle('height', viewport - 10);
		
		if(this.thumbsContainer2.getStyle('display') == 'none'){
			this.thumbsContainer2.setStyles({
				opacity: 0,
				display: 'block'
			});
			this.play.cancel();
			this.thumbsContainer2.tween('opacity', .9);
		}
		else
			this.thumbsContainer2.tween('opacity', 0);
	}
});


// Slideshow ---------------------------------------------------------------------------------------
var Slideshow = new Class({
	
	Extends: Fx.Scroll,

	pxs: 60,
	parentObj: null,
	
	go: function(obj){
		this.parentObj = obj;

		// Chiudo l'eventuale pannello thumb
		if(this.parentObj.thumbsContainer2)
			this.parentObj.thumbsContainer2.tween('opacity', 0);

		// Stop
		if(this.timer){
			this.cancel();
			return false;
		}

		// Riavvolgo se sono all'ultima immagine
		if(this.parentObj.current == this.parentObj.myPictures.length - 1){
			this.parentObj.scroll.chain(function(){this.go(this.parentObj);}.bind(this));
			this.parentObj.moveTo(0);
			return false;
		}
		
		var from = this.parentObj.element.scrollLeft + this.parentObj.element.getWidth();
		var to = this.parentObj.element.scrollWidth;
		var duration = ((to - from) / this.pxs * 1000).round();
		
		// Faccio partire l'animazione
		this.options.duration = duration;
		this.start(to);
	},
	
	step: function(){
		var time = $time();
		var now = this.parentObj.element.scrollLeft + this.parentObj.element.getWidth();
		var next = this.parentObj.myPictures[this.parentObj.current + 1];
		if(next && now >= next.offsetLeft + next.getWidth()){
			this.parentObj.current++;
			this.parentObj.selectButton(this.parentObj.current);
		}

		if (time < this.time + this.options.duration){
			var delta = this.options.transition((time - this.time) / this.options.duration);
			this.set(this.compute(this.from, this.to, delta));
		}
		else{
			this.set(this.compute(this.from, this.to, 1));
			this.complete();
			this.parentObj.selectButton(this.parentObj.current);
		}
	}
});


// Slideshow 2 -------------------------------------------------------------------------------------
var Slideshow2 = new Class({
	timer: null,
	parentObj: null,
	interval: 5000,
	
	go: function(obj){
		this.parentObj = obj;
		this.interval = obj.options.interval < 1000?1000:obj.options.interval;
		
		// Stop
		if(this.timer){
			this.cancel();
			return false;
		}

		this.move();
		
		if(!this.timer){
			this.parentObj.controllers.getElement('.KLplay').setProperty('src', this.parentObj.options.root + '/img/pause.gif');
			this.timer = this.move.periodical(this.interval, this);
		}
	},
	
	move: function(){
		this.parentObj.moveTo(this.parentObj.current + 1, true);
	},
	
	cancel: function(){
		if(!this.parentObj) return false;
		$clear(this.timer);
		this.timer = null;
		this.parentObj.controllers.getElement('.KLplay').setProperty('src', this.parentObj.options.root + '/img/play.gif');
	}
});
