/**
Script: Slideshow.Azrha.js
	Slideshow.Emsys - Emsys extension for Slideshow, includes zooming and panning effects.

License:
	MIT-style license.

Copyright:
	Copyright (c) 2008 [Aeron Glemann](http://www.electricprism.com/aeron/).
	
Dependencies:
	Slideshow.
*/

Slideshow.Azrha = new Class({
	Extends: Slideshow,
	
	options: {
		pan: [100, 100],
		zoom: [50, 50]
	},
	
/**
Constructor: initialize
	Creates an instance of the Slideshow class.

Arguments:
	element - (element) The wrapper element.
	data - (array or object) The images and optional thumbdims, captions and links for the show.
	options - (object) The options below.

Syntax:
	var myShow = new Slideshow.Azrha(element, data, options);
*/

	initialize: function(el, data, options){
		options.overlap = true;
		options.resize = true;
		options.slide = 0;
		options.thumbdims = false;
		['pan', 'zoom'].each(function(p){
				if ($chk(this[p])){
					if ($type(this[p]) != 'array') this[p] = [this[p], this[p]];
					this[p].map(function(n){return (n.toInt() || 0).limit(0, 100);});					
				}
		}, options);
		this.setOptions(options);
		this.slideshow = $(el);
		if (!this.slideshow) 
			return;
		this.slideshow.set('styles', {'display': 'block', 'position': 'relative', 'z-index': 0});
		var match = window.location.href.match(this.options.match);
		this.slide = (this.options.match && match) ? match[1].toInt() : this.options.slide;
		this.counter = this.delay = this.transition = 0;
		this.direction = 'left';
		this.paused = false;
		if (!this.options.overlap)
			this.options.duration *= 2;
		var anchor = this.slideshow.getElement('a') || new Element('a');
		if (!this.options.href)
			this.options.href = anchor.get('href') || '';
		if (this.options.hu.length && !this.options.hu.test(/\/$/)) 
			this.options.hu += '/';
		if (this.options.fast === true)
			this.options.fast = 2;
			
		// styles
		
		var keys = ['slideshow', 'first', 'prev', 'play', 'pause', 'next', 'last', 'images', 'captions', 'controller', 'thumbdims', 'hidden', 'visible', 'inactive', 'active', 'loader'];
		var values = keys.map(function(key, i){
			return this.options.classes[i] || key;
		}, this);
		this.classes = values.associate(keys);
		this.classes.get = function(){
			var str = '.' + this.slideshow;
			for (var i = 0, l = arguments.length; i < l; i++)
				str += ('-' + this[arguments[i]]);
			return str;
		}.bind(this.classes);
			
		// data	
			
		if (!data){
			this.options.hu = '';
			data = {};
			var x = this.classes.get('thumbdims') + ' img';
			var thumbdims = this.slideshow.getElements(x);
			this.slideshow.getElements(this.classes.get('images') + ' img').each(function(img, i){
				var src = img.get('src');
				var caption = $pick(img.get('alt'), img.get('title'), '');
				var parent = img.getParent();
				var properties = (parent.get('tag') == 'a') ? parent.getProperties : {};
				var href = img.getParent().get('href') || '';
				var thumbdim = (thumbdims[i]) ? thumbdims[i].get('src') : '';
				data[src] = {'caption': caption, 'href': href, 'thumbdim': thumbdim};
			});
		}
		var loaded = this.load(data);
		if (!loaded)
			return; 
		
		// events
		
		this.events = $H({'keydown': [], 'keyup': [], 'mousemove': []});
		var keyup = function(e){
			switch(e.key){
				case 'left': 
					this.prev(e.shift); break;
				case 'right': 
					this.next(e.shift); break;
				case 'p': 
					this.pause(); break;
			}
		}.bind(this);		
		this.events.keyup.push(keyup);
		document.addEvent('keyup', keyup);

		// required elements
			
		var el = this.slideshow.getElement(this.classes.get('images'));
		var images = (el) ? el.empty() : new Element('div', {'class': this.classes.get('images').substr(1)}).inject(this.slideshow);
		var div = images.getSize();
		this.height = this.options.height || div.y;		
		this.width = this.options.width || div.x;
		images.set({'styles': {'display': 'block', 'height': this.height, 'overflow': 'hidden', 'position': 'relative', 'width': this.width}});
		this.slideshow.store('images', images);
		this.a = this.image = this.slideshow.getElement('img') || new Element('img');
		if (Browser.Engine.trident && Browser.Engine.version > 4)
			this.a.style.msInterpolationMode = 'bicubic';
		this.a.set('styles', {'display': 'none', 'position': 'absolute', 'zIndex': 1});
		this.b = this.a.clone();
		[this.a, this.b].each(function(img){
			anchor.clone().cloneEvents(anchor).grab(img).inject(images);
		});
		
		// optional elements
		
		if (this.options.captions)
 			this._captions();
		if (this.options.controller)
			this._controller();
		if (this.options.loader)
 			this._loader();
		if (this.options.thumbdims)
			this._thumbdims();
			
		var x = 1;

		// begin show
		
		this._preload();
	},

	/**
	Public method: load
		Loads a new data set into the show: will stop the current show, rewind and rebuild thumbdims if applicable.

	Arguments:
		data - (array or object) The images and optional thumbdims, captions and links for the show.

	Syntax:
		myShow.load(data);
	*/

		load: function(data){
			this.firstrun = true;
			this.showed = {'array': [], 'i': 0};
			if ($type(data) == 'array'){
				this.options.captions = false;			
				data = new Array(data.length).associate(data.map(function(image, i){ return image + '?' + i })); 
			}
			this.data = {'images': [], 'captions': [], 'hrefs': [], 'thumbdims': []};
			for (var image in data){
				var obj = data[image] || {};
				var caption = (obj.caption) ? obj.caption.trim() : '';
				var href = (obj.href) ? obj.href.trim() : ((this.options.linked) ? this.options.hu + image : this.options.href);
				var thumbdim = caption;
				this.data.images.push(image);
				this.data.captions.push(caption);
				this.data.hrefs.push(href);
				this.data.thumbdims.push(thumbdim);
			}
			if (this.options.random)
				this.slide = $random(0, this.data.images.length - 1);
			
			// only run when data is loaded dynamically into an existing slideshow instance
			
			if (this.options.thumbdims && this.slideshow.retrieve('thumbdims'))
				this._thumbdims();
			if (this.slideshow.retrieve('images')){
				[this.a, this.b].each(function(img){
					['morph', 'tween'].each(function(p){
						if (this.retrieve(p)) this.get(p).cancel();
					}, img);
				});
				this.slide = this.transition = 0;
				this.go(0);		
			}
			return this.data.images.length;
		},
		

	/**
	Private method: preload
		Preloads the next slide in the show, once loaded triggers the show, updates captions, thumbdims, etc.
	*/

		_preload: function(fast){
			if (!this.preloader)
				{
				var x = {'onload': function(){
					this.store('loaded', true);
				}};
			 	this.preloader = new Asset.image(this.options.hu + this.data.images[this.slide], x);	
		}
			var thisloaded = this.preloader.retrieve('loaded');
			if (this.preloader.retrieve('loaded') && $time() > this.delay && $time() > this.transition){
				if (this.stopped){
					if (this.options.captions)
						this.slideshow.retrieve('captions').get('morph').cancel().start(this.classes.get('captions', 'hidden'));
					this.pause(1);
					if (this.end)
						this.fireEvent('end');
					this.stopped = this.end = false;
					return;				
				}					
				this.image = (this.counter % 2) ? this.b : this.a;
				this.image.set('styles', {'display': 'block', 'height': 'auto', 'visibility': 'hidden', 'width': 'auto', 'zIndex': this.counter});
				['src', 'height', 'width'].each(function(prop){
					this.image.set(prop, this.preloader.get(prop));
				}, this);
				this._resize(this.image);
				this._center(this.image);
				var anchor = this.image.getParent();
				if (this.data.hrefs[this.slide])
					anchor.set('href', this.data.hrefs[this.slide]);			
				else
					anchor.erase('href');
				var text = (this.data.captions[this.slide])
					? this.data.captions[this.slide].replace(/<.+?>/gm, '').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, "'") 
					: '';
				this.image.set('alt', text);		
				if (this.options.titles)
					anchor.set('title', text);
				if (this.options.loader)
					this.slideshow.retrieve('loader').fireEvent('hide');
				if (this.options.captions)
					this.slideshow.retrieve('captions').fireEvent('update', fast);				
				if (this.options.thumbdims)
					this.slideshow.retrieve('thumbdims').fireEvent('update', fast); 			
				this._show(fast);
				this._loaded();
			} 
			else {
				if ($time() > this.delay && this.options.loader)
					this.slideshow.retrieve('loader').fireEvent('show');
				this.timer = (this.paused && this.preloader.retrieve('loaded')) ? null : this._preload.delay(100, this, fast); 
			}
		},

/**
Private method: show
	Does the slideshow effect.
*/

	_show: function(fast){
		if (!this.image.retrieve('morph')){
			['a', 'b'].each(function(image){
				this[image].set('tween', {
					'duration': this.options.duration, 'link': 'cancel', 'onStart': this._start.bind(this), 'onComplete': this._complete.bind(this), 'property': 'opacity'}
				).get('morph', {
					'duration': (this.options.delay + this.options.duration * 2), 'link': 'cancel', 'transition': $arguments(0)}
				);
			}, this);
		}
		this.image.set('styles', {'bottom': 'auto', 'left': 'auto', 'right': 'auto', 'top': 'auto'});
		var props = ['top left', 'top right', 'bottom left', 'bottom right'][this.counter % 4].split(' ');
		props.each(function(prop){this.image.setStyle(prop, 0);}, this);
		dh = this.height / this.preloader.height;
		dw = this.width / this.preloader.width;
		delta = (dw > dh) ? dw : dh;
		var values = {};
		var zoom = ($random.run(this.options.zoom) / 100.0) + 1;
		var pan = Math.abs(($random.run(this.options.pan) / 100.0) - 1);
		['height', 'width'].each(function(prop, i){
			var e = Math.ceil(this.preloader[prop] * delta);
			var s = (e * zoom).toInt();		
			values[prop] = [s, e];
			if (dw > dh || i){
				e = (this[prop] - this.image[prop]);
				s = (e * pan).toInt();			
				values[props[i]] = [s, e];
			}
		}, this);
		var paused = (this.firstrun && this.options.paused);
		if (fast || paused){
			this._center(this.image);
			this.image.get('morph').cancel();
			if (paused)
				this.image.get('tween').cancel().set(0).start(1);
			else
				this.image.get('tween').cancel().set(1);
		} 
		else{
			this.image.get('morph').start(values);
			this.image.get('tween').set(0).start(1);
		}
	},
	
	_buildMBDiv: function(i)
	{
		var mb = $("mb_" + this.data.captions[i].toLowerCase());
		var wellnessdims = $('wellnessdims');

		var el = $('mb_show');
		var mbShow = (el) ? el.empty() : new Element('div', {'id': 'mb_show'});
		mbShow.setStyles({'position':'relative', 'display': 'none', 'overflow': 'hidden'});
		var mbImage = new Element('div', {'id': 'mb_image'});
		var showImage = this.preloader.clone();
		showImage.inject(mbImage);
		//showImage.setStyles({'height':200, 'width':300, 'left':50});
		showImage.set('styles', {'height':250, 'width':300, 'position':'relative', 'left': '50px'});
		var mbFiller = new Element('div', {'id': 'mb_filler'});
		mbFiller.set('html', '<br/><br/>');
		var mbSpan = new Element('div', {'id': 'mb_span'});
		mbSpan.set('styles', {'font-weight':'bold'});
		mbSpan.set('html', mb.get('html'));
		mbImage.inject(mbShow);
		mbFiller.inject(mbShow);
		mbSpan.inject(mbShow);
		mbShow.inject(wellnessdims);
		var x = 1;

	},
	
	/**
	Private method: thumbdims
		Builds the optional thumbdims element, adds interactivity.
		This method can safely be removed if the thumbdims option is not enabled.
	*/

		_thumbdims: function(){
	 		if (this.options.thumbdims === true) 
	 			this.options.thumbdims = {}; 
	 		var pel = this.slideshow.getParent();
			var thumbdims = pel.getElement(this.classes.get('thumbdims'));
			thumbdims.setStyle('overflow', 'hidden');
			//x = el.empty();
			/*
			var thumbdims = (el) ? el.empty() : new Element('div', {'class': this.classes.get('thumbdims').substr(1)}).inject(this.slideshow);
			thumbdims.setStyle('overflow', 'hidden');
			var ul = new Element('ul', {'tween': {'link': 'cancel'}}).inject(thumbdims);
			*/
			var ul = thumbdims.getElement("ul");
			var lis = ul.getChildren("li");
			this.data.thumbdims.each(function(thumbdim, i){
				var li = lis[i];
				var a = li.getElement("a");
				var aevents = {
					'click': function(i){
						this.go(i); 
						var caption = "#mb_" + this.data.captions[i].toLowerCase();
						this._buildMBDiv(i);
						doMediaboxInline(this.preloader, "#mb_show", '400', '440');
						return false; 
					}.pass(i, this),
					'loaded': function(){
						this.data.thumbdims.pop();
						if (!this.data.thumbdims.length){
							var div = thumbdims.getCoordinates();
							var props = thumbdims.retrieve('props');			
							var limit = 0, pos = props[1], size = props[2];		
							thumbdims.getElements('li').each(function(li){			
								var li = li.getCoordinates();		
								if (li[pos] > limit) limit = li[pos];
							}, this);			
							thumbdims.store('limit', div[size] + div[props[0]] - limit);
						}
					}.bind(this)
				};
				a.addEvents(aevents);
				a.set('href', this.options.hu + this.data.images[i]);
				a.set('morph', $merge(this.options.thumbdims, {'link': 'cancel'}));
				
			}, this);
			var x = 1;
			thumbdims.set('events', {
				'scroll': function(n, fast){
					var div = this.getCoordinates();
					var ul = this.getElement('ul').getPosition();
					var props = this.retrieve('props');
					var axis = props[3], delta, pos = props[0], size = props[2], value;				
					var tween = this.getElement('ul').get('tween', {'property': pos});	
					if ($chk(n)){
						var li = this.getElements('li')[n].getCoordinates();
						delta = div[pos] + (div[size] / 2) - (li[size] / 2) - li[pos]	
						value = (ul[axis] - div[pos] + delta).limit(this.retrieve('limit'), 0);
						if (fast)	
							tween.set(value);
						else						 
							tween.start(value);
					}
					else{
						var area = div[props[2]] / 3, page = this.retrieve('page'), velocity = -0.2;			
						if (page[axis] < (div[pos] + area))
							delta = (page[axis] - div[pos] - area) * velocity;
						else if (page[axis] > (div[pos] + div[size] - area))
							delta = (page[axis] - div[pos] - div[size] + area) * velocity;			
						if (delta){			
							value = (ul[axis] - div[pos] + delta).limit(this.retrieve('limit'), 0);
							tween.set(value);
						}
					}				
				}.bind(thumbdims),
				'update': function(fast){
					var thumbdims = this.slideshow.retrieve('thumbdims');
					var as = thumbdims.getElements('a');
					as.each(function(a, i){	
						if (i == this.slide){
							if (!a.retrieve('active', false)){
								a.store('active', true);
								var active = this.classes.get('thumbdims', 'active');							
								if (fast) a.get('morph').set(active);
								else a.morph(active);
							}
						} 
						else {
							if (a.retrieve('active', true)){
								a.store('active', false);
								var inactive = this.classes.get('thumbdims', 'inactive');						
								if (fast) a.get('morph').set(inactive);
								else a.morph(inactive);
							}
						}
					}, this);
					if (!thumbdims.retrieve('mouseover'))
						thumbdims.fireEvent('scroll', [this.slide, fast]);
				}.bind(this)
			})
			var div = thumbdims.getCoordinates();
			thumbdims.store('props', (div.height > div.width) ? ['top', 'bottom', 'height', 'y'] : ['left', 'right', 'width', 'x']);
			var mousemove = function(e){
				var div = this.getCoordinates();
				if (e.page.x > div.left && e.page.x < div.right && e.page.y > div.top && e.page.y < div.bottom){
					this.store('page', e.page);			
					if (!this.retrieve('mouseover')){
						this.store('mouseover', true);
						this.store('timer', function(){this.fireEvent('scroll');}.periodical(50, this));
					}
				}
				else {
					if (this.retrieve('mouseover')){
						this.store('mouseover', false);				
						$clear(this.retrieve('timer'));
					}
				}
			}.bind(thumbdims);
			this.events.mousemove.push(mousemove);
			document.addEvent('mousemove', mousemove);
			this.slideshow.store('thumbdims', thumbdims);
		}
});
