/**
Script: Slideshow.Push.js
	Slideshow.Push - Push extension for Slideshow.

License:
	MIT-style license.

Copyright:
	Copyright (c) 2010 [Spinnaker360].

Dependencies:
	Slideshow.
	Mootools 1.2 More: Fx.Elements.
*/

Slideshow.Push = new Class({
	Extends: Slideshow,


/**
Constructor: initialize
	Creates an instance of the Slideshow class.

Arguments:
	element - (element) The wrapper element.
	data - (array or object) The images and optional thumbnails, captions and links for the show.
	options - (object) The options below.

Syntax:
	var myShow = new Slideshow.Push(element, data, options);
*/
	initialize: function(el, data, options) {
		options.overlap = true;
		options.direction = options.direction || 'left'; // default slide direction to 'left'

		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;


		// setup slide direction for next / previous slideshow actions
		this.direction = this.options.direction;
		this._nextDir = this.direction;
		this._prevDir = this.direction == 'right' ? 'left': 'right';


		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', 'thumbnails', '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 thumbnails = this.slideshow.getElements(this.classes.get('thumbnails') + ' img');
			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 thumbnail = (thumbnails[i]) ? thumbnails[i].get('src') : '';
				data[src] = {
					'caption': caption,
					'href': href,
					'thumbnail': thumbnail
				};
			});
		}
		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
		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.thumbnails) {
			this._thumbnails(); // begin show
		}
		this._preload();
	},


/**
Private method: show
	Does the slideshow effect.
*/

	_show: function(fast) {
		var images = [this.image, ((this.counter % 2) ? this.a: this.b)];
		if (!this.image.retrieve('fx')) {
			this.image.store('fx', new Fx.Elements(images, {
				'duration': this.options.duration,
				'link': 'cancel',
				'onStart': this._start.bind(this),
				'onComplete': this._complete.bind(this),
				'transition': this.options.transition
			}));
		}
		this.image.set('styles', {
			'left': 'auto',
			'right': 'auto'
		}).setStyle(this.direction, this.width);
		var values = {
			'0': {},
			'1': {}
		};
		values['0'][this.direction] = [this.width, 0];
		values['1'][this.direction] = [0, -this.width];
		if (images[1].getStyle(this.direction) == 'auto') {
			var width = this.width - images[1].width;
			images[1].set('styles', {
				'left': 'auto',
				'right': 'auto'
			}).setStyle(this.direction, width);
			values['1'][this.direction] = [width, -this.width];
		}
		if (fast) {
			for (var prop in values) {
				if (values.hasOwnProperty(prop)) {
					values[prop][this.direction] = values[prop][this.direction][1];
				}
			}
			this.image.retrieve('fx').cancel().set(values);
		} else {
			this.image.retrieve('fx').start(values);
		}
	},


/**
Private method: loaded
	Run after the current image has been loaded, sets up the next image to be shown.
*/

	_loaded: function(){
		this.counter++;
		this.delay = (this.paused) ? Number.MAX_VALUE : $time() + this.options.duration + this.options.delay;
		this.direction = this._nextDir;
		this.transition = (this.options.fast == 2 || (this.options.fast == 1 && this.paused)) ? 0 : $time() + this.options.duration;
		if (this.slide + 1 == this.data.images.length && !this.options.loop && !this.options.random)
			this.stopped = this.end = true;
		if (this.options.random){
			this.showed.i++;
			if (this.showed.i >= this.showed.array.length){
				var n = this.slide;
				if (this.showed.array.getLast() != n) this.showed.array.push(n);
				while (this.slide == n)
					this.slide = $random(0, this.data.images.length - 1);
			}
			else
				this.slide = this.showed.array[this.showed.i];
		}
		else
			this.slide = (this.slide + 1) % this.data.images.length;
		if (this.image.getStyle('visibility') != 'visible')
			(function(){ this.image.setStyle('visibility', 'visible'); }).delay(1, this);
		if (this.preloader)
			this.preloader = this.preloader.destroy();
		this._preload();
	},


/**
Public method: go
	Jump directly to a slide in the show.

Arguments:
	n - (integer) The index number of the image to jump to, 0 being the first image in the show.

Syntax:
	myShow.go(n);
*/

	go: function(n, direction) {
		if ((this.slide - 1 + this.data.images.length) % this.data.images.length == n || $time() < this.transition) {
			return;
		}
		$clear(this.timer);
		this.delay = 0;
		this.direction = (direction) ? direction: ((n < this.slide) ? this._prevDir: this._nextDir);
		this.slide = n;
		if (this.preloader) {
			this.preloader = this.preloader.destroy();
		}
		this._preload(this.options.fast == 2 || (this.options.fast == 1 && this.paused));
	},


/**
Public method: next
	Goes to the next image in the show.

Syntax:
	myShow.next();
*/

	next: function(last) {
		var n = (last) ? this.data.images.length - 1 : this.slide;
		this.go(n, this._nextDir);
	},


/**
Public method: prev
	Goes to the previous image in the show.

Syntax:
	myShow.prev();
*/

	prev: function(first) {
		var n = 0;
		if (!first) {
			if (this.options.random) { // if it's a random show get the previous slide from the showed array
				if (this.showed.i < 2) {
					return;
				}
				this.showed.i -= 2;
				n = this.showed.array[this.showed.i];
			} else {
				n = (this.slide - 2 + this.data.images.length) % this.data.images.length;
			}
		}
		this.go(n, this._prevDir);
	}
});