/**
 * @class Tabs
 * @namespace INTRIGO
 * @requires INTRIGO
 * @param {DOM|String} container: where your tabs will be outputed
 */
INTRIGO.Tabs = function(container) {
	if (typeof(container) == 'string')
		this._mainDiv = document.getElementById(container);
	else this._mainDiv = container;
	
	this._tabs = [];
	
	this.create();
	
	return this;
}
INTRIGO.Tabs.prototype = {
	_mainDiv: null,
	_tabsDiv: null,
	_newTabDiv: null,
	_contentDiv: null,

	_tabs: null,
	_newTab: null,
	
	/**
	 * adds a tab to the container and the array of tabs
	 * @param {String} label: the name that shows on the label
	 * @param {String|Object} content: this can either be a string or a DOM Object
	 * @param {Object} data: anything you want to attach to the tab
	 * @return {Tab}
	 */
	addTab: function(label, content, data) {
		var data = {
			label:label,
			content:content,
			data:data,
			contentPlaceholder:this._contentDiv,
			tabsRef:this
		}
		var tab = new INTRIGO.Tab(data);
		this._tabs[this._tabs.length] = tab;
		this._tabsDiv.appendChild(tab.getContainer());
		return tab;
	},
	
	/**
	 * stationary tab always located on the right of the tab list
	 * this tab isn't stored in the tabs array
	 * @param {Object} defaultTabName
	 * @param {Object} selectFunc
	 */
	addEndTab: function(label, content, data) {
		var tab = this.addTab(label, content, data);
		
		this._endTabDiv.appendChild(tab.getContainer());
		this._endTab = tab;
		
		return tab;
	},
	
	/**
	 * sets the content container where the tab's content gets added
	 * @param {Object|String} container: either an id or a DOM element
	 */
	setContentContainer: function(container) {
		if (typeof(container) == 'string') {
			container = document.getElementById(container);
		}
		this._contentDiv = container;
	},

	/**
	 * removes a tab from the container and the array of tabs
	 * @param {Tab} tab
	 * @param {Boolean} callFromTabObj: true if called from the Tab object else false
	 */
	removeTab: function(tab, callFromTabObj) {
		var tmp = [];
		var j = 0;
		for (var i = 0; i < this._tabs.length; i++) {
			if (this._tabs[i] != tab) {
				tmp[j] = this._tabs[i];
				j++;
			}
			else {
				// if callFromTabObj is true, tag was already removed.
				if (!callFromTabObj) {
					tab.remove();
				}
				// if tab you're trying to remove is selected
				if (tab.isSelected()) {
					// try selecting next tab
					if (this._tabs[i + 1])
						this._tabs[i + 1].select();
					// otherwise select previous 
					else if (this._tabs[i - 1])
						this._tabs[i - 1].select();
				}
			}
		}
		this._tabs = tmp;
	},
	
	/**
	 * deselects all tags but the one passed
	 * as soon as a selected tag is found, loop stops (only one tag can be selected at a time)
	 * @param {Tab} tab
	 */
	deselectAllBut: function(tab) {
		if (this._endTab && tab != this._endTab)
			this._endTab.deselect();
		for (var i = 0; i < this._tabs.length; i++) {
			if (this._tabs[i] != tab && this._tabs[i].isSelected()) {
				this._tabs[i].deselect();
				return;
			}
		}
	},
	
	/**
	 * @return {Array}: returns an array of all the displayed tabs
	 */
	getTabs: function() {
		return this._tabs;
	},
	
	// creating elements
	create: function(){
		var tabsDiv = document.createElement('div');
		var borderDiv = document.createElement('div');
		var endTabDiv = document.createElement('div');
		var contentDiv = document.createElement('div');
		
		INTRIGO.addClassName(this._mainDiv, 'tabContainer');
		
		tabsDiv.className = 'tabs';
		endTabDiv.className = 'endTab';
		borderDiv.className = 'border';
		
		contentDiv.className = 'contentContainer';
		
		this._tabsDiv = tabsDiv;
		this._endTabDiv = endTabDiv;
		this._contentDiv = contentDiv;
		this._mainDiv.appendChild(tabsDiv);
		this._mainDiv.appendChild(endTabDiv);
		this._mainDiv.appendChild(borderDiv);
		this._mainDiv.appendChild(contentDiv);
	}	
}
INTRIGO.Tab = function(data) {
	this._label = data.label;
	this._data = data.data;
	this._tabsRef = data.tabsRef;
	this._selected = false;
	this._removeEnabled = false;
	
	this.create();
	this.createContentDiv(data.content, data.contentPlaceholder);
}
INTRIGO.Tab.prototype = {
	//tab data
	_label: null,
	_data: null,
	_selected: null,
	_tabsRef: null,

	//tab html elements
	_tabMainDiv: null,
	_tabContentDiv: null,
	_tabLabelDiv: null,
	
	//content html element
	_contentDiv: null,
	
	//user Functions
	_onSelect: null,
	_onDeselect: null,
	_onRemove: null,
	_onRename: null,
	
	//status
	_removeEnabled: null,
	
	/**
	 * selects the tab and displays associated content
	 * calls tabs reference obj's deselectAllBut function
	 * calls custom select function if set
	 * @return {Tab}: returns instance of self
	 */
	select: function() {
		if (!this.isSelected()) {
			INTRIGO.addClassName(this._tabMainDiv, 'selected');
			this._selected = true;
			this.showContent();
			if (this._tabsRef)
				this._tabsRef.deselectAllBut(this);
			if (INTRIGO.isFunction(this._onSelect)) 
				this._onSelect(this._label, this._data);
		}
		return this;
	},
	
	/**
	 * deselects the tab and hides associated content
	 * calls custom deselect function if set
	 * @return {Boolean}: true for selected, fase for not
	 */
	deselect: function() {
		if (this.isSelected()) {
			INTRIGO.removeClassName(this._tabMainDiv, 'selected');
			this._selected = false;
			this.hideContent();
			if (INTRIGO.isFunction(this._onDeselect)) 
				this._onDeselect(this._label, this._data);
		}
		return this;
	},
	
	/**
	 * adds hover class to main div
	 */
	hover: function() {
		INTRIGO.addClassName(this._tabMainDiv, 'hover');
	},
	
	/**
	 * removes hover class from main div
	 */
	blur: function() {
		INTRIGO.removeClassName(this._tabMainDiv, 'hover');
	},
	 
	 /**
	  * renames the label to the corresponding "value"
	  * @param {String|Object} value: either a string or DOM element
	  * @return {Boolean}: true for selected, fase for not
	  * 
	  */
	rename: function(value) {
		if (typeof(value) == 'string') 
			this._tabLabelDiv.innerHTML = value;
		else {
			this._tabLabelDiv.innerHTML = '';
			this._tabLabelDiv.appendChild(value);
		}
		if (INTRIGO.isFunction(this._onRename))
			this._onRename(this._label, this._data);
			
		return this;
	},
	
	/**
	 * shows content associated with tab
	 * @return {Boolean}: true for selected, fase for not
	 */
	showContent: function() {
		this._contentDiv.style.display = 'block';
		return this;
	},
	
	/**
	 * hides content associated with tab
	 * @return {Boolean}: true for selected, fase for not
	 */
	hideContent: function() {
		this._contentDiv.style.display = 'none';
		return this;
	},

	/**
	 * removes the content div associated with tab
	 * @return {Boolean}: true for selected, fase for not
	 */
	removeContent: function() {
		this._contentDiv.parentNode.removeChild(this._contentDiv);
		return this;
	},
	
	/**
	 * removes tab and content div
	 * calls tabs reference obj's removeTab function
	 */
	remove: function() {
		this._tabMainDiv.parentNode.removeChild(this._tabMainDiv);
		this.removeContent();
		
		if (INTRIGO.isFunction(this._onRemove))
			this._onRemove(this._label, this._data);
		
		if (this._tabsRef)
			this._tabsRef.removeTab(this, true);
	},
	
	/**
	 * returns whether or not this tab is selected
	 * @return {Boolean}: true for selected, fase for not
	 */
	isSelected: function() {
		return this._selected;
	},
	
	/**
	 * user specific select function
	 * @param {Function} funcName
	 * @return {Tab}: returns instance of self
	 */
	setSelectFunc: function(funcName) {
		if (INTRIGO.isFunction(funcName))
			this._onSelect = funcName;
		else alert('setSelectFunc error: Argument is not a function.');
		return this;
	},
	
	/**
	 * user specific deselect function
	 * @param {Function} funcName
	 * @return {Tab}: returns instance of self
	 */
	setDeselectFunc: function(funcName) {
		if (INTRIGO.isFunction(funcName))
			this._onDeselect = funcName;
		else alert('setDeselectFunc error: Argument is not a function.');
		return this;
	},
	
	/**
	 * user specific remove function
	 * @param {Function} funcName
	 * @return {Tab}: returns instance of self
	 */
	setRemoveFunc: function(funcName) {
		if (INTRIGO.isFunction(funcName)) {
			this._onRemove = funcName;
			this.enableRemove();
		}
		else alert('setRemoveFunc error: Argument is not a function.');		
		return this;
	},

	/**
	 * user specific rename function
	 * @param {Function} funcName
	 * @return {Tab}: returns instance of self
	 */
	setRenameFunc: function(funcName) {
		if (INTRIGO.isFunction(funcName))
			this._onRename = funcName;
		else alert('setRenameFunc error: Argument is not a function.');		
		return this;
	},
	
	/**
	 * allows for a tab to be removed
	 * @return {Tab}: returns instance of self
	 */
	enableRemove: function() {
		if (!this._removeEnabled) {
			this.createRemoveDiv();
			this._removeEnabled = true;
		}
		return this;
	},	
	
	/**
	 * @return {Object}: returns the tab's DOM object
	 */
	getContainer: function() {
		return this._tabMainDiv;
	},
	
	/**
	 * @return {Object}: returns custom data set by user
	 */
	getData: function() {
		return this._data;
	},
	
	//creating elements
	create: function() {
		this.createMainDiv();
		this.createLabelDiv();
	},
	
	createMainDiv: function() {
		var mainDiv = document.createElement('div');
		var leftDiv = document.createElement('div');
		var contentDiv = document.createElement('div');
		var rightDiv = document.createElement('div');
		var self = this;

		mainDiv.className = 'tab';
		mainDiv.onmouseover = function() {
			self.hover();
		};
		mainDiv.onmouseout = function() {
			self.blur();
		};
		mainDiv.onclick = function() {
			self.select();
		};
		
		leftDiv.className = 'left';
		contentDiv.className = 'content';
		rightDiv.className = 'right';
		
		mainDiv.appendChild(leftDiv);
		mainDiv.appendChild(contentDiv);
		mainDiv.appendChild(rightDiv);
		
		this._tabMainDiv = mainDiv;
		this._tabContentDiv = contentDiv;
	},
	
	createLabelDiv: function() {
		var labelDiv = document.createElement('div');
		var self = this;

		labelDiv.className = 'name';
		if (typeof(this._label) == 'string')
			labelDiv.innerHTML = this._label;
		else labelDiv.appendChild(this._label);
		labelDiv.onclick = function() {
			self.select();
		}
		this._tabContentDiv.appendChild(labelDiv);
		
		this._tabLabelDiv = labelDiv;
	},
	
	createRemoveDiv: function() {
		var removeDiv = document.createElement('div');
		var removeLink = document.createElement('a');
		var self = this;
		
		removeLink.href = '#';
		removeLink.innerHTML = 'x';
		removeLink.title = 'Click here to close tab';
		
		removeLink.onclick = function(){
			self.remove();
			return false;
		};
		
		removeDiv.className = 'remove';
		removeDiv.appendChild(removeLink);
		
		this._tabContentDiv.appendChild(removeDiv);
	},
	
	createContentDiv: function(content, mainContentDiv){
		if (typeof(content) == 'object') {
			this._contentDiv = content;
		}
		else {
			this._contentDiv = document.createElement('div');
			if (content)
			this._contentDiv.innerHTML = content;
		}
		this._contentDiv.style.display = 'none';
		mainContentDiv.appendChild(this._contentDiv);
	}
}
