/*
Parameters:
	box: dom element | required
	items: dom collection | required
	size: int | item size (px) | default: 240
	mode: string | 'horizontal', 'vertical' | default: 'horizontal'
	addButtons:{
		previous: single dom element OR dom collection| default: null
		next:  single dom element OR dom collection | default: null
		play:  single dom element OR dom collection | default: null
		playback:  single dom element OR dom collection | default: null
		stop:  single dom element OR dom collection | default: null
	}
	button_event: string | event type | default: 'click'
	handles: dom collection | default: null
	handle_event: string | event type| default: 'click'
	fxOptions: object | Fx.Tween options | default: {duration:500,wait:false}
	interval: int | seconds for periodical | default: 1
	autoPlay: boolean | default: false
	onWalk: event | pass arguments: currentItem, currentHandle | default: null
	startItem: int | default: 0

Properties:
	box: dom element
	items: dom collection
	size: int
	mode: string
	buttons: object
	button_event: string
	handles: dom collection
	handle_event: string
	previousIndex: int
	nextIndex: int
	fx: Fx.Tween instance
	interval: int
	autoPlay: boolean
	onWalk: function

Methods:
	previous(manual): walk to previous item
		manual: bolean | default:false
	next(manual): walk to next item
		manual: bolean | default:false
	play (interval,direction,wait): auto walk items
		interval: int | required
		direction: string | "previous" or "next" | required
		wait: boolean | required
	stop(): stop auto walk
	walk(item,manual,noFx): walk to item
		item: int | required
		manual: bolean | default:false
		noFx: boolean | default:false
	addHandleButtons(handles):
		handles: dom collection | required
	addActionButtons(action,buttons):
		action: string | "previous", "next", "play", "playback", "stop" | required
		buttons: dom collection | required

Requires:
	prototype
*/
var ProtoSlide = Class.create();

ProtoSlide.prototype = {
	initialize: function(params){
		this.items = params.items;
		this.mode = params.mode || 'horizontal';
		this.modes = {horizontal:['left','width'], vertical:['top','height']};
		this.size = params.size || 240;
		this.initSize = params.initSize || 0;
		this.partialWalk = params.partialWalk || false;
		this.box = params.box;
		this.mask = params.mask;
		this.boxContainerSlider = $(params.boxContainerSlider) || null;
		
		this.hoverPause = params.hoverPause || true;
		
		if (this.items && this.items.length>0) {
			var first = this.items[0];
			var last = this.items[this.items.length - 1];

			var firstClone = this.clone(this.items[this.items.length - 1], true);
			var lastClone = this.clone(this.items[0], true);

			// Aggiunge in cima
			// this.items.unshift(firstClone);
			first.insert({before: firstClone});

			// Appende in fondo
			// this.items.push(lastClone);
			last.insert({after: lastClone});

			if (this.mode == 'horizontal') {
				firstClone.setStyle({margin: '0 0 0 ' + (-this.size + 'px')});
			} else {
				firstClone.setStyle({margin: (-this.size + 'px') + ' 0 0 0'});
			}

		}

		if (this.mode == 'horizontal') {
			this.box.setStyle({
				width: (this.size * (this.items.length + 2)) + 'px'
			});
		} else {
			this.box.setStyle({
				height: (this.size * (this.items.length + 2)) + 'px'
			});
		}

		this.button_event = params.button_event || 'click';
		this.handle_event = params.handle_event || 'click';
		this.onWalk = params.onWalk || null;
		this.walkLimit = params.walkLimit || 99;
		this.currentIndex = null;
		this.previousIndex = null;
		this.nextIndex = null;
		this.interval = params.interval || 1;
		this.autoPlay = params.autoPlay || false;
		this.playDirection = null;
		this.stopOnFirstItem = params.stopOnFirstItem || false;
		this.stopOnLastItem = params.stopOnLastItem || false;
		this._play = null;
		this.handles = params.handles || null;
		if (this.handles){
			this.addHandleButtons(this.handles);
		}
		this.buttons = {
			previous: [],
			next: [],
			play: [],
			playback: [],
			stop: []
		};
		if (params.addButtons){
			for (var action in params.addButtons){
				this.addActionButtons(action, $type(params.addButtons[action]) == 'array' ? params.addButtons[action] : [params.addButtons[action]]);
			}
		}
		
		this.walk((params.startItem || 0), true, true, 'next');
		
		if (this.hoverPause && this.boxContainerSlider){				
			this.boxContainerSlider.observe('mouseover', this._stopAutoPlay.bind(this));
			this.boxContainerSlider.observe('mouseout', this._startAutoPlay.bind(this));
		}
	},

	_stopAutoPlay: function(){		
		this.stop();
	},
	
	_startAutoPlay: function(){
		var ctx = new Array();
		ctx[0] = this.interval;
		ctx[1] = 'next';
		ctx[2] = true;
		this.play(ctx);		
	},
	
	clone: function(element, deep) {
		if (!(element = $(element))) return;
		var clone = element.cloneNode(deep);
		clone._prototypeUID = void 0;
		if (deep) {
			var descendants = Element.select(clone, '*'), i = descendants.length;
			while (i--) {
				descendants[i]._prototypeUID = void 0;
			}
		}
		return Element.extend(clone);
	},

	addHandleButtons: function(handles) {
		for (var i = 0; i < handles.length; i++) {
			handles[i].observe(this.handle_event, this.handler.bind(this, [i]));
		}
	},

	addActionButtons: function(action, buttons) {
		for (var i = 0; i < buttons.length; i++) {
			switch (action){
				case 'previous': buttons[i].observe(this.button_event,this.previous.bind(this,[true])); break;
				case 'next': buttons[i].observe(this.button_event,this.next.bind(this,[true])); break;
				case 'play': buttons[i].observe(this.button_event,this.play.bind(this,[this.interval,'next',false])); break;
				case 'playback': buttons[i].observe(this.button_event,this.play.bind(this,[this.interval,'previous',false])); break;
				case 'stop': buttons[i].observe(this.button_event,this.stop.bind(this)); break;
			}
			this.buttons[action].push(buttons[i]);
		}
	},

	previous: function(manual){
		if (this.stopOnFirstItem) {
			var boxOffset = this.box.cumulativeOffset();
			var maskOffset = this.mask.cumulativeOffset();

			if (this.mode == 'horizontal') {
				// TODO
			} else {
				var boxTop = boxOffset.top;
				var maskTop = maskOffset.top;

				if (maskTop > boxTop) {
					this.walk((this.currentIndex > 0 ? this.currentIndex - 1 : this.items.length - 1), manual, false, 'previous');
				}
			}

		} else {
			this.walk(this.currentIndex - 1, manual, false, 'previous');
			// this.walk((this.currentIndex > 0 ? this.currentIndex - 1 : this.items.length - 1), manual, false, 'previous');
		}
	},

	next: function(manual) {
		if (this.stopOnLastItem) {
			var boxOffset = this.box.cumulativeOffset();
			var maskOffset = this.mask.cumulativeOffset();

			if (this.mode == 'horizontal') {
				// TODO
			} else {
				var boxBottom = this.box.getHeight() + boxOffset.top - 2 * this.size; // rimuovo i 2 elementi in pi�
				var maskBottom = this.mask.getHeight() + maskOffset.top;

				// console.debug("****** box: h: " + this.box.getHeight() + " top: " + boxOffset.top + " -> " + boxBottom);
				// console.debug("****** mask: h:  " + this.mask.getHeight() + " top. " + maskOffset.top + " -> " + maskBottom);
				
				if (maskBottom < boxBottom) {
					
					if (this.partialWalk) {
						this.walk((this.currentIndex <= this.items.length - 1 ? this.currentIndex + 1 : 0), manual, false, 'next');
					} else {
						this.walk((this.currentIndex < this.items.length - 1 ? this.currentIndex + 1 : 0), manual, false, 'next');
					}
				}
			}

		} else {
			this.walk(this.currentIndex + 1, manual, false, 'next');
			// this.walk((this.currentIndex <= this.items.length - 1 ? this.currentIndex + 1 : 0), manual, false, 'next');
		}

		/*} else if (this.partialWalk) {
			this.walk((this.currentIndex <= this.items.length - 1 ? this.currentIndex + 1 : 0), manual, false, 'next');
		} else {
			this.walk((this.currentIndex < this.items.length - 1 ? this.currentIndex + 1 : 0), manual, false, 'next');
		}*/
	},

	handler: function(index) {
		this.walk(index, true, false, 'handler');
	},

	play: function(context) {
		var interval = context[0];
		var direction = context[1];
		var wait = context[2];
		
		if (this.playDirection == null ) {

			// console.debug('play ' + this.playDirection + " " + direction);

			this.playDirection = direction;
			this.stop();
			if (!wait) {
				this[direction](false);
			}

			this._play = new PeriodicalExecuter(this[direction].bind(this), interval);
		} else {
			// console.debug('skip');
		}
	},

	stop: function() {
		if (this._play) {
			this._play.stop();
			this.playDirection = null;
			// console.debug('set null');
		}
	},

	getCurrentIndex: function() {
		return this.currentIndex;
	},

	getItemsSize: function(){
		return this.items.length;
	},

	getNextIndex: function(){
		var currentIndex = this.currentIndex;
		return currentIndex < (parseInt(this.items.length) - 1) ? (parseInt(currentIndex) + 1) : 0;
	},

	getPreviousIndex: function(){
		var currentIndex = this.currentIndex;
		return currentIndex > 0 ? (parseInt(currentIndex) - 1) : this.items.length - 1;
	},

	afterUpdate: function(direction, animationCtx) {
		if (this.currentIndex > this.items.length - 1) {
			this.currentIndex = 0;
		}

		if (this.currentIndex < 0) {
			this.currentIndex = this.items.length - 1;
		}

		// console.debug("new current: " + this.currentIndex);

		if (direction == 'next') {
			if (this.currentIndex == this.items.length) {
				// console.debug("sposto il box");
				
				if (this.mode == 'horizontal') {
					this.box.setStyle({left: this.size + 'px'});
				} else {
					this.box.setStyle({top: this.size + 'px'});
				}

			} else if (this.currentIndex == 0) {
				if (this.mode == 'horizontal') {
					if (this.initSize!=0){
						this.box.setStyle({left: this.initSize + 'px'});
					}else{
						this.box.setStyle({left: '0px'});
					}
				} else {
					if (this.initSize!=0){
						this.box.setStyle({top: this.initSize + 'px'});
					}else{
						this.box.setStyle({top: '0px'});
					}
				}
			}
		} else if (direction == 'previous') {
			if (this.currentIndex == this.items.length - 1) {
				// console.debug("sposto il box");

				if (this.mode == 'horizontal') {
					if (this.initSize!=0){
						this.box.setStyle({left: (-this.size * (this.items.length - 1) + this.initSize) + 'px'});
					}else{
						this.box.setStyle({left: (-this.size * (this.items.length - 1)) + 'px'});
					}
				} else {
					this.box.setStyle({top: (-this.size * (this.items.length - 1)) + 'px'});
				}
			}
		}

	},

	walk: function(item, manual, noFx, direction) {
		var currentIndexOld = this.currentIndex;
		if (Effect.Queues.get('ticker').size() == 0) {
		
			if (this.stopOnLastItem && item > 0) {
				// Verifica dell'indice passato: se troppo alto devo fermare lo slide prima
				var elementsInMask = Math.round($(this.mask).getHeight() / this.size);
				if (this.items.length - item < elementsInMask) {
					item = this.items.length - elementsInMask;
				}
			}
		
			this.currentIndex = item;

			if (this.stopOnLastItem) {
				this.previousIndex = this.currentIndex + (this.currentIndex > 0 ? -1 : this.items.length - 1);
				this.nextIndex = this.currentIndex + (this.currentIndex < this.items.length - 1 ? 1 : 1 - this.items.length);
			}

			// console.debug("going to: " + item);

			if (manual) {
				// this.stop();
			}
			if (noFx) {
				// this.fx.cancel().set((this.size *- this.currentIndex) + 'px');
			} else {
				var deltaMove = 0;

				if (direction == 'next') {
					if (this.stopOnLastItem) {
						if (this.currentIndex == 0 && this.previousIndex > this.currentIndex) {							
							if (this.currentIndex == currentIndexOld) {
								deltaMove = 0;
							} else {
								deltaMove = (this.size * this.previousIndex);
							}
							
						} else {
							var elementsDiff = Math.abs(currentIndexOld - this.currentIndex);
							deltaMove = -this.size * (elementsDiff != 0 ? elementsDiff : 1);
						}
					} else {
						deltaMove = -this.size;
					}
				} else if (direction == 'previous') {
					if (this.stopOnLastItem) {
						if (this.currentIndex == this.items.length - 1 && this.currentIndex > this.nextIndex) {
							deltaMove = - (this.size * this.currentIndex);
						} else {
							deltaMove = this.size;
						}
					} else {
						deltaMove = this.size;
					}
				} else if (direction = 'handler') {
					deltaMove = this.size * (currentIndexOld - this.currentIndex);
				}

				if (this.mode == 'horizontal') {
					new Effect.Move(this.box, {
						x: deltaMove,
						y: 0,
						queue: {
							position: 'end',
							limit: this.walkLimit,
							scope: 'ticker'
						},
						afterFinish: this.stopOnLastItem ? null : this.afterUpdate.bind(this, direction)
					});
				} else if (this.mode == 'vertical') {
					new Effect.Move(this.box, {
						x: 0,
						y: deltaMove,
						queue: {
							position: 'end',
							limit: this.walkLimit,
							scope: 'ticker'
						},
						afterFinish: this.stopOnLastItem ? null : this.afterUpdate.bind(this, direction)
					});
				}

				if (this.onWalk) {
					this.onWalk.bind(this);
					this.onWalk(this.currentIndex, this.items.length, direction);
				}

			}

			if (manual && this.autoPlay) {				
				var ctx = new Array();
				ctx[0] = this.interval;
				ctx[1] = 'next';
				ctx[2] = true;
				this.play(ctx);
			}

		}
	}

};
