/*
Script: SlideTab.js
	Contains the SlideTab Class.

License:
	MIT-style license.

Copyright:
	copyright (c) Klaas Moerman, <http://www.klaasmoerman.be>
*/

/*
Class: SlideTab
	A Mootools extension Class to make horizontal sliding tabs (independant of the window's size). Inherits options and events from the Mootools Framework Class Fx.Base (see <http://docs.mootools.net/Effects/Fx-Base.js#Fx.Base>).

Arguments:
	Element container -  The id of the main element, or the elements itself, containing at least all the tabs.
	Array/String/Element tabs - A single element or id or an array of id's or elements representing the (sliding) tab elements.
	Array/String/Element handles - A single element or id or an array of id's or elements, representing the handles for each tab (duplicates allowed).
	Object options - Optional, see Options below.

Options:
	All of the Fx.Base options and events (see <http://docs.mootools.net/Effects/Fx-Base.js#Fx.Base>) plus:

	Array state - The default state of each individual tab (0: closed, 1: open), all 0 by default.
	boolean cache - Store the state of the tabs during an entire browser session or not (using Cookies). This overrides the default settings when the page reloads. True by default.

Example:
	> var mySlideTab = new SlideTab('container', ['tab1','tab2','tab3'], $$('.handle'), {state: [1,0,0]})
	
	Creates a new SlideTab istance with three tabs and 2 handles. Handle 1 controls both tab 1 and 2. Tab 1 is open by default. The states of the tabs are stored during this session.
*/

var SlideTab = new Class({
	
	options: {
            state: false,
		cache: true
	},
	
	initialize: function(container, tabs, handles, options) {
		this.container = $(container);
		this.tab = this.$$(tabs);
		this.handle = this.$$(handles);
		this.setOptions(options);
				
		this.interaction = [];
		this.handle.each(function(el, i) {
			var first = this.handle.indexOf(el);
			if (first == i) this.interaction[first] = [];
			this.interaction[first].push(i);
			this.interaction[i] = this.interaction[first];
			if (first == i) el.addEvent('click', this.toggle.bind(this, first));
		}, this);
		
		this.wrapper = [];
		this.num = 0;
		this.tab.each(function(el, i) {
			this.num++;
			if (window.ie) this.wrapper[i] = new Element('div', {'styles': $extend(el.getStyles('margin'), {'overflow': 'hidden', 'float': 'left'})}).injectAfter(el).adopt(el);
			else this.wrapper[i] = new Element('div', {'styles': $extend(el.getStyles('margin', 'float'), {'overflow': 'hidden'})}).injectAfter(el).adopt(el);
			el.setStyles({'margin': 0, 'padding': 0});
		}, this);

		this.state = [];
		for(i = 0; i < this.num; i++) this.state[i] = 0;
		if (this.options.state) this.state = this.options.state;
		if (this.options.cache) {
			if (Cookie.get('slideTabsState')) this.state = Json.evaluate(Cookie.get('slideTabsState'));
			Cookie.set('slideTabsState', Json.toString(this.state));
		}
		
		this.fx = new Fx.Elements([this.container].extend(this.wrapper), $extend(this.options, {onStart: Class.empty, onComplete: Class.empty}));
		
		this.wrapper.each(function(el, i) {
			el.setStyle('width', this.state[i] * this.wrapper[i].getSize().size.x);
		}, this);
		
		if (this.options.cache && Cookie.get('slideTabsWidth')) this.container.setStyle('width', Cookie.get('slideTabsWidth').toInt());
		this.width = this.container.getStyle('width').toInt();
		
		this.current = {
			tab: this.state.indexOf(1),
			handle: -1
		};
		
	},

	$$: function(elms) {
		var elements = [];
		if ($type(elms) != 'array') elms = [elms];
		elms.each(function(item) {
			elements.push($(item));
		});
		return elements;
	},
	
	size: function(x) {
		return this.tab[x].getSize().size.x.toInt();
	},
	
	compute: function(x) {
		this.state[x] = 1 - this.state[x];
		if (this.state[x] == 1 && this.current.tab == -1) this.current.tab = x;
		this.width += (2*this.state[x] - 1) * this.size(x);
		return this.state[x] * this.size(x);
	},
	
	start: function(to) {
		to[0] = {width: this.width};
		this.fireEvent('onStart', this);
		this.fx.start(to).chain(this.stop.bind(this));
		return this;
	},
	
	stop: function() {
		this.busy = false;
		if (this.options.cache) {
			Cookie.set('slideTabsState', Json.toString(this.state));
			Cookie.set('slideTabsWidth', this.width);
		}
		this.fireEvent('onComplete', this);
		this.callChain();
	},

	/*
	Method: toggle
		Opens and closes appropriate tabs controlled by handle x.
	
	Arguments:
		int x - The number of the handle.
	
	Example:
		> new SlideTab('container', ['tab1','tab2','tab3'],['handle1','handle1','handle3'], {state: [1,0,0]}).toggle(0) // Same as clicking on the first handle. Closes tab 1 and opens tab 2.
	*/
	
	toggle: function(x) {
		this.current.tab = -1;
		if (!this.busy) {
			to = {};
			this.interaction[x].each(function(value) {
				to[value + 1] = {width: this.compute(value)};
			}, this);
			return this.start(to);
		}
		return this;
	},

	/*
	Property: getCurrent
		Returns the numbers of the currently active handle and tab.
	
	Returns:
		An Object with the numbers of the active handle and tab.

	Example:
		>new SlideTab('container', ['tab1','tab2','tab3'],['handle1','handle1','handle3'], {state: [1,0,0]}).toggle(2).getCurrent();
	
	Returns:
		(start code)
		{
			'handle': 2,
			'tab': 0
		}
		(end)
	*/

	getCurrent: function() {
		if (this.current.tab == -1) this.current.tab = this.state.indexOf(1);
		var i = 0;
		while (i < this.num && !this.interaction[i].contains(this.current.tab)) {
			i++;
		}
		this.current.handle = (i < this.num) ? i : -1;
		return this.current;
	},

	/*
	Property: set
		Open or close custom tabs.

	Arguments:
		Array/int tabs - The numbers or just one number of the tab(s) to open/close.
		Array/int states - The states for all tabs or  an array with the states for each individual tab (1: open, 0: close).

	Example:
		> new SlideTab('container', ['tab1','tab2','tab3'],['handle1','handle2','handle3'], {state: [1,0,0]}).set([0,2],[0,1]) // Closes the first tab and opens the third.
		> new SlideTab('container', ['tab1','tab2','tab3'],['handle1','handle2','handle3'], {state: [1,0,0]}).set([0,1,2],1) // Opens all the tabs.
	*/

	set: function(tabs, states) {
		this.current.tab = -1;
		to = {};
		if ($type(tabs) == "number") tabs = [tabs];
		if ($type(states) == "number"){
			var state = states;
			states = [];
			tabs.each(function(tab, i) {
				states[i] = state;
			});
		}
		tabs.each(function(tab, i) {
			if (this.state[tab] != states[i]) to[tab + 1] = {width: this.compute(tab)};
		}, this);
		return this.start(to);
	},

	/*
	Property: close
		Close all the tabs.
	*/
	
	close: function() {1
		var tabs = [];
		for (var i = 0; i < this.num; i++) tabs[i] = i;
		return this.set(tabs, 0);
	},

	/*
	Property: open
		Open all the tabs.
	*/

	open: function() {
		var tabs = [];
		for (var i = 0; i < this.num; i++) tabs[i] = i;
		return this.set(tabs, 1);
	}

});

SlideTab.implement(new Chain, new Events, new Options);

/*
Class: Element
	Custom class to allow all of its methods to be used with any DOM element via the dollar function <http://docs.mootools.net/Native/Element.js#$>. See Mootools' Element Class <http://docs.mootools.net/Native/Element.js>.
*/

Element.extend({
	
	/*
	Property: slideTab
		Applies a <SlideTab> to the Element and sets the Element as the container; This is a shortcut for <SlideTab>.

	Arguments:
		Array/String/Element tabs - A single element or id or an array of id's or elements representing the (sliding) tab elements.
		Array/String/Element handles - A single element or id or an array of id's or elements, representing the handles for each tab (duplicates allowed).
		Object options - Optional, see Options below.

	Options:
		All of the Fx.Base options and events (see <http://docs.mootools.net/Effects/Fx-Base.js#Fx.Base>) plus:

		Array state - The default state of each individual tab (0: closed, 1: open), all 0 by default.
		boolean cache - Store the state of the tabs during an entire browser session or not (using Cookies). This overrides the default settings when the page reloads. True by default.

	Example:
		>var mySlideTab = $('container').slideTab(['tab1', 'tab2', 'tab3'], ['handle1', 'handle2', 'handle3'], {cache: true});
		>//OR
		>var mySlideTab = new SlideTab('container', ['tab1', 'tab2', 'tab3'], ['handle1', 'handle2', 'handle3'], {cache: true});
	*/
	
	slideTab: function(tabs, handles, options) {
		return new SlideTab(this, tabs, handles, options);
	}

});