// system wide functionality
var g_IEVersion = 7;	/* only use this value if you have already
			determined that the browser is IE.  Otherwise
			the value if this variable is meaningless. */
/* Set blank default to off */
var g_Blank = false;

// these are here because when non-IE browsers check for an IE deficency function
// it won't generate a javascript error.
onSubMenuCreate = null;
onSubMenuDestroy = null;
ieFixObjects = null;

// BEGIN BrowserDetect
var BrowserDetect = {
        init: function () {
                this.browser = this.searchString(this.dataBrowser) || "An unknown browser";
                this.version = this.searchVersion(navigator.userAgent)
                        || this.searchVersion(navigator.appVersion)
                        || "an unknown version";
                this.OS = this.searchString(this.dataOS) || "an unknown OS";
        },
        searchString: function (data) {
                for (var i=0;i<data.length;i++) {
                        var dataString = data[i].string;
                        var dataProp = data[i].prop;
                        this.versionSearchString = data[i].versionSearch || data[i].identity;
                        if (dataString) {
                                if (dataString.indexOf(data[i].subString) != -1)
                                        return data[i].identity;
                        }
                        else if (dataProp)
                                return data[i].identity;
                }
        },
        searchVersion: function (dataString) {
                var index = dataString.indexOf(this.versionSearchString);
                if (index == -1) return;
                return parseFloat(dataString.substring(index+this.versionSearchString.length+1));
        },
        dataBrowser: [
                {       string: navigator.userAgent,
                        subString: "OmniWeb",
                        versionSearch: "OmniWeb/",
                        identity: "OmniWeb"
                },
                {
                        string: navigator.vendor,
                        subString: "Apple",
                        identity: "Safari"
                },
                {
                        prop: window.opera,
                        identity: "Opera"
                },
                {
                        string: navigator.vendor,
                        subString: "iCab",
                        identity: "iCab"
                },
                {
                        string: navigator.vendor,
                        subString: "KDE",
                        identity: "Konqueror"
                },
                {
                        string: navigator.userAgent,
                        subString: "Firefox",
                        identity: "Firefox"
                },
                {
                        string: navigator.vendor,
                        subString: "Camino",
                        identity: "Camino"
                },
                {               // for newer Netscapes (6+)
                        string: navigator.userAgent,
                        subString: "Netscape",
                        identity: "Netscape"
                },
                {
                        string: navigator.userAgent,
                        subString: "MSIE",
                        identity: "Explorer",
                        versionSearch: "MSIE"
                },
                {
                        string: navigator.userAgent,
                        subString: "Gecko",
                        identity: "Mozilla",
                        versionSearch: "rv"
                },
                {               // for older Netscapes (4-)
                        string: navigator.userAgent,
                        subString: "Mozilla",
                        identity: "Netscape",
                        versionSearch: "Mozilla"
                }
        ],
        dataOS : [
                {
                        string: navigator.platform,
                        subString: "Win",
                        identity: "Windows"
                },
                {
                        string: navigator.platform,
                        subString: "Mac",
                        identity: "Mac"
                },
                {
                        string: navigator.platform,
                        subString: "Linux",
                        identity: "Linux"
                }
        ]

};
BrowserDetect.init();
// END BrowserDetect

function getNodeData(root, nodeName)
{// begin getNodeData
	var nodes = root.getElementsByTagName(nodeName);
	if(nodes.length > 0 && nodes[0].firstChild)
	{
		return nodes[0].firstChild.nodeValue;
	}
	return "";
}// end getNodeData

function getAbsoluteLeft(objectId)
{
	// Get an object left position from the upper left viewport corner
	// Tested with relative and nested objects
	var o = document.getElementById(objectId);
	var oLeft = o.offsetLeft;            // Get left position from the parent object
	while(o.offsetParent!=null)
	{   // Parse the parent hierarchy up to the document element
		var oParent = o.offsetParent;    // Get parent object reference
		oLeft += oParent.offsetLeft; // Add parent left position
		o = oParent;
	}
	// Return left postion
	return oLeft;
}

function getAbsoluteTop(objectId)
{
	// Get an object top position from the upper left viewport corner
	// Tested with relative and nested objects
	var o = document.getElementById(objectId);
	if(!o)
		return null;
	var oTop = o.offsetTop;            // Get top position from the parent object
	while(o.offsetParent!=null)
	{ // Parse the parent hierarchy up to the document element
		var oParent = o.offsetParent;  // Get parent object reference
		oTop += oParent.offsetTop; // Add parent top position
		o = oParent;
	}
	// Return top position
	return oTop;
}

/* BEGIN onload hook */
function addLoadEvent(func)
{
	var oldonload = window.onload;
	if (typeof window.onload != 'function')
	{
		window.onload = func;
	}
	else
	{
		window.onload = function() {
			oldonload();
			func()
		}
	}
}

	addLoadEvent(onPageLoad);
//	addLoadEvent(function() {
//	/* more code to run on page load */
//	});
/* END onload hook */

function onPageLoad()
{
	// hook in addEventListener emulation
	if(ieFixObjects)
		ieFixObjects(document.all);
}

/* Define our console debugging handlers to overlook firebug based debugging when not enabled */
if(!window.console)
{
	// setup a debugging panel
	function OutputConsole()
	{// begin OutputConsole
		this.info = function (msg)
		{// begin info
			var debug_panel = document.getElementById("debugpanel");
			if(!debug_panel)
			{
				// create the panel
				var debug_panel_div = document.createElement("div");
				debug_panel_div.setAttribute("id", "debugpanel");
				debug_panel_div.setAttribute("style", "position: absolute; top: 0; opacity: 0.8; font-size: .8em; font-family: fixed; background-color: #444; color: white; z-index: 9999; text-align: left; padding: .5em; max-height: 15em; max-width: 25em; overflow-y: scroll;");
				var body_element = document.getElementsByTagName("body");
				if(body_element.length > 0)
				{
					body_element = body_element[0];
					body_element.appendChild(debug_panel_div);
					debug_panel = debug_panel_div;
				}
			}
			var log_msg = document.createElement("div");
			log_msg.setAttribute("style", "border-bottom: thin dotted #CCC; padding-bottom: .25em; padding-top: .25em;");
			log_msg.innerHTML = ": "+msg;
			debug_panel.appendChild(log_msg);
			debug_panel.scrollTop = 9999999;
//			alert(msg);
		}// end info
		this.log = function (msg)
		{// begin info
			this.info(msg);
		}// end info
	}// end OutputConsole

	console = new OutputConsole();
}

function hasTag(tagName,tagValue,startTag)
{// begin hasTag
	if(startTag == null)
		tags = document.getElementsByTagName("div");
	else
		tags = startTag.getElementsByTagName("div");
	for(var i = 0;i < tags.length;i++)
	{// begin find tagName
		if(tags[i].type == "div")
			if(hasTag(tagName,tagValue,tags[i]))
				return true;
		if(tags[i].getAttribute(tagName) == tagValue)
			return true;
	}// end find tagName
	return false;
}// end  hasTag

function onGlobalPageKeyPress(e)
{
	var e_out;
	var ie_var = "srcElement";
	var w3c_var = "target";
	var prop_var = "form";
	var object = e[w3c_var] ? e[w3c_var] : e[ie_var];
	
	DOMEventHandler_KeyPress(e);
}

function DOMEventHandler_KeyPress(e)
{
	var e_out;
	var ie_var = "srcElement";
	var w3c_var = "target";
	var prop_var = "form";
	var object = e[w3c_var] ? e[w3c_var] : e[ie_var];
	
	var key = e.keyCode ? e.keyCode : e.which;
	
	if(key == 13 && object.type != 'textarea' && object.type != 'submit')
	{
		console.log("DOMEventHandler_KeyPress: "+object.nodeName+":"+object.type);
		
		// if the next field in the form is submit, then let the browser handle the event
		// this is normally the form submission.  Otherwise move to the next field.
		var next_submit = false;
		var focus_moved = false;
		for(var i = 0;focus_moved == false && next_submit == false && i < document.forms.length;i++)
		{
			for(var j = 0;focus_moved == false && next_submit == false && j < document.forms[i].elements.length;j++)
			{
				if(document.forms[i].elements[j].getAttribute("id") == object.getAttribute("id") && j+1 < document.forms[i].elements.length)
				{
					for(;focus_moved == false && next_submit == false && j+1 < document.forms[i].elements.length;j++)
					{
						var element_type = document.forms[i].elements[j+1].getAttribute("type");
						console.log("element_type: "+element_type);
						console.log("nodeName orig: "+document.forms[i].elements[j].nodeName);
						console.log("nodeName: "+document.forms[i].elements[j+1].nodeName);
						if(element_type)
						{
							element_type = element_type.toLowerCase();
							if(element_type == "submit")
							{
								next_submit = true;
								console.log("next element is submit");
							}
							else if(element_type != "hidden")
							{
					//			document.forms[i].elements[j+1].focus();
								focus_moved = true;
							}
						}

					}
				}
			}
		}
		if(object.nodeName.toLowerCase() != "a" && next_submit == false || focus_moved == true)
		{// begin not anchor
			e.returnValue = false;
			e.cancelBubble = true;
			if(e.preventDefault)
				e.preventDefault();
			if(e.stopPropagation)
				e.stopPropagation();
			return false;
		}// end not anchor
	}
	return true;
}


function MicrosoftEventHandler_KeyPress()
{
	if (event.keyCode == 13 && event.srcElement.type != 'textarea' && event.srcElement.type != 'submit')
	{
		if(event.srcElement.type != 'a' && document.getElementById("link-display"))
		{// begin default link
			location.href = document.getElementById("link-display").childNodes[0].getAttribute("href");
		}// end default link
		return false;
	}
	return true;
}

function clearArea(id)
{
	if(document.getElementById(id))
	{
		document.getElementById(id).style.visibility = "hidden";
		document.getElementById(id).style.display = "none";
		document.getElementById(id).innerHTML = "";
	}
}

function array_find(arr,val)
// returns true if val is in array arr, false otherwise
{
	for(var i = 0;i < arr.length;i++)
	{
		if(arr[i] == val)
			return true;
	}
	return false;
}

function fixupReplaceElement(element, old_element, id)
{// begin fixupReplaceElement
	// remove id and class and replace it with the replacing's id and class
	element.removeAttribute("id");
	element.setAttribute("id", id);
	element.setAttribute("class", old_element.className);
}// end fixupReplaceElement

function grabAndReplacePageCallback(request)
{
	if (request.readyState == 4)
	{

		try
		{
			var element = document.getElementById(request.current_id);
			var newdoc = request.responseXML;
			var new_element = newdoc.getElementById(request.new_id);
	
			fixupReplaceElement(new_element, element, request.current_id)
			if(request.extraCallback)
				console.log("grabAndReplacePageCallback: call back found");
			element.parentNode.replaceChild(new_element, element);
		}
		catch(e)
		{
			/*
			Since browsers that don't automatically convert an XML node to a DOM node
			Will throw an exception, we will catch it and try to do the rendering the
			fallback way by creating a DOM element, assigning the innerHTML, then replacing.
			The reason we don't do this by default is that it incures a significant performace
			penalty, which if can be avoided should be.
			This also only works for top-level elements from the document body so it isn't
			yet a general solution.  To be that a getElementById() like search should be performed for the entrie document tree.
			*/
			console.log("alternate replace method");
			new_element = null;
			var node = document.createElement("div");
			node.innerHTML = request.responseText;
			if(document.all && !window.opera)	// IE HACK
				ieFixObjects(node.all);
			var divs = node.getElementsByTagName("div");
			for(var i = 0;i < divs.length;i++)
			{
				if(divs[i].hasAttribute("id") == true && divs[i].getAttribute("id") == request.new_id)
				{// being found the correct node
					console.log("correct node found");
					new_element = divs[i];
					fixupReplaceElement(new_element, element, request.current_id)
					element.parentNode.replaceChild(new_element, element);
					break;
				}// end found the correct node
			}
			console.log(i);
		}
		if(swapInHook)
			swapInHook();
		overrideLinks(request.uri, request.core_node_id, request.current_id, request.new_id, request.extraCallback, request.extraOnClick);
	}
}

function grabAndReplacePage(uri, core_node_id, current_id, new_id, changeURI, extraCallback, extraOnClick, async)
{// begin grabAndReplacePage
	console.log(uri);
	
	// show loading animation
	var element = document.getElementById(current_id);
	var loading = document.createElement("div");
	loading.className = "loading";
	loading.innerHTML = "<img src='/Skins/Curby/loading.gif' alt='Loading...' />";
	loading.style.top = getAbsoluteTop(current_id)+"px";
	loading.style.left = getAbsoluteLeft(current_id)+"px";
	loading.style.width = element.offsetWidth+"px";
	loading.style.height = element.offsetHeight+"px";
	element.insertBefore(loading, element.firstChild);
	
	var xmlRequest = new XMLHttpRequest();
	xmlRequest.current_id = current_id;
	xmlRequest.new_id = new_id;
	xmlRequest.uri = changeURI;
	xmlRequest.core_node_id = core_node_id;
	xmlRequest.extraCallback = extraCallback;
	xmlRequest.extraOnClick = extraOnClick;
// ignore for now
//	if(async == true)
		xmlRequest.onreadystatechange = function() { grabAndReplacePageCallback(xmlRequest); };
	xmlRequest.open('GET', uri, async);
	xmlRequest.setRequestHeader("X_CURBY_CUSTOM", "force-xhtml");
	xmlRequest.send(null);
}// end grabAndReplacePage

function overrideLinks(uri, core_node_id, current_id, new_id, extraCallback, extraOnClick)
{
	if(!document.getElementById(core_node_id))
	{
		console.log("invalid core_node_id: "+core_node_id);
		return;
	}
	var a = document.getElementById(core_node_id).getElementsByTagName("a");
	for(var i = 0;i < a.length;i++)
	{
		if(!a[i].hasAttribute("href"))
			continue;
		// The following is commented out since IE doesn't follow the specs when and 'href' attribute is retrived.
		// But by passing the second parameter iFlags (IE specific) to getAttribute it does the right thing.  Good
		// browsers just seem to ignore the second attribute (luckily).  Unfortunately this doesn't work realiably in IE
		// since on nodes created from .innerHTML creation still return the full path even with the iFlags parameter set
		// to 2.  So we need to create a wrapper function to return only the relative path.  Only force IE to incur this
		// overhead now.
//		var hrefValue = a[i].getAttribute("href");
//		var hrefValue = a[i].getAttribute("href", 2);
		if(document.all && !window.opera)	// IE
			var hrefValue = getRelativePath(a[i].getAttribute("href"));
		else	// Good Browsers
			var hrefValue = a[i].getAttribute("href");
		var uriMatch = new RegExp("^"+uri);

		/*
		Certain links (anchor tags) may want to not be overridden/replaced
		with the XmlHttpRequest handling due to various reasons. To have these
		links be ignore set the "rel" attribute to "noreplace".  This will
		instruct the replacer (overrideLinks) that this link should be
		skipped.  Currently the code doesn't support multiple entries in the
		"rel" attribute.  This should be addressed in future versions for
		more generic compatibility.
		*/
		if(a[i].hasAttribute("rel") && a[i].getAttribute("rel").toLowerCase() == "noreplace")
			continue;

		if(hrefValue.match(uriMatch) == null)
			continue;
		a[i].removeAttribute("href");
		a[i].hrefValue = hrefValue;
		a[i].current_id = current_id;
		a[i].new_id = new_id;
		a[i].uri = uri;
		a[i].core_node_id = core_node_id;
		a[i].extraCallback = extraCallback;
		a[i].extraOnClick = extraOnClick;
		// add our default onclick handler
		a[i].addEventListener('click', onClickLinkOverride, false);

		var children = a[i].childNodes;
		for(var n = 0;n < children.length;n++)
		{// begin hook child nodes
			try
			{
				children[n].hrefValue = hrefValue;	// IE seems to have trouble here instead of just creating the member
				children[n].current_id = current_id;
				children[n].new_id = new_id;
				children[n].uri = uri;
				children[n].core_node_id = core_node_id;
				children[n].extraCallback = extraCallback;
				children[n].extraOnClick = extraOnClick;
				children[n].addEventListener('click', onClickLinkOverride, false);
			}
			catch(err)
			{
				// we don't do anthing here since IE will throw an exception on stuff in the try{...} block
			}
		}// end hook child nodes

		// add our custom onclick handler
		if(extraOnClick)
		{
			a[i].addEventListener('click', extraOnClick, false);
			if(a[i].firstChild && a[i].firstChild.hrefValue)
			{
				// safari 1.3 seems to not install the event handler correctly so directly attach it to
				// the text child element
				a[i].firstChild.addEventListener('click', extraOnClick, false);
			}
		}
	}
	// run callback
	if(extraCallback)
		extraCallback();
	else
		console.log("No extra callback");
}


function onClickLinkOverride(e)
{// begin onClickLinkOverride
	var e_out;
	var ie_var = "srcElement";
	var w3c_var = "target";
	var prop_var = "form";
	var object = e[w3c_var] ? e[w3c_var] : e[ie_var];

	console.log(object.nodeName);
	if(!object.hrefValue)
	{// begin we might be in child #text node
		object = object.parentNode;
	}// end we might be in child #text node

	grabAndReplacePage(object.hrefValue, object.core_node_id, object.current_id, object.new_id, object.uri, object.extraCallback, object.extraOnClick, true);
	if(e.preventDefault)
		e.preventDefault();
	if(e.stopPropagation)
		e.stopPropagation();
	e.cancelBubble = true;
	return false;
}// end onClickLinkOverride

function findParent(obj, nodeName)
{// begin findParent
	var currentNode = obj.parentNode;
	while(currentNode && currentNode.nodeName.toLowerCase() != nodeName)
	{
		currentNode = currentNode.parentNode;
	}
	return currentNode;
}// end findParent

function getRelativePath(url)
{// begin getRelativePath
	var hostnameStripRe = new RegExp("^http[s]?://[0-9a-zA-Z\-\:\.]+");
	return url.replace(hostnameStripRe,"");
}// end getRelativePath

