/**
 * @fileOverview Tabs, tab switchers and tab switcher collections now stored here.
 */

/**
 * @namespace Tabs handling classes
 */
myDeco.tabs = {}

/**
 * Creates a new Tab
 *
 * @param {Element} element DOM tab element
 * @param {Function} preActivateCallback This function will be called
 * before tab is activated
 * @constructor
 * @class Single tab class
 */
myDeco.tabs.Tab = function(element, preActivateCallback) {
	/**
	 * Tab's DOM element
	 * @type Element
	 * @private
	 */
	this._dom = element;
	/**
	 * Tab's link DOM element
	 * @type Element
	 * @private
	 */
	this._link = element.down('.cmslink');
	/**
	 * Tab's container DOM element
	 * @type Element
	 * @private
	 */
	this._container = $(element.id+'-container');
	/**
	 * Is tab active?
	 * @type Boolean
	 */
	this.isActive = element.hasClassName('active');
	/**
	 * Id of parent switcher dom element (used for effect queues)
	 * @type String
	 */
	this._switcherId = '';
	/**
	 * prev Prev Tab in the list
	 * @type Tab
	 */
	this.prev = null;
	/**
	 * next Next Tab in the list
	 * @type Tab
	 */
	this.next = null;
	/**
	 * Pre activation callback
	 * @type Function
	 * @private
	 */
	this._preActivateCallback = preActivateCallback;
}

myDeco.tabs.Tab.prototype = {
	/**
	 * Activates tab
	 *
	 * @param {Boolean} useEffects Do we need to use effects?
	 */
	activate : function(useEffects) {
		if (this.isActive) {
			return;
		}
    
		this._dom.addClassName('active');
		if (!useEffects) {
			this._container.show();
		} else {
			new Effect.Appear(this._container, {
				duration: 0.4,
				queue: { scope: this._switcherId, position: 'end'}
			});
		}

		this.isActive = true;
	},

	/**
	 * Deactivate tab
	 *
	 * @param {Boolean} useEffects Do we need to use effects?
	 */
	deactivate: function(useEffects) {
		if (!this.isActive) {
			return;
		}

		this._dom.removeClassName('active');
		if (!useEffects) {
			this._container.hide();
		} else {
			Effect.Queues.get(this._switcherId).each(function(effect) { effect.cancel(); });
			
			new Effect.Fade(this._container, {duration: 0.1,
				queue: { scope: this._switcherId }
			});
		}

		this.isActive = false;
	},

	/**
	 * Get tab id. Will return random id if none found.
	 *
	 * @returns {String} Tag identifier
	 */
	getId: function() {
		return this._dom.identify();
	},

	/**
	 * Attaches event handlers to the tag element
	 *
	 * @param {Integer} interval Interval id if any
	 * @param {Boolean} useEffects Do we need to use effects?
	 * @param {Function[]} callbacks Callbacks list
	 */
	attachHandlers: function(interval, useEffects, callbacks) {
		this._link.observe('click', function(e) {
			e.stop();
			// Don't run the machinery if tab is already active.
			if (this.isActive) {
				return;
			}

			if (interval) {
				window.clearInterval(interval);
			}
			// Call pre activation callback
			this._preActivateCallback(this);
			this.activate(useEffects);
			// Fire all callbacks
			for (var i=0; i < callbacks.length; i++) {
				callbacks[i](this);
			}
		}.bind(this));

		if (interval) {
			this._container.observe('mouseover', function(e) {
				window.clearInterval(interval);
			});
		}
	},
	/**
	 * Sets tab container content
	 *
	 * @param {String} content HTML content
	 */
	setContent: function(content) {
		this._container.innerHTML = content;
	},
	/**
	 * Does tab's container have content?
	 *
	 * @returns {Boolean} True if has content, false otherwise
	 */
	hasContent: function() {
		return !this._container.innerHTML.blank();
	},
	/**
	 * Get link element object
	 *
	 * @returns {Element} Tab link element
	 */
	getLink: function() {
		return this._link;
	},
	/**
	 * Get tab container element object
	 *
	 * @returns {Element} Tab container element
	 */
	getContainer: function() {
		return this._container;
	}
}

/**
 * Create TabSwitcher object
 *
 * @param {Element} element TabSwitcher DOM element
 * @param {Object} options Dictionary of options
 * @param {Boolean} options.use_effects do we use effects?
 * @param {Integer} options.period switch period (used if 'auto_switch' is true)
 * @param {Boolean} options.endless is switching looped (used if 'auto_switch' is true)
 * @param {Boolean} options.auto_switch do we use auto switching?
 * @constructor
 * @class TabSwitcher class that operates collection of tabs
 */
myDeco.tabs.TabSwitcher = function(element, options) {
	var self = this;
	/**
	 * Dictionary of options
	 * @type Object
	 * @private
	 */
	this._options = {
		'use_effects': true,
		'period': 7000,
		'endless': false,
		'auto_switch': true
	};
	this._options = Object.extend(this._options, options);
	/**
	 * DOM element
	 * @type Element
	 * @private
	 */
	this._dom = element;
	/**
	 * Tab First Tab in the list
	 * @type Tab 
	 * @private
	*/
	this._firstTab = null;
	/**
	 * Reference to the active Tab
	 * @type Tab
	 */
	this.activeTab = null; 

	/**
	 * _navigationLinks Collection of navigation links
	 * @type Array
	 */
	this._navigationLinks = null; 

	/**
	 * _interval Interval ID
	 * @type Integer
	 */
	this._interval = null;
	if (this._options['auto_switch']) {
		this._interval = window.setInterval(this.activateNext.bind(this), this._options['period']);
	}
	
	this._navigationLinks =  this._dom.select('.tabs-navigation');

	this._navigationLinks.invoke('observe', 'click', function(e) {
		var el = Event.findElement(e, '.tabs-navigation');
		Event.stop(e);
		
		self._navigationLinks.invoke('removeClassName', 'disabled');
		
		var disable = !(el.hasClassName('prev-link') ? self.activatePrev() : self.activateNext())
		
		if (disable)
			el.addClassName('disabled');
	});

	/**
	 * List of after activate callbacks
	 * @type Function[]
	 * @private
	 */
	this._callbacks = [];
	var prevTab = null;

	// Init all tabs
	this._dom.select('.tab:not(.inactive)')._each(function(el) {
		var tab = new myDeco.tabs.Tab(el, function(tab) {
			// Pre activation callback
			// Deactivates current active tab
			// and updates the reference
			self.activeTab.deactivate(self._options['use_effects']);
			self.activeTab = tab;
		});

		tab.attachHandlers(self._interval, self._options['use_effects'], self._callbacks);
		tab._switcherId = self.getId();
		
		if (tab.isActive)
			self.activeTab = tab;

		tab.prev = prevTab;

		if (prevTab)
			prevTab.next = tab;

		prevTab = tab;

		if (!self._firstTab)
		  	self._firstTab = tab;
	});
}

myDeco.tabs.TabSwitcher.prototype = {
	/**
	 * Activate next tab in the list
	 */
	activateNext: function() {
		if (!this._firstTab)
			return false;

		var doActivate = true;
		var currentTab = this.activeTab;
		if (!currentTab.next) {
			// Do not loop if endless == false
			if (!this._options['endless']) {
				doActivate = false;
				window.clearInterval(this._interval);
			} else {
				// Make first active if looping is needed
				currentTab = this._firstTab;
			}
		} else {
			// Switch to the next tab
			currentTab = this.activeTab.next;
		}

		if (doActivate) {
			// First deactivate current active tab
			this.activeTab.deactivate(this._options['use_effects']);
			currentTab.activate(this._options['use_effects']);
			this.activeTab = currentTab;
		}

		return doActivate && currentTab.next;
	},

	/**
	 * Activate prev tab in the list
	 */
	activatePrev: function() {
		if (!this._firstTab)
			return false;

		var doActivate = true;
		var currentTab = this.activeTab;
		if (!currentTab.prev) {
			doActivate = false;
			window.clearInterval(this._interval);
		} else {
			// Switch to the next tab
			currentTab = this.activeTab.prev;
		}

		if (doActivate) {
			// First deactivate current active tab
			this.activeTab.deactivate(this._options['use_effects']);
			currentTab.activate(this._options['use_effects']);
			this.activeTab = currentTab;
		}

		return doActivate && currentTab.prev;
	},

	/**
	 * Get TabSwitcher DOM element id
	 *
	 * @returns {String} DOM element id, random if none
	 */
	getId: function() {
		return this._dom.identify();
	},

	/**
	 * Get Tab object by its DOM id
	 *
	 * @param {String} id DOM id
	 * @returns {Tab} Tab object, null if not found
	 */
	getTabById: function(id) {
		var curTab = this._firstTab;
		while (curTab) {
			if (curTab.getId() == id) {
				return curTab;
		  	}
			curTab = curTab.next;
		}

		return null;
	},

	/**
	 * Switch to tab by its DOM id
	 *
	 * @param {String} id DOM id
	 */
	switchTabById: function(id) {
		var tab = this.getTabById(id);
		if (!tab || id == this.activeTab.getId()) {
			return;
		}

		this.activeTab.deactivate(this._options['use_effects']);
		tab.activate(this._options['use_effects']);
		this.activeTab = tab;
	},

	/**
	 * Adds callback for tags after activation action
	 *
	 * @param {Function} callback Callback function,
	 * callback must define one argument - current Tab object:
	 * function(tab) {
	 *   alert(tab.getId());
	 * }
	 */
	addCallback: function(callback) {
		if (callback instanceof Function) {
			this._callbacks.push(callback);
		}
	}
}

/**
* @namespace Collection of tab switchers and functions to operate it
*/
myDeco.tabs.tabSwitcherCollection = {
	switchers: [], // Switchers list
	/**
	 * Initialize all TabSwitchers on the page
	 */
	init: function(e, force) {
		// Skip if tabs have been initialized already
		if (myDeco.tabs.tabSwitcherCollection.switchers.length && !force) {
			return;
		}
		$$('.tab-switcher')._each(function(switcher) {
			var options = {
				'use_effects': !switcher.hasClassName('noeffect'),
				'endless': switcher.hasClassName('endless'),
				'auto_switch': !switcher.hasClassName('no-auto-switch')
			};
			myDeco.tabs.tabSwitcherCollection.switchers.push(new myDeco.tabs.TabSwitcher(switcher, options));
		});
	},

	/**
	 * Get TabSwitcher object by its DOM id
	 *
	 * @param {String} id DOM id
	 * @returns {TabSwitcher} TabSwitcher object
	 */
	getSwitcherById: function(id) {
		// Load switchers if they haven't been already loaded
		if (!myDeco.tabs.tabSwitcherCollection.switchers.length) {
			myDeco.tabs.tabSwitcherCollection.init();
		}
		return myDeco.tabs.tabSwitcherCollection.switchers.find(function(switcher) {
			return switcher.getId() == id;
		});
	}
}

addLoadEvent(myDeco.tabs.tabSwitcherCollection.init);
