//
// Class Tab:
// o. A tab object used by TabControl
// o. Holds a tab information, a tab consists of a tab button and a tab body (which contains content)
//
Tab = function(buttonId, bodyId, selectedClassName, unselectedClassName) {
	this.TabId = buttonId; // tab unique id
	this.Button = document.getElementById(buttonId); // tab button (normally a div)
	this.BodyId = bodyId // tab body unique id
	this.Body = document.getElementById(bodyId); // tab body content (normally a div)
	this.SelectedCss = selectedClassName || "tab-selected"; // tab selected style class name
	this.UnselectedCss = unselectedClassName || "tab-unselected"; // tab unselected style class name
	this.IsCollapsed = Tab.DisplayMode.Collapse;	// tab display mode, by default hidden/collapse

	this.OnBeforeTabRollIn = null;
	this.BeforeTabRollIn = function(F, args) {
		this.OnBeforeTabRollIn = {"F": F, "args": args};
	}

	this.OnAfterTabRollIn = null;
	this.AfterTabRollIn = function(F, args) {
		this.OnAfterTabRollIn = {"F": F, "args": args};
	}

	this.OnBeforeTabRollOut = null;
	this.BeforeTabRollOut = function(F, args) {
		this.OnBeforeTabRollOut = {"F": F, "args": args};
	}

	this.OnAfterTabRollOut = null;
	this.AfterTabRollOut = function(F, args) {
		this.OnAfterTabRollOut = {"F": F, "args": args};
	}

	this.OnTabClick = null; // tab click callback info
	this.TabClick = function(F, args) {
		this.OnTabClick = {"F": F, "args": args};
	}
	
	this.Dispose = function() {
		this.Button = null;
		this.Body = null;
	}
}

Tab.DisplayMode = {
	Expand:0,
	Collapse:1
}


//
// Class TabClickedEventArgs:
// o. Event arguments object being passed on when the TabClick event is executed
//
TabClickEventArgs = function() {this.initialize.apply(this,arguments);}
TabClickEventArgs.prototype = {
	initialize: function(source, params) {
		this.ClickedTab = source;
		this.Params = params;
	}
}


//
// Class TabControl:
// o. A tab manager class that handles switching of content blocks registered to it
//
// Example:
// <script>
// var tc = new TabControl("TabCtrl0");
// var tab0 = new Tab("tab_allord", "tabC_allord");
// tab0.TabClick(F);
// tc.RegisterTab(tab0);
//
// var tab1 = new Tab("tab_au", "tabC_au", "tab-sel", "tab-unsel");
// tc.RegisterTab(tab1);
//
// var tab2 = new Tab("tab_market", "tabC_market");
// tc.RegisterTab(tab2);
// tab2.TabClick(RenderWeather);
//
// var tab3 = "123";
// tc.RegisterTab(tab3);
//
// tc.SetDefaultTab(tab2);
//
// function F(eventArgs) {
// 	alert(eventArgs.ClickedTab.TabId);
// }
//
// function RenderWeather(e) {
// 	var tab = e.ClickedTab;
// 	if(tab && tab.IsCollapsed) {
// 		var req = new Ajax.Request();
// 		req.Url = "/tab.xml";
// 		req.CacheInterval = 5000;
// 		req.OnRequestComplete = function(e) {
// 			if(e.Xml) {
// 				var container = tab.Body;
// 				while(container.childNodes.length > 0) container.removeChild(container.lastChild);
// 				var data = e.Xml.getElementsByTagName("value");
// 				if(data == null) return;
// 				container.appendChild(document.createTextNode(data[0].childNodes[0].nodeValue));
// 			}
// 		};
//		
// 		Ajax.Send(req);
// 	}	
// }
// </script>
//
TabControl = function(id) {

	// [variable] unique identifier for the tab controller
	var id = id;

	// [variable] if set to true, the content of a clicked tab will be automatically closed if it is already opened.
	var autoHide = true;

	// [property] tabs collection
	var tabs = [];

	// [variable] the tab that was last opened
	var lastTab = null;

	// [variable] optional single container for tab body, which when specified
	var container = null;

	// [variable] dimension of the container in pixel
	//var _w = 980, _h = 172;

	// [variable] flag to disable/enable animation
	var animate = 0;

	// [variable] animation mode
	var animation = TabControl.Animation.AnimateAll;

	// [variable] animation acceleration function
	var accelerationFunction = Animation.AccelerationFunctions.CrazyElevator14;

	// [variable] flag to determine whether the tab is rolling
	var isRolling = 0;


	//
	// EnableAutoHide:
	// Enable auto hide mode
	//
	this.EnableAutoHide = function() {
		autoHide = true;
	}


	//
	// DisableAutoHide:
	// Disable auto hide mode, which is on by default
	//
	this.DisableAutoHide = function() {
		autoHide = false;
	}


	//
	// EnableAnimation:
	// Enable roll animation when showing tab content
	//
	this.EnableAnimation = function(a) {
		animation = a;
		animate = 1;
	}


	//
	// DisableAnimation:
	// Enable roll animation when showing tab content
	//
	this.DisableAnimation = function() {
		animate = 0;
	}


	//
	// SetAccelerationFunction:
	// Set the acceleration function for the animation
	//
	this.SetAccelerationFunction = function(F) {
		if(F instanceof Animation.AccelerationFunction) accelerationFunction = F;
	};


	//
	// RegisterContainer:
	// - Use this function to register a single container where tab body will be rendered.
	// - When a container is registered, the body content of a clicked tab will be copied into the container and shown
	//
	this.RegisterContainer = function(c) {
		var e = document.getElementById(c);
		if(e) container = e;
	}


	//
	// RegisterTab():
	// Add a tab to the tab controller
	//
	this.RegisterTab = function(tab) {
		if(!(tab instanceof Tab)) return;

		// add a new tab instance to the tab collection
		tabs[tab.TabId] = tab;
		
		// add the onclick event to this tab button
		Events.AddEventListener(tab.Button, 'click', this.ToggleTab.BindWithEvent(false, this, tab));
	}


	//
	// SetDefaultTab():
	// Set the default selected tab
	//
	this.SetDefaultTab = function(tab) {
		if(!(tab instanceof Tab)) return;

		if(tab) this.ToggleTab(tab);
	}


	//
	// ToggleTab():
	// Toggle a selected tab to show the tab content, and an unselected tab to hide the tab content
	//
	this.ToggleTab = function(tab) {
		if(!(tab instanceof Tab)) return;

		// makes sure tab button is a valid html object
		var button = tab.Button;

		// do simple content switch when different tabs are clicked
		if(button && !animate) {
			// do expand/collapse when the newly chosen tab isn't the same as the tab before
			if(tab != lastTab) {
				if(lastTab) SwitchStyle(lastTab, false);
				SwitchStyle(tab, true);
				lastTab = tab;
			}
			// do expand/collapse for the newly chosen is the same as the tab before only when auto hide mode is on
			else if(tab == lastTab && autoHide) {
				SwitchStyle(lastTab, false);
				lastTab = null;
			}
			
			if(tab.OnTabClick) {
				var del = tab.OnTabClick.F;
				var args = tab.OnTabClick.args;
				(del || function(){})(new TabClickEventArgs(tab, args));
			}
		}
		// do simple content switch when different tabs are clicked but with animation!
		else if(button && animate && !isRolling) {
			if(lastTab == null ||
				(tab != lastTab && animation == TabControl.Animation.AnimateAll)) {

				if(lastTab) {
					var b1 = lastTab.Body;
					if(container) b1 = container;
					var r1 = new Animation.Roller(b1, Animation.Roller.View.Expanded);
					r1.SetMinHeight(0);
					r1.SetAccelerationFunction(accelerationFunction);
					r1.OnBeforeRollIn = function() {
						if(tab.OnBeforeTabRollIn) (tab.OnBeforeTabRollIn.F || function(){})(new TabClickEventArgs(tab, tab.OnBeforeTabRollIn.args));
					}
					r1.OnAfterRollIn = function() {
						if(tab.OnAfterTabRollIn) (tab.OnAfterTabRollIn.F || function(){})(new TabClickEventArgs(tab, tab.OnAfterTabRollIn.args));
						HideElement(b1);
						isRolling = 0;
					}
					r1.RollIn(Animation.Roller.RollDirection.BottomUp);

					lastTab.IsCollapsed = Tab.DisplayMode.Collapse;

					SwitchTabCss(lastTab);
				}

				var b2 = tab.Body;
				if(container) {
					var clone = b2.cloneNode(true);
					clone.style.display = "block";
					while(container.childNodes.length > 0) container.removeChild(container.lastChild);
					container.appendChild(clone);
					b2 = container;
				}

				var r2 = new Animation.Roller(b2, Animation.Roller.View.Collapsed);
				r2.SetMinHeight(0);
				r2.SetAccelerationFunction(accelerationFunction);
				r2.OnBeforeRollOut = function() {
					if(tab.OnBeforeTabRollOut)
						(tab.OnBeforeTabRollOut.F || function(){})(new TabClickEventArgs(tab, tab.OnBeforeTabRollOut.args));
				}
				r2.OnAfterRollOut = function() {
					if(tab.OnAfterTabRollOut)
						(tab.OnAfterTabRollOut.F || function(){})(new TabClickEventArgs(tab, tab.OnAfterTabRollOut.args));

					isRolling = 0;
				}
				r2.RollOut(Animation.Roller.RollDirection.TopDown);

				ShowElement(b2);

				tab.IsCollapsed = Tab.DisplayMode.Expand;

				SwitchTabCss(tab);

				lastTab = tab;
			}
			// - this is a special case when we don't animate even when animation is turned on (TabControl.Animation.AnimatePartial)
			// - since we don't animate, we need to set isRolling flag to false as soon as we are done switching the tab
			// - also, we'll have to break from this function, otherwise isRolling flag will be set to true again
			else if(tab != lastTab) {
				if(lastTab) SwitchStyle(lastTab, false);
				SwitchStyle(tab, true);

				if(tab.IsCollapsed) {
					if(tab.OnBeforeTabRollIn) (tab.OnBeforeTabRollIn.F || function(){})(new TabClickEventArgs(tab, tab.OnBeforeTabRollIn.args));
				}
				else {
					if(tab.OnBeforeTabRollOut) (tab.OnBeforeTabRollOut.F || function(){})(new TabClickEventArgs(tab, tab.OnBeforeTabRollOut.args));
				}
				
				if(tab.OnTabClick) {
					(tab.OnTabClick.F || function(){})(new TabClickEventArgs(tab,  tab.OnTabClick.args));
				}
				
				if(tab.IsCollapsed) {
					if(tab.OnAfterTabRollIn) (tab.OnAfterTabRollIn.F || function(){})(new TabClickEventArgs(tab, tab.OnAfterTabRollIn.args));
				}
				else {
					if(tab.OnAfterTabRollOut) (tab.OnAfterTabRollOut.F || function(){})(new TabClickEventArgs(tab, tab.OnAfterTabRollOut.args));
					tab.Body.style.marginTop = 0;
				}
				
				isRolling = 0;

				lastTab = tab;
	
				return; 
			}
			else if(tab == lastTab) {
				// does nothing when the hiding of a tab body is not enabled
				if(!autoHide) return;

				var b = tab.Body;
				if(container) b = container;
				var r = new Animation.Roller(b, Animation.Roller.View.Expanded);
				r.SetMinHeight(0);
				r.SetAccelerationFunction(accelerationFunction);
				r.OnBeforeRollIn = function() {
					if(tab.OnBeforeTabRollIn)
						(tab.OnBeforeTabRollIn.F || function(){})(new TabClickEventArgs(tab, tab.OnBeforeTabRollIn.args));
				}
				r.OnAfterRollIn = function() {
					if(tab.OnAfterTabRollIn)
						(tab.OnAfterTabRollIn.F || function(){})(new TabClickEventArgs(tab, tab.OnAfterTabRollIn.args));

					HideElement(b);
					isRolling = 0;
				}
				r.RollIn(Animation.Roller.RollDirection.BottomUp);

				tab.IsCollapsed = Tab.DisplayMode.Collapse;

				SwitchTabCss(tab);

				lastTab = null;
			}

			isRolling = 1;

			if(tab.OnTabClick) {
				var del = tab.OnTabClick.F;
				var args = tab.OnTabClick.args;
				(del || function(){})(new TabClickEventArgs(tab, args));
			}
		}
	}


	//
	// SwitchStyle():
	// Switch to a particular tab style
	//
	function SwitchStyle(tab, isSelected) {
		// get a reference to the tab button and update the style
		var clickedTab = tab.Button;

		// let's switch the tab style when the tab button and its styles are defined

		// switch display on/off for tab body
		var tabBody = tab.Body;
		if(tabBody && isSelected) {
			var b = tabBody;
			if(container) {
				var clone = tabBody.cloneNode(true);
				clone.style.display = "block";
				while(container.childNodes.length > 0) container.removeChild(container.lastChild);
				container.appendChild(clone);
				b = container;
			}
			ShowElement(b);
			tab.IsCollapsed = Tab.DisplayMode.Expand;
		}
		else if(tabBody && !isSelected) {
			var b = tabBody;
			if(container) { b = container; }
			HideElement(b);
			tab.IsCollapsed = Tab.DisplayMode.Collapse;
		}

		SwitchTabCss(tab);
	}
	

	//
	// ShowElement():
	// Show a html element
	//
	function ShowElement(el) {
		if(el) {
			el.style.display = "block";
			el.style.visibility = "visible";
		}
	}


	//
	// HideElement():
	// Hide a html element
	//
	function HideElement(el) {
		if(el) {
			el.style.display = "none";
			el.style.visibility = "hidden";
		}
	}


	//
	// SwitchTabCss:
	// Switch between selected and unselected css class for tab depending on its IsCollapsed property
	//
	function SwitchTabCss(tab) {
		var classes = tab.Button.className.split(" ");
		var newClassName = "";
		tab.Button.className = "";
		for(var i=0; i<classes.length; i++) {
			if(classes[i] != tab.SelectedCss && classes[i] != tab.UnselectedCss) newClassName += classes[i];

			// add space if we have multiple definition of css classes
			if(i != classes.length-1) newClassName += " ";
		}

		// let's add the selected/unselected style define in the tab object if defined
		newClassName += (newClassName.length > 0? " " : "") + (!tab.IsCollapsed? tab.SelectedCss : tab.UnselectedCss);
		tab.Button.className = newClassName;
	}


	//
	// Dispose:
	// Garbage collection time!
	//
	this.Dispose =	function() {
		for(var tab in tabs) {
			tabs[tab].Dispose();
			tabs[tab] = null;
		}
		tabs = null;

		lastTab=null;

		container=null;
	}
}

TabControl.Animation = {
	AnimatePartial: 1,
	AnimateAll: 2
}