﻿/* Utils: a static class with various AJAX/UI related JavaScript functions */
var Utilities = Class.create();
Object.extend(Utilities.prototype,
{
	initialize: function()
	{
	},
	GetHash: function(elemLink)
	{
		var astrHref = elemLink.href.split("#");
		if (astrHref.length <= 1)
			return "";
		if (astrHref[1].substring(0, 1) == '_')
			return astrHref[1].substring(1);
		else
			return astrHref[1];
	},
	SetHash: function(elemLink, strHash)
	{
		var astrHref = elemLink.href.split("#");
		elemLink.href = astrHref[0] + "#" + '_' + strHash;
	},
	// adds our '_' prefix to hashes
	ProcessHash: function(elemLink)
	{
		if (Utils.IsLocalAnchor(elemLink))
			Utils.SetHash(elemLink, Utils.GetHash(elemLink));
	},
	GetTargetId: function(elemLink)
	{
		if (elemLink.getAttribute("targetId"))
			return elemLink.getAttribute("targetId");
		else
			return Utils.GetHash(elemLink);
	},
	// IsLocalAnchor: a link to an anchor on the current page
	IsLocalAnchor: function(elemLink)
	{
		// some browsers (Safari) just return "#all" for a local anchor href
		return elemLink.href.split("#")[0] == window.location.href.split("#")[0] || elemLink.href.split("#")[0] == "";
	},
	RemoveAll: function(elemSelect)
	{
		var nItems = elemSelect.options.length;
		for (var nItem = nItems - 1; nItem >= 0; --nItem)
			elemSelect.remove(nItem);
	},
	RemoteDataBind: function(strTargetUrl, strElemTargetId, strDataTextField, strDataValueField)
	{
		new Ajax.Request(strTargetUrl, { method: 'get', onSuccess: function(transport) { Utils.DataBind(eval(transport.responseText), strElemTargetId, strDataTextField, strDataValueField); } });
	},
	DataBind: function(aObjects, strElemTargetId, strDataTextField, strDataValueField)
	{
		// check if typeof aObjects is array
		var nObjects = aObjects.length;
		var elemTarget = $(strElemTargetId);
		for (var nObject = 0; nObject < nObjects; ++nObject)
		{
			var obj = aObjects[nObject];
			// TODO: find a cross-browser way to add an option to a select element (not as easy as it seems. The IE/FF .add() method signatures are incompatible and .appendChild() doesn't work in IE)
			try { 	elemTarget.add(new Option(obj[strDataTextField], obj[strDataValueField])); }
			catch (e) { elemTarget.add(new Option(obj[strDataTextField], obj[strDataValueField]), null); }
		}
	},
	// AJAX helper function, 
	LoadXMLDoc: function(strTargetUrl, elemDestination)
	{
		new Ajax.Updater(elemDestination.id, strTargetUrl, { method: 'get' });
		//new ajax(strTargetUrl, {postBody: 'arg1=5', update: elemDestination});
		//Utils.AjaxRequest(strTargetUrl, function(strResponse) { elemDestination.innerHTML = strResponse; });
	}
});

var Utils = new Utilities();

var Mediator = Class.create();
Mediator.prototype =
{
	initialize: function()
	{
		this.hTogglers = new Hash();
		
		// if there is a tab id in the URL, we'll need to show it
		this.strCurrentTabId = Utils.GetHash(window.location);
		
		// all non-IE browsers store each anchor as a separate history-item. To make the back-button work, we respond to URL changes
		if (Prototype.Browser.Gecko)
		{
			setInterval(function()
			{
				var strAnchor = Utils.GetHash(window.location);
				if (this.strCurrentTabId != strAnchor)
				{
					this.strCurrentTabId = strAnchor;
					this.onURLChange(strAnchor);
				}
			}.bind(this), 1000);
		}
	},

	Register: function(strID, obj)
	{
		this.hTogglers[strID] = obj;
		// if this hToggler instance can show the current Tab ID, show it
		if (this.strCurrentTabId)
			obj.ShowByTargetId(this.strCurrentTabId);
	},
	
	GetNestedTogglers: function(elemParent)
	{
		var aobjNested = [];
		this.hTogglers.each(function(pair)
		{
			
			var elemToggler = $(pair.key);
			elemToggler.ancestors().each(function(elemAncestor)
			{
				if (elemAncestor == elemParent)
					aobjNested.push(pair.value);
			});
		});
		return aobjNested;
	},
	
	ShowByTargetId: function(strID)
	{
		this.hTogglers.each(function(pair)
		{
			pair.value.ShowByTargetId(strID);
		});
	},

	// when the anchor changes, go to that particular tab
	onURLChange: function(strAnchor)
	{
		this.ShowByTargetId(strAnchor);
	}
};


/* hToggler version 0.9 by Martin Hintzmann Andersen, http://www.hintzmann.dk */
/* hToggler-CSNW v1.0 by CornerStone NW, http://www.CornerStoneNW.com/ */
var hToggler;

// Constructor (new hToggler("tabs_id", "tabs2_id", ...);
var hToggler = Class.create();

// IsSupported (static property)
hToggler.IsSupported = (document.getElementById && document.getElementsByTagName);
// Mediator (static object-property) - Constructor
hToggler.Mediator = new Mediator();

hToggler.prototype = 
{
	initialize: function(sRoot)
	{
		// guard clauses
		if (!hToggler.IsSupported) return;
		if (!sRoot) return;
		
		// build list of all the links
		this.aelemLinks = [];
		var nArgs = arguments.length;
		for (var nArg = 0; nArg < nArgs; ++nArg)
		{
			var strRoot = arguments[nArg];
			$(strRoot).className = "hTogglerJS";
			var nodeListLinks = $(strRoot).getElementsByTagName("a");
			var nNodes = nodeListLinks.length;
			for (var nNode = 0; nNode < nNodes; ++nNode)
				this.aelemLinks.push(nodeListLinks[nNode]);
		}

		// iterate the links, styling all the target elements
		var nLinks = this.aelemLinks.length;
		for (var i=0; i < nLinks; ++i)
		{
			var elemLink = this.aelemLinks[i];
			Utils.ProcessHash(elemLink);
			var elemTarget = $(Utils.GetTargetId(elemLink));
			if (Utils.IsLocalAnchor(elemLink))
			{
				elemLink.onclick = this.GenerateClickHandler(elemLink); // had to move into separate function to prever closure from always happening on the *last* elemLink
			}
			else
			{
				elemLink.setAttribute("targetUrl", elemLink.href); // store href in targetUrl property
				elemLink.href = "#";
				Utils.SetHash(elemLink, elemTarget.id); // set href to tab id
			}
			
			// add styling, click handler and hide the target div
			if (elemTarget)
			{
				elemTarget.addClassName("hTogglerJS_target");
				elemTarget.style.display = "none";
			}
		}
		this.ShowDefault();
		
		// register this instance with the static mediator
		hToggler.Mediator.Register(sRoot, this);
	},
	GenerateClickHandler: function(elemLink)
	{
		return function() { this.Show(elemLink); }.bind(this);
	},
	ShowByTargetId: function(strID)
	{
		if (strID.length > 0)
		{
			var elemSource = this.GetSourceElement(strID);
			if (elemSource)
				this.Show(elemSource);
		}
	},
	
	ShowDefault: function()
	{
		// show the first tab by default
		if (this.aelemLinks.length > 0)
			this.Show(this.aelemLinks[0], true);
	},

	Show: function(elemLink, bDefault)
	{
		elemLink = $(elemLink);
		var elemTarget = $(Utils.GetTargetId(elemLink));

		// STINK?
		// For back-button to first element on nested tabs:
		// if an element's already visible, reset nested hTogglers to default (first element)
		if (elemTarget.visible())
		{
			hToggler.Mediator.GetNestedTogglers(elemTarget).each(function(objToggler)
			{
				objToggler.ShowDefault();
			});
		}

		this.HideAll();
		elemTarget.show();
		elemLink.parentNode.addClassName("current");
		
		var strTargetUrl = elemLink.getAttribute("targetUrl");
		if (strTargetUrl)
		{
			Utils.LoadXMLDoc(strTargetUrl, elemTarget);
			elemLink.setAttribute("targetUrl", ""); // it's already been loaded, remove targetUrl
		}

		// if it's not just being shown by default, walk the ancestors and show them if they're invisible
		if (!bDefault)
		{
			elemTarget.ancestors().each(function(elemAncestor)
			{
				if (!elemAncestor.visible())
					hToggler.Mediator.ShowByTargetId(elemAncestor.id);
			}.bind(this));
		}
	},

	HideAll: function()
	{
		// hide the targets for all the normal tabs
		var nLinks = this.aelemLinks.length;
		for (var i=0; i < nLinks; ++i)
		{
			var elemLink = this.aelemLinks[i];
			$(elemLink.parentNode).removeClassName("current");
			var elemTarget = $(Utils.GetTargetId(elemLink));
			if (elemTarget)
				elemTarget.hide();
		}
	},

	GetSourceElement: function(elemTarget)
	{
		elemTarget = $(elemTarget); // convert to element, if it's a string
		var nLinks = this.aelemLinks.length;
		for (var i=0; i < nLinks; ++i)
		{
			var elemLink = this.aelemLinks[i];
			if ($(Utils.GetTargetId(elemLink)) == elemTarget)
				return elemLink;
		}
		return null;
	}
};

