// 
//  panslider.delia.js
//  Pan Slider
//  
//  Created by Les Argonautes on 2010-07-29.
//  Copyright 2010 Les Argonautes. All rights reserved.
// 
/*
	@class
		(deliaPanSlider)
			@params
				[options]					->				Object of options
					[panWrapper]			->				Id of the [panWrapper] panel, which will be the scrolled area. Width & Height has to be fixed;
					[panContainer]			->				Id of the [panContainer] panel, which will be direct child of [panWrapper]
					[pansSelector]			->				The selector to get all "panels" to scroll to. (have to be in "float:left;" style, and fixed width).
					[direction]				->				(default: 'horizontal') "horizontal" or "vertical"
					[mode]					->				"loop" : if you want to allow to back to first from "next" controller when you are on last, and go on last when you are on first.
															"infiniteloop" : if you want to always scroll without rewind. Currently works only with a "scrollby" to "1"
				[controllers] have to be defined.
					[controllers]			->				Contains the [left] & [right] "id" of controllers, and [disabled] CSS class to apply on first & last when not in loop mode.
						[left]				->				Id of the [left] controller
						[right]				->				Id of the [right] controller
						[disabled]			->				Class to apply on [left] controller if we are on first, on [right] controller if we are on last. [mode] should not be set to "loop"
	@method
		(toNext)							->				Go to Next panel (or first if [mode] set to "loop")
		(toPrevious)						->				Go to Previous panel (or last if [mode] set to "loop")
		(toPan)								->				Go to defined panel (used by (toNext) and (toPrevious))
			@params
				[el]						->				"first"			->	go to first panel
															"last"			->	go to last panel
															"random"		->	go to a random panel
															id or element	->	id panel or panel element to go to
		(setStart)							->				Try to go directly to the panel without "scroll effect"
			@params
				[el]						->				"first"			->	go to first panel
															"last"			->	go to last panel
															"random"		->	go to a random panel
															id or element	->	id panel or panel element to go to
		(reset)								->				Reset the Pan Slider. (i.e: if you reload the content with ajax request, reset the pan slider to redefine the scroll area)
															
		protected(_setControllersStatus)	->				Set the controller status (disabled class or not) {can't be used out of the class}
*/


deliaPanSlider = new Class({
	Implements: [Options, Events],
	
	options:
	{
		panWrapper: 'panWrapper',
		panContainer: 'panContainer',
		pansSelector: '.pans',
		direction: 'horizontal',
		mode: null,
		scrollby: 1,
		controllers:
		{
			left: null,
			right: null,
			disabled: 'disabled'
		},
		offset: 0,
		// Events
		onBeforeInit: $empty,
		onInit: $empty,
		onFirst: function(position) { },
		onLast: function(position) { },
		onChange: function(position) { }
	},
	_panPosition:
	{
		current: 0,
		start:0,
		end:0,
		maxbyscroll:2,
		itemWidth: 0
	},
	_pans: null,
	_infiniteloop:
	{
		active: false,
		mode: 'double'
	},
	
	initialize: function(options)
	{
		// #Set options
		this.setOptions(options);
		
		this.fireEvent('beforeInit');

		// +Infinite Loop
		if(this.options.mode == 'infiniteloop')
		{
			this._infiniteloop.active = true;
		}
		
		// #Set temp vars
		var tmp_containerSize = 0;
		this._pans = $$(this.options.pansSelector);

		// #Set Container size from pans size
		if(this.options.direction == 'vertical')
		{
			this._pans.each(function(item, ind)
			{
				tmp_containerSize += item.getHeight() + item.getStyle('margin-top').toInt() + item.getStyle('margin-bottom').toInt();
				if(ind==0)
				{
					tmp_itemSize = item.getHeight() + item.getStyle('margin-top').toInt() + item.getStyle('margin-bottom').toInt() + item.getStyle('padding-top').toInt() + item.getStyle('padding-bottom').toInt();
				}
			}.bind(this));

			this._panPosition.itemSize = tmp_itemSize;
			tmp_containerSize = (tmp_itemSize * this._pans.length) + this.options.offset;

			$(this.options.panContainer).setStyle("height", tmp_containerSize + "px");

			this._panPosition.maxbyscroll = ($(this.options.panWrapper).getHeight() / tmp_itemSize).round(0);
		}
		else
		{
			this._pans.each(function(item, ind)
			{
				tmp_containerSize += item.getWidth() + item.getStyle('margin-left').toInt() + item.getStyle('margin-right').toInt();
				if(ind==0)
				{
					tmp_itemSize = item.getWidth() + item.getStyle('margin-left').toInt() + item.getStyle('margin-right').toInt() + item.getStyle('padding-left').toInt() + item.getStyle('padding-right').toInt();
				}
			}.bind(this));

			this._panPosition.itemSize = tmp_itemSize;
			tmp_containerSize = (tmp_itemSize * this._pans.length) + this.options.offset;
			$(this.options.panContainer).setStyle("width", tmp_containerSize + "px");

			this._panPosition.maxbyscroll = ($(this.options.panWrapper).getWidth() / tmp_itemSize).round(0);
		}

		if(this._infiniteloop.active)
		{
			this._panPosition.end = (this._pans.length - 1);
		}
		else if(this._pans.length > this._panPosition.maxbyscroll)
		{
	        this._panPosition.end = (this._pans.length - this._panPosition.maxbyscroll);
		}
		else
		{
			this._panPosition.end = this._panPosition.start;
		}
		
		// #Define Scroll
		this._scroll = new Fx.Scroll($(this.options.panWrapper), 
			{
				link: 'chain'
			});
		this._scroll.addEvents({
			'complete': function(e)
			{
				if(this._infiniteloop.active && ((this._infiniteloop.mode == 'simple' && this._panPosition.movePanPosition == 'top') || this._infiniteloop.mode == 'double'))
				{
					this._movePan();
				}
			}.bind(this)
		});
		
		// #Set Controllers "disabled" status
		if(this.options.direction == 'vertical')
		{
			this._setControllersStatus((tmp_containerSize <= $(this.options.panWrapper).getHeight()));
		}
		else
		{
			this._setControllersStatus((tmp_containerSize <= $(this.options.panWrapper).getWidth()));
		}
		
		// #Add controllers events
		if(this.options.controllers.left != null)
		{
			$(this.options.controllers.left).addEvent('click', function(e)
			{
				e.stop();
				if($(this.options.controllers.left).hasClass(this.options.controllers.disabled) == false)
				{
					this.toPrevious();
				}
			}.bind(this));
		}
		if(this.options.controllers.right != null)
		{
			$(this.options.controllers.right).addEvent('click', function(e)
			{
				e.stop();
				if($(this.options.controllers.right).hasClass(this.options.controllers.disabled) == false)
				{
					this.toNext();
				}
			}.bind(this));
		}

		// +Infinite Loop
		if(this._infiniteloop.active)
		{
			if(this._pans.length == (this._panPosition.maxbyscroll + 1))
			{
				this._infiniteloop.mode = 'simple';
			}
			else if(this._pans.length > (this._panPosition.maxbyscroll + 1))
			{
				this._infiniteloop.mode = 'double';
			}
			if(this._pans.length >= (this._panPosition.maxbyscroll))
			{
				this._pans.getLast().dispose().inject(this._pans[0], 'before');
			}
			this.setStart(this._pans[0]);
		}
		
			// +Fire the Event 'init'
			this.fireEvent('init');
	},
	
	toNext: function()
	{
		this._panPosition.movePanPosition = 'bottom';
		var tmp_nextPan = (this._panPosition.current + this.options.scrollby);

		if(this._panPosition.current == 0)
		{
			this._panPosition.movePan = this._panPosition.end;
		}
		else if(this._panPosition.current == this._panPosition.end)
		{
			this._panPosition.movePan = (this._panPosition.end - 1);
		}
		else
		{
			this._panPosition.movePan = (this._panPosition.current - 1);
		}
		
		if(this._infiniteloop.active && this._infiniteloop.mode == 'simple')
		{
			this._movePan();
			
			if(this._panPosition.end + 1 == 2)
			{
				this._scroll.set(0, 0);
			}
		}
		
		// #Go to next if we are not on last item
		if(tmp_nextPan <= this._panPosition.end)
		{
			this.toPan(this._pans[tmp_nextPan]);
		}
		else if(tmp_nextPan > this._panPosition.end && this._infiniteloop.active)
		{
			this.toPan(this._pans[this._panPosition.start]);
		}
		else if(tmp_nextPan > this._panPosition.end && this._panPosition.current != this._panPosition.end)
		{
			this.toPan(this._pans[this._panPosition.end]);
		}
		// #Go to first if we are on last item & loop mode is enabled
		else if((tmp_nextPan > this._panPosition.end) && (this.options.mode == 'loop' && !this._infiniteloop.active))
		{
			this.toPan(this._pans[this._panPosition.start]);
		}
	},
	
	toPrevious: function()
	{
		this._panPosition.movePanPosition = 'top';
		if(this._panPosition.current > this._panPosition.end)
		{
			var tmp_previousPan = this._panPosition.end;
		}
		else
		{
	        var tmp_previousPan = (this._panPosition.current - this.options.scrollby);
		}

		if(this._panPosition.current == this._panPosition.start)
		{
			this._panPosition.movePan = (this._panPosition.end - 1);
		}
		else if(this._panPosition.current == (this._panPosition.start + 1))
		{
			this._panPosition.movePan = this._panPosition.end;
		}
		else
		{
			this._panPosition.movePan = (this._panPosition.current - 2);
		}

		if(tmp_previousPan >= this._panPosition.start)
		{
			this.toPan(this._pans[tmp_previousPan]);
		}
		else if(tmp_previousPan < this._panPosition.start && this._infiniteloop.active)
		{
			this.toPan(this._pans[this._panPosition.end]);
		}
		else if(tmp_previousPan < this._panPosition.start && this._panPosition.current != this._panPosition.start)
		{
			this.toPan(this._pans[this._panPosition.start]);
		}
		else if((tmp_previousPan > this._panPosition.end || tmp_previousPan < 0) && (this.options.mode == 'loop' || this._infiniteloop.active))
		{
			this.toPan(this._pans[this._panPosition.end]);
		}
	},
	
	toPan: function(el)
	{		
		// #Define element from type of argument
		switch(el)
		{
			case 'first':
				var tmp_scrollTarget = this._pans[0];
			break;
			
			case 'last':
				var tmp_scrollTarget = this._pans[this._panPosition.end];
			break;
			
			case 'random':
				var tmp_scrollTarget = this._pans.getRandom();
			break;
			
			default:
				var tmp_scrollTarget = $(el);
			break;
		}

		// #Define current position
		this._panPosition.current = this._pans.indexOf(tmp_scrollTarget);
		
		// #Scroll to defined element
		this._scroll.cancel();
		this._scroll.toElement(tmp_scrollTarget);
		this.fireEvent('change', [this._panPosition.current]);
		
		// #Set Controllers "disabled" status
		this._setControllersStatus();
	},
	
	toCoord: function(x,y)
	{

		this._scroll.set(x,y);
	},
	
	setStart: function(el)
	{
		// #Define element from type of argument
		switch(el)
		{
			case 'first':
				var tmp_scrollTarget = this._pans[0];
			break;
			
			case 'last':
				var tmp_scrollTarget = this._pans.getLast();
			break;
			
			case 'random':
				var tmp_scrollTarget = this._pans.getRandom();
			break;
			
			default:
				var tmp_scrollTarget = $(el);
			break;
		}
		
		// #Get scroll position & scroll
		if(this.options.direction == 'horizontal' && tmp_scrollTarget.offsetLeft && !this._infiniteloop.active)
		{
			this._scroll.set(tmp_scrollTarget.offsetLeft, 0);
		}
		else if(this.options.direction == 'vertical' && tmp_scrollTarget.offsetTop && !this._infiniteloop.active)
		{
			this._scroll.set(0, tmp_scrollTarget.offsetTop);
		}
		else
		{
			this._scroll.set(tmp_scrollTarget.getWidth().toInt(), 0);
		}
		
		// #Define current position
		this._panPosition.current = this._pans.indexOf(tmp_scrollTarget);
		
		// #Set Controllers "disabled" status
		this._setControllersStatus();
	},
	
	_setControllersStatus: function(forceDisable)
	{
		// #Set only if not in "loop" mode and class defined for "disabled"
		if(forceDisable == false)
		{
			// #Remove existing class added
			$$('.' + this.options.controllers.disabled).removeClass(this.options.controllers.disabled);
		}
		if(((this.options.mode != 'loop' && !this._infiniteloop.active) || forceDisable == true || (this._panPosition.start == this._panPosition.end)) && (this.options.controllers.disabled != null))
		{
			// #Remove existing class added
			$$('.' + this.options.controllers.disabled).removeClass(this.options.controllers.disabled);
			
			// #Add it for "Left" controller
			if((this.options.controllers.left != null) && ((this._panPosition.current == this._panPosition.start) || (this._panPosition.current - this.options.scrollby < this._panPosition.start && this._panPosition.current == this._panPosition.start) || forceDisable === true))
			{
				$(this.options.controllers.left).addClass(this.options.controllers.disabled);
				this.fireEvent('first', [this._panPosition.current]);
			}
			
			// #Add it for "Right" controller
			if((this.options.controllers.right != null) && ((this._panPosition.current == this._panPosition.end) || (this._panPosition.current + this.options.scrollby > this._panPosition.end && this._panPosition.current == this._panPosition.end) || forceDisable === true || (this._panPosition.current+this._panPosition.maxbyscroll) > this._pans.length))
			{
				$(this.options.controllers.right).addClass(this.options.controllers.disabled);
				this.fireEvent('last', [this._panPosition.current]);
			}
		}
		else if((this.options.mode == 'loop') && (this.options.controllers.disabled != null))
		{
			if ((this._panPosition.current + this._panPosition.maxbyscroll) >= this._pans.length)
			{
				this._panPosition.current = this._panPosition.end;
			}
		}
	}.protect(),
	
	_movePan: function(movePan, position)
	{
		if(this._panPosition.movePan != null)
		{
			if(this._infiniteloop.active)
			{
				if(this._infiniteloop.mode == 'simple')
				{
					if(this._panPosition.movePanPosition == 'bottom')
					{
						this.toCoord(0, 0);
					}
				}
				var tmp_currentScrollPosition = $(this.options.panContainer).getScroll();
				this._pans[this._panPosition.movePan].dispose().inject(this.options.panContainer, this._panPosition.movePanPosition);
				if(this.options.direction == 'vertical')
				{
					if(this._panPosition.movePanPosition == 'top' && this._infiniteloop.mode == 'simple')
					{
						this.toCoord(0, this._scroll.from[1]);
					}
					else
					{
						this._scroll.set(0, (this._panPosition.itemSize.toInt()));
					}
					
				}
				else
				{
					this._scroll.set((this._panPosition.itemSize.toInt()),0);
				}
			}
		}
	},
	
	reset: function()
	{
		this.fireEvent('beforeInit');

		// #Set temp vars
		var tmp_containerSize = 0;
		this._pans = $$(this.options.pansSelector);

		// #Set Container size from pans size
		if(this.options.direction == 'vertical')
		{
			this._pans.each(function(item, ind)
			{
				tmp_containerSize += item.getHeight() + item.getStyle('margin-top').toInt() + item.getStyle('margin-bottom').toInt();
				if(ind==0)
				{
					tmp_itemSize = item.getHeight() + item.getStyle('margin-top').toInt() + item.getStyle('margin-bottom').toInt() + item.getStyle('padding-top').toInt() + item.getStyle('padding-bottom').toInt();
				}
			}.bind(this));

			this._panPosition.itemSize = tmp_itemSize;
			tmp_containerSize = (tmp_itemSize * this._pans.length) + this.options.offset;

			$(this.options.panContainer).setStyle("height", tmp_containerSize + "px");

			this._panPosition.maxbyscroll = ($(this.options.panWrapper).getHeight() / tmp_itemSize).round(0);
		}
		else
		{
			this._pans.each(function(item, ind)
			{
				tmp_containerSize += item.getWidth() + item.getStyle('margin-left').toInt() + item.getStyle('margin-right').toInt();
				if(ind==0)
				{
					tmp_itemSize = item.getWidth() + item.getStyle('margin-left').toInt() + item.getStyle('margin-right').toInt() + item.getStyle('padding-left').toInt() + item.getStyle('padding-right').toInt();
				}
			}.bind(this));

			this._panPosition.itemSize = tmp_itemSize;
			tmp_containerSize += this.options.offset;
			$(this.options.panContainer).setStyle("width", tmp_containerSize + "px");

			this._panPosition.maxbyscroll = ($(this.options.panWrapper).getWidth() / tmp_itemSize).round(0);
		}

		if(this._infiniteloop.active)
		{
			this._panPosition.end = (this._pans.length - 1);
		}
		else if(this._pans.length > this._panPosition.maxbyscroll)
		{
	        this._panPosition.end = (this._pans.length - this._panPosition.maxbyscroll);
		}
		else
		{
			this._panPosition.end = this._panPosition.start;
		}
		
		// #Set Controllers "disabled" status
		if(this.options.direction == 'vertical')
		{
			this._setControllersStatus((tmp_containerSize <= $(this.options.panWrapper).getHeight()));
		}
		else
		{
			this._setControllersStatus((tmp_containerSize <= $(this.options.panWrapper).getWidth()));
		}

		// +Infinite Loop
		if(this._infiniteloop.active)
		{
			if(this._pans.length == (this._panPosition.maxbyscroll + 1))
			{
				this._infiniteloop.mode = 'simple';
			}
			else if(this._pans.length > (this._panPosition.maxbyscroll + 1))
			{
				this._infiniteloop.mode = 'double';
			}
			if(this._pans.length >= (this._panPosition.maxbyscroll))
			{
				this._pans.getLast().dispose().inject(this._pans[0], 'before');
			}
			this.setStart(this._pans[0]);
		}
		
			// +Fire the Event 'init'
			this.fireEvent('init');
	},

	_debug: function (clear) {
		if(clear)
	        console.clear();
		console.log('start: '+this._panPosition.start);
		console.log('current: '+this._panPosition.current);
		console.log('end: '+this._panPosition.end);
		console.log('maxbyscroll: '+this._panPosition.maxbyscroll);
		console.log('end > maxbyscroll: '+(this._panPosition.end > this._panPosition.maxbyscroll));
		console.log('length: '+this._pans.length);
		console.log('(current+maxbyscroll) > length: '+((this._panPosition.current+this._panPosition.maxbyscroll) > this._pans.length));
		console.log('---');
		console.log('infiniteloop: ' + this._infiniteloop.active);
		console.log('infiniteloop.mode: ' + this._infiniteloop.mode);
		console.log('------------------------');
	}
});
