/*
	$Archive: /SwiftKnowledge.VB.NET/trunk/SKWeb/resources/_site_utils.js $
	$Author: jm04 $
	$Date: 2005-07-25 15:56:23-05:00 $
	$Revision: 18 $
	
	Copyright (c) 2000-2005, SwiftKnowledge, Inc.
	All rights reserved.
	
	**Start Encode**
*/

var reHTML = /[\&\<\>\n]/g; // used by writeMsg AND innerText clone

function addHandler(object, eventName, callBack)
{
	// usage: addHandler(window, "onload", functionName);
	// This cross-browser function will allow you to bind multiple
	// handlers to one event.
	
	eventName = eventName.toLowerCase();
	
	if (object.addEventListener)
	{
		if (eventName.substr(0,2) == "on")
			eventName = eventName.substr(2);
			
		object.addEventListener(eventName, callBack, false);			
	}
	else
	{
		if (eventName.substr(0,2) != "on")
			eventName = "on" + eventName;
		
		object.attachEvent(eventName, callBack);
	}
}

function checkFrames()
{
	if (window == top)
	{
		if (window.opener != null)
		{
			try
			{
				var sourceHref = window.opener.document.location.href.toLowerCase();
				var curHref = document.location.href.toLowerCase();
				sourceHref = sourceHref.substring(0, sourceHref.lastIndexOf("/"));
				curHref = curHref.substring(0, curHref.lastIndexOf("/"));
				
				if (curHref == sourceHref) // the opener is part of our app, so we don't want to redirect
					return;
			}
			catch (error)
			{
				// If opener is from a different site, we'll get a security error,
				// which proves it's okay to do the redirect.
			}
		}
		
		top.location.href = "default.aspx?dest=" + encodeURIComponent(document.location.href);
		return false;
	}
	return true;
}

// IE 5.5:		Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0)
// IE 6:		Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; .NET CLR 1.1.4322) 
// Mozilla 1.3:	Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.3) Gecko/20030312
//				Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.3.1) Gecko/20030425
// Netscape 7:	Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.0.2) Gecko/20030208 Netscape/7.02
//				Mozilla/5.0 (Macintosh; U; PPC; en-US; rv:1.0.2) Gecko/20030208 Netscape/7.02
//				Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.4) Gecko/20030624 Netscape/7.1 (ax)

	
var reIE = /MSIE (\d+\.?\d*)/;
var reMoz = /Mozilla\/5.0 \(.*? rv:(\d+\.\d+\.?\d*)[a-z]?\) Gecko\/[0-9]{8}( (Netscape)\/(\d+\.\d+\.?\d*))?/;
var browserName = "";
var browserVersion = 0;
var platform = "";

function getBrowserName()
{
	if (browserName == "")
		getBrowserAttributes();
	return browserName;
}

function getBrowserVersion()
{
	if (browserVersion == 0)
		getBrowserAttributes();
	return browserVersion;
}

function getBrowserAttributes()
{
	var agent = "" + window.navigator.userAgent;
	if (reIE.test(agent))
	{
		browserName = "IE";
		browserVersion = parseVersion(RegExp.$1);
	}
	else if (reMoz.test(agent))
	{
		if (RegExp.$3.length > 0)
		{
			browserName = "Netscape";
			browserVersion = parseVersion(RegExp.$4);
		}
		else
		{
			browserName = "Mozilla";
			browserVersion = parseVersion(RegExp.$1);
		}		
	}
}

function parseVersion(versionStr)
{
	var major = parseInt(versionStr.substring(0, versionStr.indexOf(".")), 10);
	var minor = parseFloat(versionStr.substr(versionStr.indexOf(".") + 1), 10) / 10;
	return major + minor;
}

function getPlatform()
{
	if (platform == "")
	{
		platform = "" + window.navigator.platform;
		if (platform.indexOf("Win") == 0)
		{
			platform = "Win";
		}
		else if (platform.indexOf("Mac") == 0)
		{
			var agent = "" + window.navigator.userAgent;
			platform = (agent.indexOf("Mac OS X") != -1 ? "MacOSX" : "Mac");
		}
	}
	return platform;
}

function topPos(el, abs)
{
	return doPosLoop(el, "Top", (abs ? true : false));
}

function leftPos(el, abs)
{
	return doPosLoop(el, "Left", (abs ? true : false));
}

function doPosLoop(el, val, abs)
{
	//TODO: abs allows for the override of the "not position absolute" check.
	// At some point we should test whether or not this test can or should be dropped.
	// If it must be here, we should change it to work against currentStyle.
	 
	if (el == null)
		return 0;

	var temp = el;
	var x = eval("temp.offset" + val);
	while (temp.offsetParent != null && 
		   temp.tagName != "BODY" && temp.tagName != "HTML" && 
		   (abs || temp.offsetParent.style.position != "absolute"))
	{
		temp = temp.offsetParent;
		x += eval("temp.offset" + val);
	}
	return x;
}

try
{
	if (!document.all)
	{
		// SET UP insertAdjacentHTML CLONE FOR NETSCAPE
		var globalRange = null;

		HTMLElement.prototype.insertAdjacentHTML = function(sWhere, sHTML)
		{
			var r = globalRange;
			
			if (r == null)
			{
				r = this.ownerDocument.createRange();
				globalRange = r;
			}
			
			// Calling setStartBefore and setStartAfter more than once on a given Range object
			// seems to cause an error: ([Exception... "Component returned failure code: 0x80070057 (NS_ERROR_ILLEGAL_VALUE) [nsIDOMRange.setStartBefore]")
			// Destroying the global cache seems to be the only way to fix this.
			
			switch (String(sWhere).toLowerCase()) // convert to string and unify case
			{
				case "beforebegin":
					try
					{
						r.setStartBefore(this);
						r.insertNode(r.createContextualFragment(sHTML));
					}
					catch (e)
					{
						r = null;
						globalRange = null;
						this.insertAdjacentHTML(sWhere, sHTML);
					}
					break;
			        
				case "afterbegin":
					try
					{
						r.selectNodeContents(this);
						r.collapse(true);
						r.insertNode(r.createContextualFragment(sHTML));
					}
					catch (e)
					{
						r = null;
						globalRange = null;
						this.insertAdjacentHTML(sWhere, sHTML);
					}
					
					break;
			         
				case "beforeend":
					try
					{
						r.selectNodeContents(this);
						r.collapse(false);
						r.insertNode(r.createContextualFragment(sHTML));
					}
					catch (e)
					{
						r = null;
						globalRange = null;
						this.insertAdjacentHTML(sWhere, sHTML);
					}
					break;
			         
				case "afterend":
					try
					{
						r.setStartAfter(this);
						r.insertNode(r.createContextualFragment(sHTML));
					}
					catch (e)
					{
						r = null;
						globalRange = null;
						this.insertAdjacentHTML(sWhere, sHTML);
					}
					break;
					
				default:
					throw new Error("Unknown insertion location: " + sWhere);
			}
		};
		
		// SET UP innerText CLONE FOR NETSCAPE
		function escapeHTML(htmlChar)
		{
			switch (htmlChar)
			{
				case "<":
					return "&lt;";
				case ">":
					return "&gt;";
				case "&":
					return "&amp;";
				default:
					return htmlChar;
			}
		}
		
		function escapePlus(value)
		{
			// Escape doesn't handle "+"!!!!
			// "+" must be escaped separately. The unicode value is 43, hex is %2B.
			var v = escape(value);
			return v.replace(/\+/g, "%2B");
			
			// IMPORTANT!!  If your using a IE 6.0 or Netscape 7.0 and above, then call the following.
			// encodeURIComponent(value);
		}
		
		HTMLElement.prototype.__defineSetter__("innerText", function(sText)
		{
			this.innerHTML = String(sText).replace(reHTML, escapeHTML);
		});
		
		HTMLElement.prototype.__defineGetter__("innerText", function()
		{
			var r = this.ownerDocument.createRange();
			r.selectNodeContents(this);
			return r.toString();
		});
		
		// SET UP READ-ONLY outerHTML CLONE FOR NETSCAPE
		var _emptyTags = {
			"IMG":   true,
			"BR":    true,
			"INPUT": true,
			"META":  true,
			"LINK":  true,
			"PARAM": true,
			"HR":    true
		};
		
		HTMLElement.prototype.__defineGetter__("outerHTML", function()
		{
			var attrs = this.attributes;
			var str = "<" + this.tagName;
			for (var i = 0; i < attrs.length; i++)
				str += " " + attrs[i].name + "=\"" + attrs[i].value + "\"";

			if (_emptyTags[this.tagName])
				return str + ">";

			return str + ">" + this.innerHTML + "</" + this.tagName + ">";
		});
		
		HTMLElement.prototype.all = function(sId)
		{
			var oId = null;
			if (this.hasChildNodes()) 
			{
				for (var i = 0; i < this.childNodes.length; i++) 
				{
					if (oId == null) {
						try 
						{
							if (this.childNodes[i].id == sId) 
							{
								oId = this.childNodes[i];
							}
							else if (this.childNodes[i].hasChildNodes()) 
							{
								oId = this.childNodes[i].all(sId);
							}
						} 
						catch(e) 
						{
						}
					}
				}
			}
			return oId;
		};
	}
}
catch (e)
{
	// IE 6 on WinXP SP2 sometimes gets "Permission Denied" on an attempt to access document.all,
	// but only after the user has pressed the browsers Refresh button.
	if (window === top)
		top.document.location.href = "default.aspx";
	else
		document.location.reload();
}

// MESSAGE WINDOW FOR TESTING
function writeMsg(m) 
{
	if (typeof(m) == "object")
	{
		m = extractProperties(m);
	}

	if (top.oMsgWin == null || top.oMsgWin.closed || top.oMsgWin.document == null) 
	{
		top.oMsgWin = window.open("", "MsgWin", "left=0,top=0,height=700,width=500,menubar=yes,scrollbars=yes,toolbar=no,location=no,resizable=yes");
		
		if (top.oMsgWin == null)
		{
			throw new Error("Popup windows are disabled. To enable the debug window, please add this web site to your popup exceptions list.");
		}
		
		addHandler(top, "onunload", function()
			{
				if (top.oMsgWin != null && !top.oMsgWin.closed)
					top.oMsgWin.close()
			});
		
		top.oMsgWin.document.open();
	}
	
	var output = new String();
	
	if (arguments[1] != null)
		output += "<b>" + arguments[1] + ":</b><br>";

	output += String(m).replace(reHTML, function($0)
		{
			switch ($0)
			{
				case "<":
					return "&lt;";
				case ">":
					return "&gt;";
				case "&":
					return "&amp;";
				case "\n":
					return "<br>";
				default:
					return $0;
			}
		});

	top.oMsgWin.document.writeln(output + "<br>");
	
	if (document.all) // IE
		top.oMsgWin.scrollBy(0, top.oMsgWin.document.documentElement.offsetHeight);
	else // Netscape
		top.oMsgWin.scrollBy(0, top.oMsgWin.innerHeight);
		
	//top.oMsgWin.document.close();
}

var reConstant = /^[A-Z0-9_]+$/;

function extractProperties(obj)
{
	var output = new String();
	
	for (var name in obj)
	{
		if (!reConstant.test(name))
		{
			var value = eval("obj." + name);
			var valueType = typeof(value);
			
			if (value == null)
			{
				output += name + " (" + valueType + "): " + value + "\n";
				continue;
			}
			
			switch (valueType)
			{
				case "function":
					break;
				
				case "object":
					output += (name + " ");
					if (typeof(value.toString) == "function" && value.toString().indexOf("HTML") != -1)
						output += value.toString() + ": " + value.tagName + (value.id != null && value.id.length > 0 ? " (" + value.id + ")" : "") + "\n";
					else
						try
						{
							output += "(" + valueType + "): " + value + "\n";
						}
						catch (err)
						{
							output += "(" + valueType + "): [Native Object]\n";
						}
					break;
					
				case "string":
					output += name + " (" + valueType + "): \"" + value + "\"\n";
					break;
			
				default:
					output += name + " (" + valueType + "): " + value + "\n";
					break;
			}
		}
	}
	
	return output;
}

function waitFor(strCmd)
{
	if (top.bComplete)
		eval(strCmd);
	else
		window.setTimeout("waitFor('" + strCmd + "')", 100);
}

function stringToIntArray(value)
{
	var arr = value.split(",");
	for (var i = 0; i < arr.length; i++)
	{
		arr[i] = parseInt(arr[i], 10);
	}
	return arr;	
}

function ellipsisTextOverflow(container)
{
	// This function can be used in netscape to add ellipsis to text overflow.
	// The container is expected to have a childNode that contains the actual text.
	var width = container.offsetWidth;
	var textSpan = container.childNodes[0];
	var text = textSpan.innerText;
	//writeMsg("container=" + container.tagName);
	//writeMsg("text=" + text + " width=" + width + " s=" + textSpan.offsetWidth);
	if (width < textSpan.offsetWidth)
	{
		var x = Math.round(width / textSpan.offsetWidth * text.length) - 3;
		while (width < textSpan.offsetWidth)
		{
			textSpan.innerText = text.substr(0, x--) + "...";
			//writeMsg("width=" + width + " span=" + textSpan.offsetWidth);
		}
	}	
}

/*** TODO: re-evaluate utility of all functions below this line. ***/

// Following two functions are for automatic lookup lists. TODO: move to behavior.

function doSelectChange(el,dest)
{
	  dest.value = el.options[el.selectedIndex].text;
}

function lookupItem(el,dest)
{
	var curValue = el.value.toLowerCase();
	if (curValue.length == 0)
	{
		dest.selectedIndex = -1;
		return;
	}
	
	var found = false;
	var index = dest.selectedIndex;
	var numOptions = dest.options.length;
	var pos = 0;
	while ((!found) && (pos < numOptions))
	{
		found = (dest.options[pos].text.toLowerCase().indexOf(curValue)==0); 
		if (found) 
			index = pos;
		pos++
	}
	if (found)
		dest.selectedIndex = index;
	else
		dest.selectedIndex = -1;
}

function doOnselectstart()
{
	// To use with IE attach this function to onselectstart.
	// To use with Netscape attach this function to mousedown.
	
	if (window.event != null)
	{
		// this is IE
		var source = window.event.srcElement;
		//writeMsg("doOnselectstart=" + source.id + " " + source.tagName);
		if ((source.tagName == "INPUT") || (source.tagName == "TEXTAREA"))
		{
			window.event.returnValue=true;
			window.event.cancelBubble = true;
		}
		else
		{
			window.event.returnValue=false;
			window.event.cancelBubble = true;
		}
	}
	else
	{
		// this is Netscape
		var event = arguments[0];
		var source = event.target;
		//writeMsg("doOnselectstart=" + source.tagName);
		if ((source.tagName != "INPUT") && (source.tagName != "TEXTAREA"))
		{
			event.preventDefault();
		}
	}
}


function colorRgbToHex(v) 
{
	// returns the hex representation of one byte (2 digits)
	function hex(d) 
	{
		return (d < 16) ? ("0" + d.toString(16)) : d.toString(16);
	};
	
	if (v.substr(0, 3) == "rgb") 
	{
		// in rgb(...) form -- Mozilla
		var re = /rgb\s*\(\s*([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\s*\)/;
		if (v.match(re)) {
			var r = parseInt(RegExp.$1);
			var g = parseInt(RegExp.$2);
			var b = parseInt(RegExp.$3);
			return ("#" + hex(r) + hex(g) + hex(b)).toUpperCase();
		}
		// doesn't match RE?!  maybe uses percentages or float numbers
		// -- FIXME: not yet implemented.
		return null;
	}

	// if everything else fails ;)
	return null;
}
