/* Copyright 2007 by Ruben Kleiman. All Rights Reserved.
Write to ruben@rubenkleiman.com to get written permission to use this.
- Thanks.
*/

// _initialMenuElementId: menu id corresponding to loaded page
//var _initialMenuElementId = set up by server;


/* Detect user agent */
var agent = navigator.userAgent.toLowerCase();
var _isSafari = (agent.indexOf("safari") != -1);
var _isFirefox = (agent.indexOf("firefox") != -1);
var _isIE = (agent.indexOf("msie") != -1);
var _isOpera = (agent.indexOf("opera") != -1);

// _homeMenuElementId: menu id of home page
var _homeMenuElementId = "index";

// _selectedMenu: the currently selected menu
//   This is an IMG tag with the menu's image
var _selectedMenuElement;

// _clickedLink: last link clicked
var _lastClickedLink = null;

// _HOST_URL: url of host application
//  IMPORTANT: must exactly match location.href hostname (e.g., no "www")
var _HOST_URL = _getHostUrl();
//alert(_HOST_URL);
function _getHostUrl() {
	var cgi = '/?f=';
	var loc = location.href;
	if (loc.indexOf('localhost') != -1) {
		return "http://localhost/horsensei"+cgi;
	}
	var ix = loc.indexOf('/', 7)
	return loc.substr(0, ix)+cgi;
}

// _addAppHooks: called on page load
function _addAppHooks() {
	if (!document.getElementById || !document.getElementsByTagName) return;
	_adjustMenus4Browsers();
	_selectMenu(_getMenuLinkElement(_initialMenuElementId), null);
	_processElements(document.getElementById("navmenus"), false);
	var content = document.getElementById("content");
	_processElements(content, true);
	_showContent(content);
}



// _processElements: Processes all elements inside the root element.
//    [See _processElements2 for processing details]
// root: a root element node
// doUpdate: if true, fetches contents from specified page
//           after processing the nodes.
function _processElements(root, doUpdate) {
	if (!root) return;
	var links = root.getElementsByTagName("a");
	if (links) _processElements2(links, false);
	var areas = root.getElementsByTagName("area");
	if (areas) _processElements2(areas, doUpdate);
	
}
// _processElements2: Adds click handlers to each specified element
//   iff it does not have a blank TARGET, or if its HREF is either '#'
//   or an external uri.
// elements: array of elements
// doUpdate: if true, fetches contents from specified page
//           after processing the nodes.
function _processElements2(elements, doUpdate) { //alert('entered _processElements2');
	for (var i=0; i<elements.length; i++) {
		var el = elements[i];
		var menuid = el.getAttribute("menuid");
		if (menuid == null)  continue;
		
		/* xxx Yahoo addListener fails in Firefox
		YAHOO.util.Event.addListener( el, "click", function( evt ) { 
						var href = this.getAttribute("href");
						var section = _getSection(YAHOO.util.History.getQueryStringParameter("f", href) || _initialMenuElementId);
						if ((section == _getSection(href)) && (section == _getSection(location.href))) {
							// override
							return !_tryFetchContent(section);
						}
						try {
							_lastClickedLink = this;
							YAHOO.util.History.navigate("app", section);
							return false;
						} catch (e) {
							return !_tryFetchContent(section); // return false if ajax-incapable
						}
						// safari: YAHOO.util.Event.preventDefault(evt);
					});
		*/
		el.onclick = function _onclickHandler() { 
						var href = this.getAttribute("href"); 
						var section = _getSection(YAHOO.util.History.getQueryStringParameter("f", href) || _initialMenuElementId);
						if ((section == _getSection(href)) && (section == _getSection(location.href))) {
							// override
							return !_tryFetchContent(section);
						}
						try {
							_lastClickedLink = this;
							YAHOO.util.History.navigate("app", section);
							return false;
						} catch (e) {
							return !_tryFetchContent(section); // return false if ajax-incapable
						}
		};
		
	} // end for
	if (doUpdate) {
		var currentSection = YAHOO.util.History.getCurrentState("app");
		if (location.hash.substr(1).length > 0) {
			if (currentSection != _querySection)
				document.getElementById("content").innerHTML = ""; // maybe reduce flicker
			_tryFetchContent(currentSection);
		}
	}
}

// _getSection: ensures string is unqualified section name
function _getSection(str) {
	if (!str) return null;
	var i = str.indexOf('.htm');
	var x;
	if (i != -1) return str.substr(x = str.lastIndexOf('/')+1, i-x);
	else return str;
}

// _adjustMenus4Browsers
function _adjustMenus4Browsers() {
	if (_isFirefox || _isSafari || _isOpera) { // adjust popup menu height
		els = document.getElementsByTagName('div');
		for (var i=0;i<els.length;i++) {
			if (els[i].className == 'popup')
				els[i].style.marginTop = "-2.65em";
		}
	}
}
// _selectMenu: selects menu and deselects old menu
function _selectMenu(linkElement, menuId) { 
	//if (_isSafari) alert("linkElement="+linkElement+"menuId"+menuId);
	_deselectMenu(); 
	if (!linkElement) {
		linkElement = _getMenuLinkElement(menuId);
	}
	var menuElement = _getMenuElement(linkElement);
	if (!menuElement) {
		alert("Horsensei Server Programming Error. Missing menu item for '"+linkElement+"'\nPlease contact webmaster@horsensei.com."); // broken
			return;
	}
	_setPageCSS(menuElement.getAttribute('id'));
	homeMenu = eval(menuElement.name + "home.src");
	if (homeMenu) document[menuElement.name].src = homeMenu;
	else if (_homeMenuElementNamePrefix) {
		//document[_homeMenuElementNamePrefix].src = eval(_homeMenuElementNamePrefix + "home.src");
		//menuElement = _getMenuElement(^);
	}
	_selectedMenuElement = menuElement;
}
// _setPageCSS: sets up the page's CSS context
function _setPageCSS(menuElementId) {
	if (document.body && document.body.style) {
		var isHomePage = (menuElementId == _homeMenuElementId);
		_setBkgndImage(isHomePage);
		var c = document.getElementById("content");
		if (c) c.className = isHomePage?"homecontent":"stdcontent";
		_adjustMenus4Browsers();
	}
}

// _setBkgndImage: sets the background image
function _setBkgndImage(isHomePage) {
	/* xxx would like to cache this "preload background images css"
	var x = document.getElementById("bkgndpict");
	document["bkgndpict"].src = isHomePage?homebkgnd:stdbkgnd;
	*/
	document.body.style.backgroundImage = 
		isHomePage?"url(images/home_bg.jpg)":"url(images/secondary_bg.jpg)";
	document.body.style.backgroundRepeat="no-repeat";
}

// _deselectMenu: deselects menu
function _deselectMenu() {
		if (_selectedMenuElement) {
			document[_selectedMenuElement.name].src = eval(_selectedMenuElement.name + "off.src");
		}
}
// _getMenuElement: returns element's associated img element
function _getMenuElement(element) {
	if (!element) return null;
	var menuid = element.getAttribute('menuid'); 
	if (menuid) return document.getElementById(menuid);
	var menuElement = element.firstChild;
	if (menuElement && (menuElement.nodeName == 'IMG')) return menuElement;
	return null; // xxx test/dbg
}
// _getMenuLinkElement: returns the menu element's link element
function _getMenuLinkElement(menuElementId) {
	var menuElement = document.getElementById(menuElementId);
	if (!menuElement) return null;
	var linkElement = menuElement.parentNode;
	if (linkElement && (linkElement.nodeName == 'A')) return linkElement;
	alert('Horsensei HTML formatting error: missing A-tag for menu element\nPlease contact webmaster@horsensei.com.'); // xxx dbg
}

function _startMouseOverMenu(menuElement){ 
	if (menuElement != _selectedMenuElement)
		document[menuElement.name].src = eval(menuElement.name + "on.src");
} 

function _endMouseOverMenu(menuElement){
	if (menuElement != _selectedMenuElement)
		document[menuElement.name].src = eval(menuElement.name + "off.src");
} 
// _tryFetchContent - fetches an html fragment to insert into the content div
// section: the page's content section name
function _tryFetchContent(section) {
	//alert("fetching: "+section);
	var lnk = _getMenuLinkElement(section);
	if (lnk == null) lnk = _lastClickedLink;
	//_deselectMenu(); 
	var request = _getHTTPObject(); 
	if (!request) return false;
	request.onreadystatechange = 
		function() {
			_handleContentResponse(request, lnk);
		};
	var url = _HOST_URL+escape(section); 
	//alert('Sending to '+url);
	try {
		request.open("GET", url, true);
		request.send(null);
	} catch (e) {
		alert('Error accessing Horsensei server. Please contact webmaster@horsensei.com with error='+e.description);
		return false;
	}
	//document.getElementById("content").innerHTML = "";
	return true;
}

// _handleContentResponse: gets html fragment and inserts it into contents div
// The response consists of the following strings (delimited by "*sep*" string):
// items[0]: (required: may be empty string)Additional headers (to be placed inside the <HEADER> tag
//           Note: this is not used because not all browsers permit the HEADER to be modified
// items[1]: (required) property:value pairs of the form <property name>:<value> The property/value pairs are themselves
//            delimited by a comma ","
// items[2]: (required) the innerHTML content to be rendered as-is
// items[3]: (optional) Javascript string to execute
// xxx handle failure: do a GET on fail
function _handleContentResponse(request, lnk) { 
  if (request.readyState == 4) {
    if (request.status == 200 || request.status == 304) {
	  var content = document.getElementById("content");
	  if (content) {
	  	 //alert('content='+request.responseText);
		  data = request.responseText;
		  items = data.split('*sep*');
		  if (items.length < 3) alert("Sorry: bad content data returned by server.\nPlease contact webmaster@horsensei.com");
		  var menuid = _getPropertyValue(items[1], 'menuid');
		  if (_isSafari && (menuid == "index")) {
			  // xxx band-aid 6/25/07
			  location.href = "http://horsensei.com";
			  return;
		  }
		  _selectMenu(null, menuid);
			if (_isSafari) _showContent(content);
		  content.innerHTML = items[2]; // content visibility = hidden
		  _maybeExecScript(items);
		  _processElements(content, false);
		  _showContent(content);
		  	//_updateHeadContent(items[0]); xxx optional but compulsive people like me would love it
	  }
	} else {
		// xxx TODO go to error page or to index page
		alert('Error status='+request.status+'\nPlease contact webmaster@horsensei.com');
	}
  }
}

// _showContent: shows possibly hidden contents
function _showContent(content) {
  if ((content != null) && content.style) {
	  content.style.visibility = "visible";
  }
}
// _maybeExecScript: executes embedded Javascript, if any
function _maybeExecScript(items) {
	if (items.length == 4) eval(items[3]);
}

// _getPropertyValue: returns a property value or null if
//    there is no value for the specified property name
function _getPropertyValue(pvString, propertyName) {
	pvString = _trim(pvString)
	var pvs = pvString.split(",");
	for (var i=0;i<pvs.length;i++) {
		var pv = pvs[i].split(":");
		if ((pv.length > 1) && (pv[0] == propertyName)) {
			return pv[1].substr(0, pv[1].length-1);
		}
	}
	return null;
}

// _trim: trim returns/enter/form-feeds and spaces
function _trim(str) {
	while ((str.length != 0) && ((str.charAt(0) == ' ') || (str.charAt(0) == '\r') || (str.charAt(0) == '\n') || (str.charAt(0) == '\f')))
		str = str.substr(1, str.length-1);
	while ((str.length != 0) && ((str.charAt(0) == ' ') || (str.charAt(0) == '\r') || (str.charAt(0) == '\n') || (str.charAt(0) == '\f')))
		str = str.substr(0, str.length-2);
	return str;
}

// _updateHeadContent: change HEAD element's contents in non-IE browsers
//       IE7 won't allow one to edit the HEAD element either
//       through innerHTML or though the DOM. So, this is
//       a good ol' college try. The script will enter rigor mortis
//       when appendChild is executed. Fortunately, changing the head here is
//       a frill that won't interfere with functionality.
function _updateHeadContent(xml) { //alert(xml);
	head = document.getElementsByTagName("head")[0];
	if (!head) return;
	if (_isIE) {
		/* This won't work as if IE7
		xml = "<root>"+xml+"</root>"; 
		var doc = new ActiveXObject("Microsoft.XMLDOM"); 
  		doc.async = "false";
  		doc.loadXML(xml);
		var root = doc.documentElement;
		while (head.firstChild) head.removeChild(head.firstChild); 
		for (var i=0;i<root.childNodes.length;i++)
			head.appendChild(root.childNodes[i]); 
		*/
	} else {
		// Comically enough, this works, even though IE invented it!
		 head.innerHTML = xml;
	}
}

function _getHTTPObject() {
  var httpobj = false;
  if (window.XMLHttpRequest) {
	httpobj = new XMLHttpRequest();
  } else if (window.ActiveXObject) {
	try {
	  httpobj = new ActiveXObject("Msxml2.XMLHTTP");
	} catch(e) {
	  try {
		httpobj = new ActiveXObject("Microsoft.XMLHTTP");
	  } catch(e) {
		httpobj = false;
	  }
	}
  }
  return httpobj;
}

// EMAIL SUBSCRIPTION PAGE ============
function incompatibleBrowser() {
	alert("Sorry, your browser doesn't support this feature. To subscribe, please e-mail to sensei@horsensei.com.");
}
function subscribe() {
  // The constant contact account number might change:
  var horsenseiAccountNo = 1101312706909;
  var it = document.getElementById("ea");
  if (it == null) {
	incompatibleBrowser();
  } else {
  	var url = "http://visitor.constantcontact.com/optin.jsp?m="+horsenseiAccountNo+"&lang=en&ea="+it.value;
  	window.open(url,"SubscriptionWindow", "scrollbars=yes,width=750,height=500,personalbar=no,top=yes,toolbar=no");
  }
}
function keyPressed(e) {
	if ((e.which != null) && (e.which == 13)) {
		subscribe();
	} else if ((window.event != null) && (window.event.keyCode == 13)) {
		subscribe();
	} else {
		// do nothing
	}
}

// MISC UTILITIES =====================
function _popupRestrictedWindow(element) { // xxx deprecated
	return _popupWindow(element);
	//if (!element.href) return;
	//window.open(element.href, '', 'scrollbars=yes,width=750,height=640,personalbar=no,top=yes,toolbar=no');
}
function _popupWindow(element) {
	if (!element.href) return true;
		return _popupUrl(element.href);
}
function _popupUrl(url) {
	window.open(url, '', 'scrollbars=yes,width=750,height=640,personalbar=yes,top=yes,toolbar=yes');
	return false;
}
function goToAnchor(name) {
	window.location = '#'+name;
}

