/*
Credit:
 Heavily based off of noobSlide by luistar15, <leo020588 [at] gmail.com>
 Extended and reconfigured a bit.

Author:
	keith baker, <god.dreams@gmail.com>

License:
	MIT License
 
Class
	mooSlide (rev. 2008-09-04)

Arguments:
	Parameters - see Parameters below

Parameters:

Properties:
	
Methods:

Requires:
*/
var mooSlide = new Class({
	Implements: [Options],

	defaultOptions: {
		'mode': 'horizontal',
		'modes': {
			'horizontal': ['left','width'],
			'vertical': ['top','height']
		},
		'button_event': 'click',
		'handle_event': 'click',
		'onWalk': null,
		'fxOptions': {
			'duration':500,
			'wait':false
		},
		'currentIndex': null,
		'previousIndex': null,
		'nextIndex': null,
		'interval': 5000,
		'autoPlay': false,
		'startPlay': null,
		'handles': null,
		'addButtons': null,
		'addImageButtons': null,
		'fadeImages': false,
		'hoverButtons': null,
		'hoverActionsFx': {
			'duration': 250,
			'transition': Fx.Transitions.linear
		},
		'heightOffset': 25,
		'widthOffset': 0,
		'startItem':0,
		'description': null
	},

	initialize: function(options){
		this.setOptions($merge(this.defaultOptions, options));

		// are decriptions/captions established?
		// we call this before we set the scroller size
		if(this.options.description){
			// not generic
			this.captions = this.options.box.getElements('.content');
			this.captions.dispose();
			this.closeCaption(this.captions, this.options.startItem);
		}

		// the mask that hides what we don't want to see
		// we do this in javascript so that with JS off we get the full experience
		this.options.slideContainer.set({
				'styles': {
					'height': this.options.box.getFirst().getSize().y + (this.options.heightOffset * 2),
					'width': this.options.box.getFirst().getSize().x + this.options.widthOffset
				}
		});

		this.items = this.options.box.getChildren();
		
		// fade out all images except the starting one
		if(this.options.fadeImages){
			// not generic
			this.items.getElement('.slide').fade('out');
			this.items[this.options.startItem].getElement('.slide').fade('in');
		}

		// if we have handles, use them
		if(this.options.handles !== null){
			this.addHandleButtons(this.options.handles);
		}

		// establish buttons
		this.buttons = {
			'previous': [],
			'next': [],
			'play': [],
			'playback': [],
			'stop': []
		};

		if(this.options.addButtons !== null){
			for(var action in options.addButtons){
				this.addActionButtons(action, $type(options.addButtons[action])=='array' ? options.addButtons[action] : [options.addButtons[action]]);
			}
		}

		if(this.options.hoverButtons !== null){
			this.hoverAction(options.box, this.options.hoverButtons, this.options.hoverActionsFx, this.options.modes[this.options.mode][0]);
		}

		// establish size of box
		if(this.options.modes[this.options.mode][1] == 'height'){
			this.size = this.options.box.getFirst().getSize().y.toInt();
		} else {
			this.size = this.options.box.getFirst().getSize().x.toInt();
		}

		// set up styling for box depending on type of slide
		this.options.box.setStyle(this.options.modes[this.options.mode][1],(this.size*this.items.length)+'px');
		this.options.box.setStyle('z-index','10');
		if(this.options.modes[this.options.mode][1] == 'height'){
			this.options.box.setStyle(this.options.modes[this.options.mode][0], this.options.heightOffset+'px');
		} else {
			this.options.box.setStyle(this.options.modes[this.options.mode][0], this.options.widthOffset+'px');
		}

		this.fx = new Fx.Tween(this.options.box,$extend((this.options.fxOptions),{'property':this.options.modes[this.options.mode][0]}));
		this.walk((this.options.startItem),true,true);
	},

	closeCaption: function(captions, index) {
		var captionFx = new Fx.Tween(this.options.captionsContainer,{
			'link': 'chain',
			'property': 'opacity',
			'duration': 'short'
		});
		captionFx.start(1,0).chain(function(){
			captions.dispose();
			captions[index].inject(this.options.captionsContainer);
			captionFx.start(0,1);
		}.bind(this));
	},

	addHandleButtons: function(handles){
		for(var i=0;i<handles.length;i++){
			handles[i].addEvent(this.options.handle_event,this.walk.bind(this,[i,true]));
		}
	},

	addActionButtons: function(action,buttons){
		for(var i=0; i<buttons.length; i++){
			switch(action){
				case 'previous': buttons[i].addEvent(this.options.button_event,this.previous.bind(this,[true]));
					break;
				case 'next': buttons[i].addEvent(this.options.button_event,this.next.bind(this,[true]));
					break;
				case 'play': buttons[i].addEvent(this.options.button_event,this.play.bind(this,[this.options.interval,'next',false]));
					break;
				case 'playback': buttons[i].addEvent(this.options.button_event,this.play.bind(this,[this.options.interval,'previous',false]));
					break;
				case 'stop': buttons[i].addEvent(this.options.button_event,this.stop.bind(this));
					break;
			}
			this.buttons[action].push(buttons[i]);
		}
	},

	hoverAction:function(box,buttons,hoverActionsFx,style){
		buttons.each(function(button){
			box.set('morph', hoverActionsFx);
			button.addEvents({
				'mouseenter': function(){
					// I'd like to make morph custom set
					if(button.get('id') == 'prev') {
						if(this.options.box.getStyle('top').toInt() !== this.options.heightOffset){
							if(this.options.fadeImages){
								this.items[this.options.currentIndex - 1].getElement('.slide').fade('in');
							}
							box.morph({'top': this.size*-this.options.currentIndex + (this.options.heightOffset * 2)});
						}
					} else {
						if(this.options.box.getStyle('top').toInt() !== -(this.items.length * this.size - (this.size + this.options.heightOffset))){
							if(this.options.fadeImages){
								this.items[this.options.currentIndex + 1].getElement('.slide').fade('in');
							}
							box.morph({'top': this.size*-this.options.currentIndex});
						}
					}
				}.bind(this),
				'mouseleave': function(){
					if(this.options.fadeImages){
						this.items.getElement('.slide').fade('out');
						this.items[this.options.currentIndex].getElement('.slide').fade('in');
					}
					box.morph({'top': this.size*-this.options.currentIndex + this.options.heightOffset});
				}.bind(this)
			});
		}.bind(this));
	},

	previous: function(manual){
		this.walk((this.options.currentIndex>0 ? this.options.currentIndex-1 : this.items.length-1),manual);
	},

	next: function(manual){
		this.walk((this.options.currentIndex<this.items.length-1 ? this.options.currentIndex+1 : 0),manual);
	},

	play: function(interval,direction,wait){
		this.stop();
		if(!wait){
			this[direction](false);
		}
		this.options.startPlay = this[direction].periodical(interval,this,[false]);
	},

	stop: function(){
		$clear(this.options.startPlay);
	},

	walk: function(item,manual,noFx){
		if(item !== this.options.currentIndex){
			this.options.currentIndex = item;
			this.options.previousIndex = this.options.currentIndex + (this.options.currentIndex>0 ? -1 : this.items.length-1);
			this.options.nextIndex = this.options.currentIndex + (this.options.currentIndex<this.items.length-1 ? 1 : 1-this.items.length);
			if(manual){
				this.stop();
			}
			if(noFx){
				this.fx.cancel().set((this.size*-this.options.currentIndex) + this.options.heightOffset +'px');
			} else {
				// again, not generic
				if(this.options.fadeImages){
					$$(this.items).getElement('.slide').fade('in');
				}
				this.fx.start(this.size*-this.options.currentIndex + this.options.heightOffset + 'px').chain(function(){
						if(this.options.fadeImages){
							$$(this.items[this.options.previousIndex].getElement('.slide'),this.items[this.options.nextIndex].getElement('.slide')).fade('out');
						}
						if(this.options.description){
							this.closeCaption(this.captions, this.options.currentIndex);
						}
				}.bind(this));
			}
			if(manual && this.options.autoPlay){
				this.play(this.options.interval,'next',true);
			}
			if(this.options.onWalk){
				this.options.onWalk((this.items[this.options.currentIndex] || null), (this.options.handles && this.options.handles[this.options.currentIndex] ? this.options.handles[this.options.currentIndex] : null));
			}
		}
	}
});
