///////////////////////////////////////////////////////////////////////////////
//                                                                           //
//                       Copyright (c) 2003-2006                             //
//                            Marc Peterson                                  //
//                     marc.s.peterson at gmail.com                          //
//                                                                           //
///////////////////////////////////////////////////////////////////////////////

// Last updated:
//   04-09-2007 - added isNum(), added "ends_with" to findChildrenById()
//   03-27-2007 - openNewWin() now return window object
//   09-27-2006 - openNewWin() now accepts an object of paramaters to set width, toolsbar, etc...
//   08-21-2006 - put "px" into moveLayer() top/left setting
//   08-15-2006 - made getWidth() getHeight() use offsetWidth/Height in Moz if "auto"
//   07-25-2006 - added setStatus() to set window status
//   06-21-2006 - checked for blanks in openNewWin()
//   06-17-2006 - added toggleDisplay()
//   06-29-2006 - added findInArray() to allow searches for elements in an array
//   06-26-2006 - improved how openNewWin() places popup with left/top
//   06-19-2006 - fixed bug in findChildrenById() that prevented nodes w/o id
//                from being evaluated
//   06-16-2006 - fixed concat bug in findChildrenById()
//   06-08-2006 - added x and y properties in openNewWin() to place popup. 
//                defaults to middle of window.
//   04-16-2006 - added prototypes pad() and trim()
//   04-16-2006 - cut-n-paste bug in setClass()

// PROTOTYPES
// String.prototype.pad(len, str, side)
// Number.prototype.pad(len, str, side)
// String.prototype.trim()

// openNewWin(path, id, paramaters)
// openHelpWin(path)
// openInParent(path)
// showLayer(layerID)
// hideLayer(layerID)
// moveLayer(layerID, x, y)
// getWidth(obj)
// getHeight(obj)
// findPosition(obj)
// setClass(dest, newClass)
// setDisplay(dest, vis)
// setStatus(status)
// toggleDisplay(dest)
// exists(var_name, obj)
// getElementStyle(obj, IEStyleProp, CSSStyleProp)
// findParentByTag(node, tag)
// findChildByTagAndId(node, tag, node_id, [compare_type])
// findChildrenById(node, node_id, [compare_type], [depth])
// endEventBubble(evt)
// deleteAllChildren(obj)
// getTbody(table_id, tbody_id)
// hasAttribute(obj, attribute)
// hasAttributeValue(obj, attribute, val)
// hex2dec(str)
// dec2hex(int, pad)
// int2str(int)
// strPad(str, len, pad_char, side)
// createElementEx(elem, attributes, styles)
// setElemAttrStyle(elem, attributes, styles)
// trim(str)
// trimQuotes(str)
// showError(title, msg, width)
// hideError()
// createVarName(str)
// isArray(obj)
// isNum(str)
// findInArray(obj, str)


// Global variables
var gRowColorDark	= "#EEF9FE";
var gRowColorLight	= "#ffffff";
var gIsWinLoaded	= false; 

// Attach load and unload events to the window.  These function set the gIsWinLoaded variable's state.
// This variable is used to allow/disallow scripts that needs the entire document to be loaded.  Helps
// reduce a few errors.
if ( window.addEventListener )
{
	// Moz
	window.addEventListener("load", bodyLoad, false);
	window.addEventListener("unload", bodyUnload, false);
}
else if ( document.attachEvent )
{
	// IE
	window.attachEvent("onload", bodyLoad);
	window.attachEvent("onunload", bodyUnload);
}


////////////////////////
// PROTOTYPES
////////////////////////

// len	- length of final string
// str	- string to use as padding
// side	- side to pad on: 0-left, 1-right, 2-both
String.prototype.pad = function(len, str, side)
{
	return str || (str = " "), (len -= this.length) > 0 ? (str = new Array(Math.ceil(len / str.length)
		+ 1).join(str)).substr(0, side = !side ? len : side == 1 ? 0 : Math.ceil(len / 2))
		+ this + str.substr(0, len - side) : this;
};

// If a number is padded, first convert it into a string
Number.prototype.pad = function(len, str, side)
{
	return this.toString().pad(len, str, side);
}

// Trims whitespace from both sides of a string
String.prototype.trim = function()
{
	return this.replace(/^\s*([^ ]*)\s*$/, "$1");
}


////////////////////////
// General Functions
////////////////////////

function bodyLoad()
{
	gIsWinLoaded = true;
}

function bodyUnload()
{
	gIsWinLoaded = false;
}


function openNewWin(path, id, paramaters)
{
	// For legacy code
	// if ( typeof(w) ) != "object" openNewWinOld(path, id, w);

	var params = new Array();

	// Setup default options
	params["width"]			= 200;
	params["height"]		= 200;
	params["left"]			= "half";
	params["top"]			= "half";
	params["scrollbars"]	= "auto";
	params["toolbar"]		= 0;
	params["status"]		= 1;
	params["resizable"]		= 1;

	if ( paramaters != null && paramaters != "" )
	{
		for ( var p in paramaters )
		{
			// allow some shortcuts
			if ( p == "w" ) params["width"]		= paramaters[p];
			else if ( p == "h" ) params["height"]	= paramaters[p];
			else if ( p == "t" ) params["top"]		= paramaters[p];
			else if ( p == "l" ) params["left"]		= paramaters[p];
			else params[p] = paramaters[p];
		}
	}

	// Determine position of window in case the default "half" is used
	if ( document.layers||(document.getElementById&&!document.all) )
	{
		browseWidth = window.outerWidth;
		browseHeight = window.outerHeight;
	}
	else if( document.all )
	{
		browseWidth = document.body.clientWidth;
		browseHeight = document.body.clientHeight;
	}
	if ( params["left"] == "half" ) params["left"]	= Math.floor((browseWidth-params["width"])/2);
	if ( params["top"] == "half" )  params["top"]	= Math.floor((browseHeight-params["height"])/2);

	// create the string of paramaters
	var str = "";
	for ( var p in params )
	{
		if ( str == "" ) str = p+"="+params[p];
		else str += ","+p+"="+params[p];
	}
	var new_win = window.open(path, id, str);
	return new_win;
}

/*
function openNewWinOld(path, id, w, h, x, y, scrollbars)
{

	if ( id === undefined || id == "" ) id = "_blank";
	if ( w === undefined || w == "" ) w = 200;
	if ( h === undefined || h == "" ) h = 200;
	if ( x === undefined || x == "" ) x = 'half';
	if ( y === undefined || y == "" ) y = 'half';
	if ( scrollbars === undefined || scrollbars == "" ) scrollbars = 'auto';

	if ( document.layers||(document.getElementById&&!document.all) )
	{
		browseWidth = window.outerWidth;
		browseHeight = window.outerHeight;
	}
	else if( document.all )
	{
		browseWidth = document.body.clientWidth;
		browseHeight = document.body.clientHeight;
	}

	if ( x == 'half' ) x = Math.floor((browseWidth-w)/2);
	if ( y == 'half' ) y = Math.floor((browseHeight-h)/2);

	var new_win = window.open(path, id, "width="+w+",height="+h+",scrollbars="+scrollbars+",resizable=yes,left="+x+",top="+y);
}
*/

function openHelpWin(path)
{
	return openNewWin(path, "helpWindow", {w:600, h:400});
}

function openInParent(path)
{
	if (top.opener)
	{
		if ( !top.opener.closed )
		{
			top.opener.location.href=path;
			top.opener.focus();
		}
		else
		{
			window.open (path);
			window.focus();
		}
	}
	else
	{
		alert ("Sorry, the page cannot be loaded because the parent window is no longer open");
	}
}


function showLayer(layerID)
{
	if ( document.getElementById )
	{
		// If a string, get the object
		if ( typeof(layerID) == "string" ) obj = document.getElementById(layerID);

		// If the object itself was passed
		else if ( typeof(layerID) == "object" ) obj = layerID;

		if ( obj ) obj.style.visibility = "visible";
	}
	// NS4
	else if ( document.layers ) document.layers[layerID].visibility = "show";
}

function hideLayer(layerID)
{
	if ( document.getElementById )
	{
		// If a string, get the object
		if ( typeof(layerID) == "string" ) obj = document.getElementById(layerID);

		// If the object itself was passed
		else if ( typeof(layerID) == "object" ) obj = layerID;

		if ( obj ) obj.style.visibility = "hidden";
	}
	// NS4
	else if ( document.layers ) document.layers[layerID].visibility = "hidden";
}

function moveLayer(layerID, x, y)
{
	var obj = null;

	if ( document.getElementById )
	{
		// If a string, get the object
		if ( typeof(layerID) == "string" ) obj = document.getElementById(layerID);

		// If the object itself was passed
		else if ( typeof(layerID) == "object" ) obj = layerID;

		if ( obj )
		{
			if ( x != null ) obj.style.left = x+"px";
			if ( y != null ) obj.style.top = y+"px";
		}
	}
	// NS4
	else if ( document.layers ) document.layers[layerID].moveTo(x,y);
}

// Get the width of an object
function getWidth(obj)
{
	var width = null;

	if ( document.getElementById )
	{
		// If the ID was passed, find the object
		if ( typeof(obj) == "string" )
		{
			obj = document.getElementById(obj);
		}

		if ( typeof(obj) == "object" )
		{
			width = getElementStyle(obj, "width", "width");

			if ( width == "auto" && document.all ) width = obj.clientWidth;		// IE
			else if ( width == "auto" ) width = obj.offsetWidth;				// MOZ
	
			width = parseInt(width);
		}
	}
	return width;
}

// Get the height of an object
function getHeight(obj)
{
	var height = null;

	if ( document.getElementById )
	{
		// If the ID was passed, find the object
		if ( typeof(obj) == "string" )
		{
			obj = document.getElementById(obj);
		}

		if ( typeof(obj) == "object" )
		{
			height = getElementStyle(obj, "height", "height");
	
			if ( height == "auto" && document.all ) height = obj.clientHeight;	// IE
			else if ( height == "auto" ) height = obj.offsetHeight;				// Moz
	
			height = parseInt(height);
		}
	}
	return height;
}

// Determines an object's screen positin by looking at all of its parents positions
function findPosition(obj)
{
	var ret_obj = new Object;
	if ( obj.offsetParent )
	{
		for (var pos_x = 0, pos_y = 0; obj.offsetParent; obj = obj.offsetParent)
		{
			pos_x += obj.offsetLeft;
			pos_y += obj.offsetTop;
		}
		ret_obj.x = pos_x;
		ret_obj.y = pos_y;
		return ret_obj;
	}
	else
	{
		ret_obj.x = obj.x;
		ret_obj.y = obj.y;
		return ret_obj;
	}
}

function setClass(dest, newClass)
{
	var obj = null;

	if ( document.getElementById )
	{
		// If an object, set its class directly
		if ( typeof(dest) == "object" ) dest.className = newClass;

		// If a string, get the object and set its class
		else if ( typeof(dest) == "string" )
		{
			if ( obj = document.getElementById(dest) ) obj.className = newClass;
		}
	}
}

function setDisplay(dest, vis)
{
	var obj = null;

	if ( document.getElementById )
	{
		// If an object, set its display directly
		if ( typeof(dest) == "object" ) dest.style.display = vis;

		// If a string, get the object and set its display
		else if ( typeof(dest) == "string" )
		{
			if ( obj = document.getElementById(dest) ) obj.style.display = vis;
		}
	}
}

function setStatus(status)
{
	window.status = status;
	return true;
}



function toggleDisplay(dest)
{
	var obj = null;

	if ( document.getElementById )
	{
		// If a string, get the object and set its display
		if ( typeof(dest) == "string" ) dest = document.getElementById(dest);

		if ( dest )
		{
			if ( dest.style.display == "none" ) setDisplay(dest, "block");
			else setDisplay(dest, "none");
		}
		else alert("dest does not exist");		// DEBUG
	}
}

// Determines if a variable exists.
//   Variables:
//     var_name     the name of the variable to check for
//     [obj]        optional object to check if the variable exists within.  defaults to the window object.
function exists(var_name, obj)
{
	if ( typeof(obj) != "undefined" )					// If an object was defined
	{
		if ( var_name in obj ) return true;				// See if variable exists within that object
		else return false;
	}
	else if ( var_name in window ) return true;			// Otherwise see if the variable exists within the window object
	else return false;
}

// Gets an element's style assigned via a stylesheet or link
function getElementStyle(obj, IEStyleProp, CSSStyleProp)
{
	if ( document.getElementById )
	{
		// If the ID was passed, find the object
		if ( typeof(obj) == "string" )
		{
			obj = document.getElementById(obj);
		}
	
		if ( obj.currentStyle )
		{
			return obj.currentStyle[IEStyleProp];
		}
		else if ( window.getComputedStyle )
		{
			var compStyle = window.getComputedStyle(obj, "");
			return compStyle.getPropertyValue(CSSStyleProp);
		}
	}
	return "";
}

// Finds the first parent of the passed node with the given tag
// tag should be a node name such as TABLE, TR, TD, etc...
// returns the node if found, null otherwise
function findParentByTag(node, tag)
{
	var cur_node = node;
	tag = tag.toUpperCase();

	while ( cur_node && cur_node.nodeName != tag )
	{
		if ( cur_node.parentNode ) cur_node = cur_node.parentNode;
		else return null;
	}

	if ( cur_node && cur_node.nodeName == tag ) return cur_node;
	else return null;
}

// Finds the first child node of the given tag type with the given id.
// If the node does not have an id, then the name will be checked.
// Returns the node if found, null otherwise
//  [compare_type] is optional.  It determines how the ids are compared.
//    undefined = "equal" - the ids must match completely
//    "starts_with"       - the id must begin with the node_id value
function findChildByTagAndId(node, tag, node_id, compare_type)
{
	if ( compare_type === undefined ) compare_type = "equals";
	else compare_type = trim(compare_type.toLowerCase());

	if ( document.getElementById )
	{
		var nodes = node.getElementsByTagName(tag);
		for ( var i=0; i<nodes.length; i++ )
		{
			if ( nodes[i].id || nodes[i].name )
			{
				switch (compare_type)
				{
					case "starts_with":
						if ( (nodes[i].id && nodes[i].id.indexOf(node_id) == 0) || (nodes[i].name && nodes[i].name.indexOf(node_id) == 0) )
						{
							return nodes[i];
							break;
						}
					case "equals":
					default:
						if ( (nodes[i].id && nodes[i].id == node_id) || (nodes[i].name && nodes[i].name == node_id) )
						{
							return nodes[i];
							break;
						}
				}
			}
		}
	}
	return null;
}

// Finds the children nodes of the given parent node with the given id.
// If the nodes do not have an id, then their names will be checked.
// Returns an array of nodes if found, null otherwise.
//  [depth] is how deep in the tree to look.  If undefined, then no limit.
//  [compare_type] is optional.  It determines how the ids are compared.
//    undefined = "equal" - the ids must match completely
//    "starts_with"       - the id must begin with the node_id value
function findChildrenById(node, node_id, compare_type, depth)
{
	var results = new Array();

	if ( compare_type === undefined ) compare_type = "equals";
	else compare_type = trim(compare_type.toLowerCase());

	if ( depth === undefined ) depth = -1;
	else if ( depth > 0 ) depth--;

	if ( !node.hasChildNodes() ) return null;
	else
	{
		var child = node.firstChild;
		while (child != null )
		{
			if ( child.id || child.name )
			{
				switch (compare_type)
				{
					case "starts_with":
						if ( (child.id && child.id.indexOf(node_id) == 0) || (child.name && child.name.indexOf(node_id) == 0) )
						{
							results[results.length] = child;
							break;
						}
					case "ends_with":
						if ( (child.id && child.id.lastIndexOf(node_id) == (child.id.length - node_id.length))
						  || (child.name && child.name.lastIndexOf(node_id) == (child.name.length - node_id.length)) )
						{
							results[results.length] = child;
							break;
						}
					case "equals":
					default:
						if ( (child.id && child.id == node_id) || (child.name && child.name == node_id) )
						{
							results[results.length] = child;
							break;
						}
				}
			}
			if ( child.hasChildNodes() && depth != 0 )
			{
				results = results.concat(findChildrenById(child, node_id, compare_type, depth));
			}
			child = child.nextSibling;
		}
		return results;
	}
}


// Finds the first input under the given node node with the passed type and with the given name
// Returns the input if found, null otherwise
//  [compare_type] is optional.  It determines how the ids are compared.
//    undefined = "equal" - the ids must match completely
//    "begins_with"       - the id must begin with the node_id value
function findInputByTypeAndName(node, type, name, compare_type, debug)
{
	if ( compare_type === undefined ) compare_type = "equals";
	else compare_type = trim(compare_type.toLowerCase());

	if ( document.getElementById )
	{
		var oInputs = node.getElementsByTagName("input");
		if ( debug ) alert(oInputs.length+" inputs found in this node");
		for ( var i=0; i<oInputs.length; i++ )
		{
			if ( oInputs[i].type == type )
			{
				switch (compare_type)
				{
					case "starts_with":
						if ( oInputs[i].name.indexOf(name) == 0 )
						{
							if ( debug ) alert("found input "+oInputs[i].name+" of type "+oInputs[i].type);
							return oInputs[i];
							break;
						}
					case "equals":
					default:
						if ( oInputs[i].name == name )
						{
							return oInputs[i];
							break;
						}
				}
			}
		}
	}
	return null;
}


// Prevents an event from bubbling up any more.  Used on elements that catch an event (onclick),
// use the event, and want the event from not being applied to any containing elements that have 
// an event handler.
function endEventBubble(evt)
{
	var evt = (evt) ? evt : ((window.event) ? event : null);
	evt.cancelBubble = true;
}

// Deletes all children in a given element
function deleteAllChildren(obj)
{
	if ( obj )
	{
		while (obj.hasChildNodes())
		{
			obj.removeChild(obj.firstChild);
		}
	}
}

// Given the table id, return the tbody with the given id
function getTbody(table_id, tbody_id)
{
	var oTable = null;
	var oTbody = null;

	var oTable = document.getElementById(table_id);

	// If table was not found, exit
	if ( !oTable ) return null;

	// Find the tbody
	oTbody = findChildByTagAndId(oTable, "TBODY", tbody_id)

	// If tbody was not found, exit
	if ( !oTbody ) return null;
	else return oTbody;
}

// Custom hasAttribute function since Moz supports it and IE6 does not
function hasAttribute(obj, attribute)
{
	if ( obj.hasAttribute ) return obj.hasAttribute(attribute);
	else if ( obj.getAttribute )
	{
		var value = obj.getAttribute(attribute);
		if ( value == null ) return false;
		else return true;
	}
	else return false;
}

// Returns true if the object has the given attribute with the given value.  False
// if the attriute does not exist or if the value is different.
function hasAttributeValue(obj, attribute, val)
{
	if ( obj.getAttribute )
	{
		var value = obj.getAttribute(attribute);
		if ( value == null ) return false;
		else
		{
			if ( typeof val == "number" )
			{
				if ( parseInt(value) == val ) return true;
				else return false;
			}
			else if ( typeof val == "string" )
			{
				if ( value.toLowerCase() == val.toLowerCase() ) return true;
				else return false;
			}
		}
	}
	else return false;
}

// Takes a hexidecimal number and returns a decimal
function hex2dec(hex)
{
	return parseInt(hex,16);
}

// Takes a decimal number and returns a hexidecimal.
// VARIABLES
//   dec		decimal number to convert
//   [pad]		optional number of zeros "0" to pad on left of returned hex number
function dec2hex(dec, pad)
{
	var hex = Number(dec).toString(16);
	if ( pad !== undefined ) hex = strPad(hex, pad, "0", "left")
	return hex;
}

// Converts an integer to a string
function int2str(num)
{
	num += "";
	return num;
}


function strPad(str, len, pad_char, side)
{
	if ( len === undefined ) len = 0;
	if ( pad_char === undefined || pad_char == "" ) pad_char = " ";
	if ( side === undefined || side == "" ) side = "left";
	else side.toLowerCase();

	var chars_to_pad = len - str.length;
	if ( chars_to_pad > 0 )
	{
		for (var i=0; i<chars_to_pad; i++)
		{
			if ( side == "left" ) str = pad_char+str;
			else str += pad_char;
		}
	}
	return str;
}

function createElementEx(type, attributes, styles)
{
	var elem = document.createElement(type);
	return setElemAttrStyle(elem, attributes, styles);
}

function setElemAttrStyle(elem, attributes, styles)
{
	if ( elem )
	{
		if ( attributes != null && attributes != "" )
		{
			for ( var attr_name in attributes )
			{
				if ( attr_name == "className" ) elem.className = attributes[attr_name];
				else if ( attr_name == "innerHTML" ) elem.innerHTML = attributes[attr_name];
				else elem.setAttribute(attr_name, attributes[attr_name]);
			}
		}

		if ( styles !== undefined && styles != null && styles != "" )
		{
			for ( var style_name in styles )
			{
				elem.style[style_name] = styles[style_name];
			}
		}
		return elem;
	}
	else return null
}

// This function is also in forms.js
// Strip whitespace (space, tabs) from the beginning and end of a string
function trim(txt)
{
	// Handle special cases
	if ( !txt || txt == "" || txt == null || txt === undefined) return "";
	else
	{
		txt = txt.replace(/^[\s\t]*/, "");
		txt = txt.replace(/[\s\t]*$/, "");
		return txt;
	}
}

// Removes quotes " from beginning and end of a string
function trimQuotes(txt)
{
	if ( !txt || txt == "" || txt == null || txt === undefined) return "";
	else
	{
		txt = txt.replace(/^["']/, "");
		txt = txt.replace(/["']$/, "");
		return txt;
	}
}

function showError(title, msg, width)
{
	var error_box = document.getElementById("error_box");
	if ( !error_box )
	{
		var error_box = document.createElement("div");
		error_box.id = "error_box";
		document.body.appendChild(error_box);
	}

	if ( width !== undefined ) error_box.style.width = width;
	moveLayer(error_box, gMouse.x+15, gMouse.y);
	showLayer(error_box);
	error_box.innerHTML = "<div class='title'>"+title+"</div><div class='content'>"+msg+"</div>";
	error_box.innerHTML += "<div class='close' onclick='hideError();'>close</div>";
}

function hideError()
{
	var error_box = document.getElementById("error_box");
	if ( error_box )
	{
		hideLayer(error_box);
	}
}

// Takes a string and converts into a variable name usable in JavaScript.
// All letters and numbers are valid.  The result is all lowecase.  All spaces " " are
// converted to "_".  All other characters are skipped.
function createVarName(txt)
{
	var good = "_0123456789abcdefghijklmnopqrstuvwxyz ";

	var var_name = "";											// Clear variable name
	var txt_lc = trim(txt.toLowerCase());						// Trim and convert to lowercase
	for (var i=0; i<txt_lc.length; i++)						// Traverse the entire key string
	{
		cur_char = txt_lc.charAt(i);							//   Get a character
		if ( good.indexOf(cur_char) != -1 )						//   If the character is good
		{
			if ( cur_char == " " ) cur_char = "_";				//     Convert spaces to "_"
			var_name += cur_char;								//     Append this character to the variable name
		}
	}
	return var_name;
}

function isArray(obj)
{
	return( typeof(obj.length) == "undefined" ) ? false : true;
}

// Determine is a variable contains a number or not
function isNum(i)
{
	if ( i == parseInt(i) ) return true;
	else return false;
}


// Needed since IE doesn't support array.indexOf()
function findInArray(searchArray, searchElement, fromIndex)
{
	var i = (fromIndex < 0) ? searchArray.length+fromIndex : fromIndex || 0;
	for(;i<searchArray.length;i++)
		if(searchElement === searchArray[i]) return i;
	return -1
};
