// Global Javascript Code
// 
// Herein lies all common code to all Manexa projects including BarAlliance
// Portal and AMS.

// BEGIN AddEvent --------------------------------------------------------------------------------

var ManexaDelegates = window.ManexaDelegates || new Object();		// don't define twice

function ManexaAddEvent(src, eventType, func) {
	if(typeof(func) == "undefined")
		return;
	if(typeof(func) == "string") {
		try {
			eval("func = function(){" + func + "}");
		}
		catch(ex){return;}
	}
	if(typeof(func) != "function")
		return;
	
	eventType = eventType.toLowerCase();
	if(ManexaDelegates[src] == null)
		ManexaDelegates[src] = new Object();
	if(ManexaDelegates[src][eventType] == null)
		ManexaDelegates[src][eventType] = new Array();
	
	var delegate = ManexaDelegates[src][eventType];
	delegate[delegate.length] =	func;
	
	if(eval("typeof(" + src + "." + eventType + ")") != "function")
		eval(src + "." + eventType + " = function(e){try{if(!e)e=event;}catch(ex){}return ManexaEvalDelegates('" + src + "', '" + eventType + "', e);}");
}

function ManexaEvalDelegates(src, eventType, e) {
	var funcs = ManexaDelegates[src][eventType];
	for(var i=0; i<funcs.length; i++) {
		if(funcs[i](e) == false) {
			stopEvent(e);
			return false;
		}
	}
	return true;
}

function stopEvent(e) {
	if (!e) var e = window.event;
	e.cancelBubble = true;
	if (e.stopPropagation) e.stopPropagation();
}

document.addevent = function(eventType, func) {
	ManexaAddEvent("document", eventType, func);
}

window.addevent = function(eventType, func) {
	ManexaAddEvent("window", eventType, func);
}

// END AddEvent ----------------------------------------------------------------------------------

// For dumping values to page
function jsDump ( astrString ) {

	// For AMS "Edit Item," this is the page header.
	if ( jsGetObj("Header_HeaderTable") !== null )
		jsGetObj("Header_HeaderTable").innerHTML += "<BR>\n" + astrString;

	// This <div> is commonly used.
	var oDivErrorMessage = jsGetObj ( "divErrorMessage" );
	if ( !! oDivErrorMessage ) oDivErrorMessage.innerHTML += "<BR>\n[" + astrString + "]";

	// Uses javascript console in FireFox.  Start w/:
	//		FireFox.exe -console
	// Note: this doesn't work on MSIE, so check for the function's existence
	if ( window.dump ) 
		dump ( "-> " + astrString + "\r\n" );
}

var isWindows = (navigator.userAgent.toLowerCase().indexOf("windows") != -1);
var isOpera = (navigator.userAgent.toLowerCase().indexOf("opera") != -1);
var isIE = (navigator.userAgent.toLowerCase().indexOf("msie") != -1 && !isOpera);
var isWindowsIE = (isWindows && isIE);

Array.prototype.indexOf = function(value) {
	for (var i = 0; i < this.length; i++) {
		if (this[i] == value)
			return i;
	}
	return -1;
}

String.prototype.startsWith = function(value, ignoreCase) {
	if (ignoreCase)
		return (this.substr(0, value.length) == value);
	else
		return (this.substr(0, value.length) == value);
}

String.prototype.endsWith = function(value, ignoreCase) {
	var L1 = this.length;
	var L2 = value.length;
	
	if (L2 > L1)
		return false;

	if (ignoreCase)
		return (L2 == 0 || this.toLowerCase().substr(L1 - L2, L2) == value.toLowerCase());
	else
		return (L2 == 0 || this.substr(L1 - L2, L2) == value);
}

String.prototype.remove = function(start, length) {
	var s = '';
	
	if (start > 0)
		s = this.substring(0, start);
	
	if (start + length < this.length)
		s += this.substring(start + length , this.length);
		
	return s;
}

String.prototype.trim = function() {
	return this.replace(/(^\s*)|(\s*$)/g, '');
}

String.prototype.ltrim = function() {
	return this.replace(/^\s*/g, '');
}

String.prototype.rtrim = function() {
	return this.replace(/\s*$/g, '');
}

String.prototype.formatPhoneNumber = function() {
	var phone = this.replace(/\D/g, "");
	switch (phone.length) {
		case 11:
			return phone.substr(1).formatPhoneNumber();
			
		case 10:
			return "(" + phone.substr(0, 3) + ")" + phone.substr(3, 3) + "-" + phone.substr(6);
			
		case 7:
			return phone.substr(0, 3) + "-" + phone.substr(3);
		
		default:
			return phone;
	}
}

Date.prototype.addDays = function(days) {
	return this.setTime(this.getTime() + days * 86400000);
}

Date.prototype.addMonths = function(months) {
	return this.setMonth(this.getMonth() + months);
}

Date.prototype.addYears = function(years) {
	return this.setFullYear(this.getFullYear() + years);
}

// Borrowed from Adam
function CreateNamedElement(tagName, elementName) {
	try {
		if(isIE)
			return document.createElement('<' + tagName + ' NAME="' + elementName + '" />');
		else {
			var obj = document.createElement(tagName);
			obj.name = elementName;
			return obj;
		}
	}
	catch(e){alert(e);throw e;}
}

// For use in validating, rounding, and otherwise cleaning up
// a money field.  
//		Appends trailing zeros to two decimal places.
//		Sets to 0.00 any values that are bad.
//		Doesn't allow negative numbers (but could)
function jsCleanMoney ( astrMoney ) {

	if ( ! astrMoney ) return "0.00";

	if ( typeof(astrMoney) != "string" ) astrMoney = astrMoney.toString();	

	// Gives a NaN if two or more dots
	var strMoney = (Math.round(astrMoney.replace( /[^\d\.-]/g, "" )*100)/100).toString();
	if ( ! strMoney || isNaN(strMoney) ) return "0.00";
	
	// Don't allow big money
	if ( strMoney.length > 14 ) strMoney = strMoney.substring(0,14);

	// Ensure padded with trailing zeros

	var intDotPosition = strMoney.indexOf(".");
	if ( intDotPosition > -1 ) {
		var intLength = strMoney.length;

		switch ( intLength - intDotPosition ) {
			case 3:
				// 4.21
				break;
			case 2:
				// 4.2
				strMoney += "0";
				break;
			case 1:
				// 4.
				strMoney += "00";
				break;
		}
	} else {
		// No dot
		strMoney += ".00";
	}
	return strMoney;
}

// This is a generic function that pulls querystring variables out of the QUERYSTRING
function jsGetQueryStringValue ( astrName ) {
	var strQueryString = null;
	var bolUseUpdateFrame = false;

	if ( arguments.length > 1 ) bolUseUpdateFrame = true;

	if ( bolUseUpdateFrame )
		strQueryString = updateFrame.window.location.search.substring(1);
	else
		strQueryString = top.window.location.search.substring(1);

	var arrPairs = strQueryString.split("&");
	for (var i=0;i<arrPairs.length;i++) {
		var arrPair = arrPairs[i].split("=");
		if (arrPair[0] == astrName) {
			return arrPair[1];
		}
	} 
	// It's not necessarily a problem if the querystring variable isn't found.
	// alert ('jsGetQueryStringValue(): ' + astrName + ' not found');
}

// reloads the page, updating a query string parameter's value if it already
// exists or creating a new query string parameter if it doesn't
function reloadPageWithParam(key, value) {
	// a regular expression to match a query string key-value pair
	var pat = new RegExp("([\?|&])(" + key + ")=?[^&]*", "");
	with (window.location) {
		if (search == "") // the query string is empty
			return search = "?" + key + "=" + value; // write key-value pair
		else if (search.match(pat) == null) // no matches found
			return search += "&" + key + "=" + value; // append key-value pair
		else // a match was found
			return search = search.replace(pat, "$1$2=" + value); // update the value
	}
}

// BEGIN QueryString Class --------------------------------------------------------

// A class to access the QueryString variables
//
// Example of use:
//		var iQS = new jscQueryString();
//		var strValue = iQS.values["homer"];
//	or
//		var strValue = iQS.values.homer;
//
// Example of use #2:
//		var iQS = new jscQueryString ( top.document.location.toString() );
//
function jscQueryString ( astrArgs ) {

	// properties
	this.values = new Object();		// store values in an array for easy access
	this.page = new String();		// original URL of page up to [?]

	this.parse = function ( astrQS ) {

		// This function is called by the constructor.  As such, it
		// has to be defined before calling it.  So, the constructor
		// is at the end of this class.

		// If not passed, get the actual QueryString
		if ( ! astrQS ) astrQS = window.location.search.substring(1);

		// Anything after the # doesn't concern me
		var intPos = astrQS.indexOf ("#");
		if ( intPos > -1 ) astrQS = astrQS.substring(0, intPos);

		// Whole QS passed?
		//if ( astrQS.indexOf("?") > -1 )
		var arrInitial = astrQS.split("?");
		if ( arrInitial.length > 1 ) {
			this.page = arrInitial[0];				// store for later
			astrQS = arrInitial[1];					// use this for QS
		}

		var arrPairs = astrQS.split("&");
		for (var i=0;i<arrPairs.length;i++) {
			var arrPair = arrPairs[i].split("=");
			this.values[arrPair[0]] = arrPair[1];
		}
	}

	this.insert = function (astrKey, astrValue) {
		// Inserts a pair into the array.  This would be
		// used, for example, in rebuilding a querystring w/
		// all paramaters, but ensuring that one has changed.

		// There is similar functionality in document.location.search.replace()

		// See if this parameter already exists
		var bolReplaced = false;
		for ( var strKey in this.values ) {
			if ( strKey == astrKey ) {
				this.values[strKey] = astrValue;
				bolReplaced = true;
				break;
			}
		}

		// If it wasn't replaced, then add it.
		if ( ! bolReplaced ) this.values[astrKey] = astrValue;
	}

	this.remove = function ( astrKey ) {
		// Removes a pair from the airray.

		for ( var strKey in this.values ) {
			if ( strKey == astrKey ) {
				delete this.values[strKey];
				break;
			}
		}
	}

	this.dump = function () {

		// For debugging or some such thing.
		var strResult = "";
		for ( var strKey in this.values ) {
			strResult += strKey + "=" + this.values[strKey] + "\n";
		}
		return strResult;
	}

	this.rebuild = function () {
		// This might be used after a few insert()'s to rebuild
		// the document.location string.
 
		var strResult = "";
		for ( var strKey in this.values ) {

			if ( strResult !== "" ) strResult += "&";
			strResult += strKey + "=" + this.values[strKey];
		}

		if ( this.page )
			return this.page + "?" + strResult;
		else
			return "?" + strResult;
	}

	// constructor logic
	this.parse(astrArgs);
}

// END QueryString Class --------------------------------------------------------

// This is to allow access to variables without added ClientID from C#.
// I would have rewritten the original getObj() function, but this function
// has been replicated on individual pages.  Nasty. -- Tone
var garrClientID = new Array();
var jsGetObjIdSeparator = ":";
function jsGetObj(astrObj) {
	var oReturn;
	var jsGetObjIdSeparatorRegex = eval("/\\" + jsGetObjIdSeparator + "/g");
	
	// To specify the ClientID on the server side, do the following:
	// 	if (!Page.IsPostBack) Manexa.General.AddJsClientID(this);	
	
	// 1st, if the browser supports getElementsByName, use this to find the object,
	// maintaining any array structure it may have, which getElementById does not do
	// N4 and IE4 do not support this method
	if (document.getElementsByName) {
		if (document.getElementsByName(astrObj).length > 1)
			return document.getElementsByName(astrObj);
		else if (document.getElementsByName(astrObj).length == 1)
			return document.getElementsByName(astrObj)[0];
		for (var i = garrClientID.length - 1; i > -1; i--) {
			if (document.getElementsByName(garrClientID[i] + jsGetObjIdSeparator + astrObj).length > 1)
				return document.getElementsByName(garrClientID[i] + jsGetObjIdSeparator + astrObj);
			else if (document.getElementsByName(garrClientID[i] + jsGetObjIdSeparator + astrObj).length == 1)
				return document.getElementsByName(garrClientID[i] + jsGetObjIdSeparator + astrObj)[0];
		}
	}
	
	// 2nd, check the collection of form objects for the existence of this ID,
	// also maintaining any array structure; though, Adam claims otherwise
	for (var i = 0; i < document.forms.length; i++) {
		if (document.forms[i][astrObj]) // ID was aptly named
			return document.forms[i][astrObj];
		else for (var j = garrClientID.length - 1; j > -1; j--) {
			oReturn = document.forms[i][garrClientID[j] + jsGetObjIdSeparator + astrObj];
			if (oReturn) return oReturn;				
		}
	}
	
	// 3rd, if the browser supports getElementById, use this to find the object
	// N4 and IE 4 do not support this method
	if (document.getElementById) {
		if (document.getElementById(astrObj)) // ID was aptly named
			return document.getElementById(astrObj);
		else for (var i = garrClientID.length - 1; i > -1; i--) {
			oReturn = document.getElementById(garrClientID[i].replace(jsGetObjIdSeparatorRegex, "_") + "_" + astrObj);
			if (oReturn) return oReturn;
		}
	}
	// Ineternet Explorer only
	if (document.all) {
		if (document.all[astrObj]) // ID was aptly named
			return document.all[astrObj];
		else for (var i = garrClientID.length - 1; i > -1; i--) {
			oReturn = document.all[garrClientID[i].replace(jsGetObjIdSeparatorRegex, "_") + "_" + astrObj];
			if (oReturn) return oReturn;
		}
	}
	// Netscape 4 only
	if (document.layers) {
		if (document.layers[astrObj]) // ID was aptly named
			return document.layers[astrObj];
		else for (var i = garrClientID.length - 1; i > -1; i--) {
			oReturn = document.layers[garrClientID[i].replace(jsGetObjIdSeparatorRegex, "_") + "_" + astrObj];
			if (oReturn) return oReturn;
		}
	}
	return null; // give up
}

// Gets the value for an object, regardless of the object type.
function jsObjGetValue(aobj_) {
	if (!aobj_) return null;
	if (aobj_.type) {
		if (aobj_.type == "checkbox")
			return aobj_.checked;
		else
			return aobj_.value;
	} else if (aobj_.length && aobj_[0].type && aobj_[0].type == "radio") {
		for (var i = 0; i < aobj_.length; i++) {
			if (aobj_[i].checked)
				return aobj_[i].value;
		}
	} else if (aobj_.childNodes && aobj_.childNodes.length == 1 && aobj_.firstChild.data) {
		return aobj_.firstChild.data;
	}
	return null;
}

// Sets the value of an object, regardless of the object type.
function jsObjSetValue(aobj_, aNewValue) {
	if (!aobj_) return (false);
	if (aobj_.type) {
		if (aobj_.type == "checkbox")
			aobj_.checked = aNewValue;
		else
			aobj_.value = aNewValue;
	} else if (aobj_.length && aobj_[0].type && aobj_[0].type == "radio") {
		for (var i = 0; i < aobj_.length; i++) {
			if (aobj_[i].value == aNewValue) {
				aobj_[i].checked = true;
				break;
			}
		}
	} else if (aobj_.childNodes && aobj_.childNodes.length) {
		while (aobj_.childNodes.length)
			aobj_.removeChild(aobj_.firstChild);
		aobj_.appendChild(document.createTextNode(aNewValue));
	} else if (!aobj_.firstChild) {
		aobj_.appendChild(document.createTextNode(aNewValue));
	} else {
		return (false);
	}
	return (true);
}

// BEGIN Dates Class ----------------------------------------------------------

// A class to do some date functions.
// Example use:
//		new jscDates().fixYear ( year );
function jscDates ( ) {

	// properties
	this.now = new Date();					// now for defaults

	this.fixYear = function ( aintYear ) {
		// Default to this year
		if ( aintYear == null ) aintYear = this.now.getYear();

		// Years come back in silly notation
		return aintYear + ((aintYear<2000)?1900:0);
	}
	
	this.fixMonth = function ( aintMonth ) {
		// Default to this month
		if ( aintMonth == null ) aintMonth = this.now.getMonth();

		return ( aintMonth + 1 );
	}

	this.getDate = function ( aintDate ) {
		// Default
		if ( aintDate == null ) aintDate = this.now.getDate();

		return ( aintDate );
	}

	this.getHours = function ( aintHours ) {
		// Default
		if ( aintHours == null ) aintHours = this.now.getHours();

		return ( aintHours );
	}

	this.getMinutes = function ( aintMinutes ) {
		// Default
		if ( aintMinutes == null ) aintMinutes = this.now.getMinutes();

		return ( aintMinutes );
	}

	this.getSeconds = function ( aintSeconds ) {
		// Default
		if ( aintSeconds == null ) aintSeconds = this.now.getSeconds();

		return ( aintSeconds );
	}

	this.shortDate = function ( aodte ) {
		// Always useful.

		// If we don't have anything, return nothing.  This is because we might send values from the db.
		// If these are empty or null, we don't want to return today.
		if ( aodte == null ) return null;

		return ( ( this.fixMonth ( aodte.getMonth() ) ) + "/" + aodte.getDate() + "/" + this.fixYear(aodte.getYear()) );
	}
	
	this.shortTime = function ( aodte ) {
		// Like shortDate, this returns just the time.

		// If we don't have anything, return nothing.  This is because we might send values from the db.
		if ( aodte == null ) return null;
		
		var intHours = aodte.getHours();
		var bolPM = ( intHours > 12 );
		if ( bolPM ) intHours -= 12;
		var strAmPm = ( bolPM ) ? " PM" : " AM";

		return ( intHours + ":" + jsPad ( aodte.getMinutes(), 2) ) + strAmPm;
	}
	
	this.getTextMonth = function ( astrMonth ) {
		// Given a month like 02, returns February
		
		if ( astrMonth ) {
			alert ( "jsGetTextMonth: No month passed." );
			return null;
		}
	
		oDaysInMonth = {	"m1":"January",
							"m2":"February",
							"m3":"March",
							"m4":"April",
							"m5":"May",
							"m6":"June",
							"m7":"July",
							"m8":"August",
							"m9":"September",
							"m10":"October",
							"m11":"November",
							"m12":"December" };
							
		if ( typeof astrMonth == "number" ) astrMonth = astrMonth.toString();
							
		// Lop leading zeroes
		while ( astrMonth.substring(0,1) == "0" ) astrMonth = astrMonth.substring(1);
	
		var strTextMonth;	
		eval ( "strTextMonth = oDaysInMonth.m" + astrMonth + ";" );
		return strTextMonth;
	}
	
	this.isDate = function ( adte ) {
		// Typically, this would be called from a textbox entry.
		// This isn't foolproof.  For example, 11/99/2006 works.
		// There are better ways requiring formats.  Search under Google.
		// One last approach is to do a Convert.ToDateTime() in C#, and
		// use a try/catch.

		var strDate = this.cleanDate ( adte );

		// Now the date uses "/" as a delimiter
		var datePattern = /^(\d{1,2})\/(\d{1,2})\/(\d{4})$/;
		var matchArray = strDate.match(datePattern);			// is the format ok?

		// Doesn't match MM/DD/YYYY pattern
		if ( matchArray == null ) return false;
		
		// Check month
		if ( matchArray[1] == null || matchArray[1] > 12 ) return false;
		
		// Check day
		if ( matchArray[2] == null || matchArray[2] > 31 ) return false;

		// Check year
		if ( matchArray[3] == null || matchArray[3] < 1900 || matchArray[3] > 2200 ) return false;

		var dte = new Date ( strDate );

		return ( dte != "Invalid Date" );
	}
	
	this.formatMessage = function ( abolHTML ) {
		var strSeparator = ( abolHTML ) ? "<BR>" : "\x0a";
		return ( "Dates must be in the format MM/DD/YYYY." + strSeparator + "The year must be between 1900 and 2200 A.D." );
	}
	
	this.cleanDate = function ( adte ) {

		var strDate = adte.toString();

		// First replace "-" with "/"
		strDate = strDate.replace ( /-/g, "/");

		// Ensure only digits and slashes.  Gets rid of spaces, too.
		strDate = strDate.replace ( /[^\d\/]/g, "" );
		
		return strDate;	
	}
}
// END Dates Class --------------------------------------------------------


// BEGIN Tooltips Class --------------------------------------------------------

// A class to make bigger, better tooltips.

// Creates a DIV with tooltip below and to the right of the control.
// I built this because SideTooltip won't work if there is no sidebar.
// See EditInvoice.ascx for example use.
function jscTooltips ( ) {

	// properties
	this.box = null;
	this.div = null;
	this.table = null;
	this.td = null;
	this.iframe = null;
	this.width = 300;							// 300px

	// Set in the onmouseover event
	this.MouseOver = function( aobj, astrTip ) {
		if ( this.box ) return;					// Don't run multiple times
		this.box = aobj;						// hold
		this.Show ( astrTip );
	}
	
	// Set in the onmouseout event
	this.MouseOut = function ( ) {
		this.Reset()
		//this.SetTimer();
	}
	
	this.Reset = function ( ) {
		if ( this.div )
			this.div.style.display = "none";
		if ( this.iframe )
			this.iframe.style.display = "none";

		this.box = null;
	}
	
	this.Show = function ( astrTip ) {
		// Creates a DIV with tooltip centered on the calling
		// control.  I built this because SideTooltip won't 
		// work if there is no sidebar.

		// Get the offsetParent.  This is the containing object.
		var oParent = this.box.offsetParent;

		// Create the <DIV>
		this.CreateDiv ( astrTip );

		// Gets the position of the [?] box
		var arrPosition = jsGetControlPosition ( this.box );
		var posLeft = arrPosition.left + arrPosition.width;
		var posTop = arrPosition.top + arrPosition.height;
		
		this.div.style.left = 0;
		this.div.style.top = 0;
		this.div.style.display = "";						// now show it
		
		// shrink the tool tip if the text width < this.width
		this.table.width = "";
		if (this.div.offsetWidth > this.width) {
			this.table.width = this.width;
		}
		
		// move the div so it stays within the viewable area
		var bodyHeight = top.document.body.offsetHeight;
		var bodyWidth = top.document.body.offsetWidth;
		var scrollTop = top.document.body.scrollTop;
		var scrollLeft = top.document.body.scrollLeft;
		
		if (posTop + this.div.offsetHeight > bodyHeight + scrollTop)
			posTop = bodyHeight - this.div.offsetHeight + scrollTop - 20;
		if (posTop < scrollTop) posTop = scrollTop;
		
		if (posLeft + this.div.offsetWidth > bodyWidth + scrollLeft)
			posLeft = bodyWidth - this.div.offsetWidth + scrollLeft - 20;
		if (posLeft < scrollLeft) posLeft = scrollLeft;
			
		this.div.style.left = posLeft + "px";
		this.div.style.top = posTop + "px";
		
		this.iframe.style.left = this.div.style.left;
		this.iframe.style.top = this.div.style.top;
		this.iframe.style.width = this.div.offsetWidth;
		this.iframe.style.height = this.div.offsetHeight;
		this.iframe.style.display = "";
	}
	
	this.CreateDiv = function ( astrTip ) {
	
		if (this.div != null) {
			this.td.innerHTML = astrTip;
		}
		else {
			// Creates the <div> that pops up.  This is modeled after
			// the regular tooltip using similar color.

			this.div = top.document.createElement("DIV");
			this.div.onclick = function () {
				// Provides a backdoor to get rid of the <div> just in case
				// it remains.  This happens, for example, on a popup if 
				// the tooltip is showing then the user hits enter, closing 
				// the popup.
				oTooltip.MouseOut();
			}

			// <table> for positioning
			this.table = top.document.createElement("TABLE");
			this.div.appendChild(this.table);
			
			var oTbody = top.document.createElement("TBODY");
			this.table.appendChild( oTbody );
			this.table.cellPadding = 2;
			this.table.cellSpacing = 0;
			this.table.width = this.width + "px";

			// <tr>
			var tr = oTbody.insertRow ( -1 );
			
			// <td>
			this.td = tr.insertCell ( -1 );
			this.td.innerHTML = astrTip;								// better than a text node because allows markup

			// Formatting and positioning
			this.div.style.display = "none";					// Start off hidden so screen doesn't flicker
			this.div.style.position = "absolute";				// must be absolute, or page jumps
			this.div.style.border = "1px solid gray";
			this.div.style.backgroundColor = "#ffffdd";				// the yellow of tooltips
			this.div.style.zIndex = "1000";
			
			if ( top.document.body.childNodes.length > 0 )
				top.document.body.insertBefore ( this.div, top.document.body.childNodes[0] );
			else 
				top.document.body.appendChild ( this.div );

			// Creates the <iframe> behind the div. In IE6  divs
			// are covered up by drop down lists and an iframe
			// just behind the div prevents that from happening.
			this.iframe = top.document.createElement("IFRAME");
			this.iframe.style.border = "0px";
			this.iframe.style.display = "none";
			this.iframe.style.position = "absolute";
			this.iframe.style.zIndex = "999";
			
			if ( top.document.body.childNodes.length > 0 )
				top.document.body.insertBefore ( this.iframe, top.document.body.childNodes[0] );
			else 
				top.document.body.appendChild ( this.iframe );
		}
	}
}
var oTooltip = new jscTooltips();
// END Tooltips Class -----------------------------------------------------

function jsRectangle ( aLeft, aTop, aWidth, aHeight ) {
	this.left = aLeft;
	this.top = aTop;
	this.width = aWidth;
	this.height = aHeight;
}

function jsGetControlPosition ( aobj ) {
	// Loop through all offset controls to get the position of
	// the calling object.
	var oControl = aobj;
	var intLeft = 0;
	var intTop = 0;
	while ( oControl != null ) {
		intLeft += oControl.offsetLeft;
		intTop += oControl.offsetTop;
		oControl = oControl.offsetParent;
	}

	return new jsRectangle(intLeft, intTop, aobj.offsetWidth, aobj.offsetHeight);
}

function jsPad( aValue, aintDigits ) {
	// Pads a number with zeroes; pads a string with spaces.

	var strReturn;
	var strPadWith;				// space or 0

	if ( aValue.constructor == Number ) {
		// A number was passed
		strReturn = aValue.toString();
		strPadWith = "0";
	} else {
		strReturn = aValue;
		strPadWith = " ";
	}

	while ( strReturn.length < aintDigits ) strReturn = strPadWith + strReturn;

	return strReturn;
}

// Class for compatibility issues
function jscCompatibility () {

	// Can't change the "type" of an Input field in IE, but can in FireFox.
	this.ToggleHiddenField = function ( aoInput ) {
		// Get the new type
		var strType = ( aoInput.type == "text" ) ? "hidden" : "text";

		// IE allows outerHTML; FireFox does not
		if ( aoInput.outerHTML )
			aoInput.outerHTML = "<input type='" + strType + "' id='" + aoInput.id + "' value='" + aoInput.value + "'>";
		else
			aoInput.type = strType;		// FireFox is nice and clean

		// focus() doesn't work in IE until we re-refernce the object.
		// It still doesn't "work," but at least now it doesn't error.
		var oInput = jsGetObj ( aoInput.id );
		return oInput;
	}
}
// Define the object
var Compatibility = new jscCompatibility();

// Gets any object's Y coordinate in the client area
function jsGetClientTop ( aobj_ ) {
	var ypos = 0;
	while ( aobj_.offsetParent != null ) { 
		ypos += aobj_.offsetTop;
		aobj_ = aobj_.offsetParent;
	}
	return (ypos == 0 && aobj_.style && aobj_.style.top) ? parseInt(aobj_.style.top) : ypos;
}

// Gets any object's X coordinate in the client area
function jsGetClientLeft ( aobj_ ) {
	var xpos = 0;
	while ( aobj_.offsetParent != null ) { 
		xpos += aobj_.offsetLeft;
		aobj_ = aobj_.offsetParent;
	}
	return (xpos == 0 && aobj_.style && aobj_.style.left) ? parseInt(aobj_.style.left) : xpos;
}

// Gets a particular style attribute value for specified selector and name
// For example, 
//		.required { color:red; }
//
//	astrSelectorName == ".required" 
//	astrStyleName == "color"
//
// Note that the selector name doesn't have to match the case, but the
// style name must have the right case, e.g. fontSize instead of fontsize
function jsGetStyleSheetAttribute ( astrSelectorName, astrStyleName ) {

	astrSelectorName = astrSelectorName.toLowerCase();

	var oStyleSheets = document.styleSheets;
	for ( var i = 0; i < oStyleSheets.length; i++ ) {
		var oCssRules = oStyleSheets[i].cssRules;				// Mozilla
		if ( ! oCssRules ) oCssRules = oStyleSheets[i].rules;	// IE

		for ( var j = 0; j < oCssRules.length; j++ ) {

			// Selector text is like body, table, td, etc.
			if ( oCssRules[j].selectorText ) {
				if ( oCssRules[j].selectorText.toLowerCase() == astrSelectorName ) {
					// Got it

					var oStyle = oCssRules[j].style;

					var strStyleValue;
					eval ( "strStyleValue = oStyle." + astrStyleName );

					return strStyleValue;
				}
			}
		}
	}
}

function jsGetElementById ( aoNode, astrID ) {
	// Given a node, look for a particular ID, then return the object.
	// This is like document.GetElementById(), but you can start at
	// any object.

	if ( ! aoNode ) return null;

	for ( var i in aoNode.childNodes ) {

		if ( typeof ( aoNode.childNodes[i] ) == "undefined" )
			continue;

		// Are there child nodes?
		if ( aoNode.childNodes[i].childNodes ) {
			if ( aoNode.childNodes[i].childNodes.length > 0 ) {

				// There are childNodes to be checked
				var oReturn = jsGetElementById ( aoNode.childNodes[i], astrID );
				if ( oReturn ) {
					return oReturn;
				}
			}
		}

		if ( aoNode.childNodes[i].id ) {
			if ( aoNode.childNodes[i].id == astrID ) 
				return aoNode.childNodes[i];
		}
	}
	
	return null;
}


function ParseAmount(obj) {
	var val = obj.value.replace(/[^\d.-]/g, "");
	if(val=="") val="0";
	val = parseFloat(val);
	if(isNaN(val)) {
		alert("Invalid Number");
		obj.select();
		return false;
	}
	else {
		obj.value=FormatAmount(val);
		return true;
	}
}


function FormatAmount(float) {
	return parseInt(float) + "." + parseInt(float*10)%10 + parseInt(float*100)%10;
}

// The "holding tank" concept is a means to pass data between popup windows.
// It creates a <div> on the parent page called "divHoldingTank".

// BEGIN HoldingTank Class -----------------------------------------------------------
function jscHoldingTank () {
	// The holding tank in a <div> that holds the hidden <div>s for preview.
	
	// Parameters
	this._HoldingTank = null;									// reference to the holding tank

	this.Build = function () {
		// builds if it doesn't exist, otherwise returns.

		// First try to get it
		this._HoldingTank = this.Get();
		if ( this._HoldingTank ) return this._HoldingTank;		// Don't keep building

		// Build it
		this._HoldingTank = top.document.createElement("DIV");
		this._HoldingTank.id = "divHoldingTank";
		this._HoldingTank.style.display = "";					// the tank is visible.  the contents may not be.
		if ( top.document.forms['main'] ) {
			top.document.forms['main'].appendChild(this._HoldingTank);	// Put inside the form in case when posting hidden fields
		} else {
			top.document.body.appendChild(this._HoldingTank);			// It has to go somewhere
		}
		return this._HoldingTank;
	}

	this.Get = function ( ) {
		// Gets reference to the holding tank
		
		// First try to get it internally
		if ( this._HoldingTank ) return this._HoldingTank;		// already have it

		// See if it is on the page somewhere
		this._HoldingTank = top.jsGetObj("divHoldingTank");		// Try to get reference to existing holding tank
		return ( this._HoldingTank );							// already have it
	}
	
	this.GetString = function ( astrId ) {
		// Used in conjunction with AddString().  

		for ( var i = 0; i < this._HoldingTank.childNodes.length; i++ ) {
			var oCurrent = this._HoldingTank.childNodes[i];
			if ( oCurrent.id == astrId ) return oCurrent.innerHTML;
		}
	}
	
	this.Keep = function ( astrId ) {
		// Pass in the ID to one of the controls inside the holding tank.
		// Loop through all controls, then keep only that one.

		// The holding tank contains controls.  They might be other <div>s
		// or hidden fields or whatever.
		for ( var i = 0; i < this._HoldingTank.childNodes.length; i++ ) {
			var oCurrent = this._HoldingTank.childNodes[i];
			if ( oCurrent.id == astrId ) {
				this.Clear();									// wipe all
				this._HoldingTank.appendChild(oCurrent);		// re-store this one
				break;											// done
			}
		}
	}
	
	this.Clear = function ( ) {
		// Wipes contents of the holding tank

		if ( this._HoldingTank ) this._HoldingTank.innerHTML = "";
	}
	
	this.Add = function ( aobj ) {
		// Passed an object such as a <div> or a hidden input

		if ( ! this._HoldingTank ) this.Build();				// ensure it exists

		this._HoldingTank.appendChild(aobj);					// tack it on
	}
	
	this.AddString = function ( astrId, astrValue ) {
		// Puts a string into a hidden <div>
	
		var oDiv = top.document.createElement("DIV");
		oDiv.id = astrId;
		oDiv.innerHTML = astrValue;
		oDiv.style.display = "none";
		this.Add ( oDiv );
	}
	
	this.AddHidden = function ( astrId, astrValue ) {
		// Builds a <input type="hidden" value=""> field.
		// These are useful if the final product is to post.
		
		var oHdn = top.document.createElement("INPUT");
		oHdn.type = "hidden";
		this.Add(oHdn);
		oHdn.id = astrId;
		oHdn.name = oHdn.id;
		oHdn.value = astrValue;
	
	}
	
	// Constructor
	this._HoldingTank = this.Get();								// get a reference
}

// END HoldingTank Class -------------------------------------------------------------

function jsIsEmail( astrEmailAddress ) {
	var strOK = "1234567890qwertyuiop[]asdfghjklzxcvbnm.@-_QWERTYUIOPASDFGHJKLZXCVBNM";

	// First check for appropriate characters
	for ( i=0; i < astrEmailAddress.length ;i++ ) {
		if ( strOK.indexOf(astrEmailAddress.charAt(i))<0 ) { 
			return (false);
		}	
	} 

	// If match works
	if (document.images) {

		// Shouldn't match these
		re = /(@.*@)|(\.\.)|(^\.)|(^@)|(@$)|(\.$)|(@\.)/;
		if ( astrEmailAddress.match(re) ) return false;

		// Should match this
		re_two = /^.+\@(\[?)[a-zA-Z0-9\-\.]+\.([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$/;
		if (! astrEmailAddress.match(re_two)) return false;		
	}

	return true;
}

// Class for popup error handling
// 
// I use the same method for showing errors on all Popups that I create.
// It assumes a <div>, generally toward the top of the page that has 
// appropriate styles of bold and brown (Jed hates red).
//
// Example creation:
// jsNotificationClone.Err = new jscPopupErrors ("divCloneErrorMessage");
//
// Example use:
// this.Err.show ( "The title for this Notification Type is required." );

// BEGIN PopupErrors Class -----------------------------------------------------------

function jscPopupErrors ( astrErrorContainer ) {
	this.div = null;
	this._strErrorContainer = astrErrorContainer;

	this.getdivref = function( astrErrorContainer ) {
		this.div = top.top.jsGetObj(this._strErrorContainer);
	}

	this.clear = function() {
		if ( ! this.div ) return;
		this.div.innerHTML = "";
	}
	
	this.show = function( astrErrorMessage ) {
		if ( ! this.div ) this.getdivref();
		this.div.innerHTML = astrErrorMessage;
		return false;								// so I can say: 'return jsWho.Err.show("");'
	}
}
// END PopupErrors Class -------------------------------------------------------------

// Events section
function getKeyCode(e) {
	if (!e) {
		//if the browser did not pass the event information to the
		//function, we will have to obtain it from the event register
		if (window.event) {
			//Internet Explorer
			e = window.event;
		} else {
			//total failure, we have no way of referencing the event
			return null;
		}
	}
	if (typeof(e.keyCode) == "number") {
		//DOM
		e = e.keyCode;
	} else if (typeof(e.which) == "number") {
		//NS 4 compatible
		e = e.which;
	} else if (typeof(e.charCode) == "number") {
		//also NS 6+, Mozilla 0.9+
		e = e.charCode;
	} else {
		//total failure, we have no way of obtaining the key code
		return null;
	}
	return e;
}
//End Events section
