
/*
* Copyright 2007-2010 Tandem Games
* Aaron Murray
* aaron@tandemgames.com
* 
* */


//Since parameters to functions in JS are optional, 
//it is good practice to call IsValidInstance() on the param before using it
//to test it's existance and possibly set a default value on it.

/* 
    typeof(x) notes
    Type	            Result
    Undefined	        "undefined"
    Null	            "object"
    Boolean	            "boolean"
    Number	            "number"
    String	            "string"
    E4X XML object	    "xml"
    E4X XMLList object	"xml"
    Host object (provided by the JS environment)	Implementation-dependent
    Function object (implements [[Call]])	"function"
    Any other object	"object"
*/

//--- debug variables ---
var DEBUG_ENABLED = false; //turns on/off extra debugging code (alerts, window.status, etc)

//flags for key press events
var __special__shift = false;
var __special__alt = false;
var __special__ctrl = false;
var __special__arrow_up = false;
var __special__arrow_down = false;
var __special__arrow_left = false;
var __special__arrow_right = false;
var __special__pause = false;
var __special__space = false;





// --------------------------------------------------------------------------------------
// -- EVENTS ----------------------------------------------------------------------------
// --------------------------------------------------------------------------------------


document.onkeyup = KeyUp; //register the KeyUp() function




/* ================================================================== */
/*                                                                    */
/* ! OS and Modern Browser Check */
/*                                                                    */
/*   for Mac OS X, iPhone OS and Windows                              */
/*       Safari, Chrome, Firefox, Opera and Internet Explorer         */
/*                                                                    */
/* ------------------------------------------------------------------
*
*    How to get OS Name:
*       alert(_ua.os.name);
*
*    How to get OS Version (except "Opera" in Mac):
*       alert(_ua.os.name);
*
*    How to get Browser Name:
*       alert(_ua.browser.name);
*
*    How to get Browser Version:
*       alert(_ua.browser.ver);
*
* =================================================================== */

var _ua = new Object();

_ua.str = navigator.userAgent.toUpperCase();
_ua.os = {};
_ua.browser = {};

if (_ua.str.indexOf("MACINTOSH") >= 0) {
    _ua.os.name = "Mac";
    if (_ua.str.indexOf("MAC OS X ") >= 0) {
        _ua.os.ver = _ua.str.match(/MAC OS X [0-9_.]*/).toString().substr(9, 4).replace(/_/g, ".");
    }
}
else if (_ua.str.indexOf("IPHONE") >= 0) {
    _ua.os.name = "iPhone";
    if (_ua.str.indexOf("IPHONE OS ") >= 0) {
        _ua.os.ver = _ua.str.match(/IPHONE OS [0-9_.]*/).toString().substr(10, 3).replace(/_/g, ".");
    }
}
else if (_ua.str.indexOf("IPOD") >= 0) {
    _ua.os.name = "iPod touch";
    if (_ua.str.indexOf("IPHONE OS ") >= 0) {
        _ua.os.ver = _ua.str.match(/IPHONE OS [0-9_.]*/).toString().substr(10, 3).replace(/_/g, ".");
    }
}
else if (_ua.str.indexOf("WINDOWS") >= 0) {
    _ua.os.name = "Windows";
    if (_ua.str.indexOf("WINDOWS NT 5.1") >= 0) _ua.os.ver = "XP";
    if (_ua.str.indexOf("WINDOWS NT 6.0") >= 0) _ua.os.ver = "Vista";
    if (_ua.str.indexOf("WINDOWS NT 6.1") >= 0) _ua.os.ver = "7";
}


if (_ua.str.indexOf("CHROME") >= 0) {
    _ua.browser.name = "Chrome";
    _ua.browser.ver = _ua.str.match(/CHROME\/[0-9_.]*/).toString().substr(7, 3);
}
else if (_ua.str.indexOf("IPHONE") >= 0 && _ua.str.indexOf("SAFARI") >= 0) {
    _ua.browser.name = "Mobile Safari";
    _ua.browser.ver = _ua.str.match(/VERSION\/[0-9_.]*/).toString().substr(8);
}
else if (_ua.str.indexOf("IPOD") >= 0 && _ua.str.indexOf("SAFARI") >= 0) {
    _ua.browser.name = "Mobile Safari";
    _ua.browser.ver = _ua.str.match(/VERSION\/[0-9_.]*/).toString().substr(8);
}
else if (_ua.str.indexOf("SAFARI") >= 0) {
    _ua.browser.name = "Safari";
    _ua.browser.ver = _ua.str.match(/VERSION\/[0-9_.]*/).toString().substr(8);
}
else if (_ua.str.indexOf("FIREFOX") >= 0) {
    _ua.browser.name = "Firefox";
    _ua.browser.ver = _ua.str.match(/FIREFOX\/[0-9_.]*/).toString().substr(8, 3);
}
else if (_ua.str.indexOf("OPERA") >= 0) {
    _ua.browser.name = "Opera";
    _ua.browser.ver = _ua.str.match(/VERSION\/[0-9_.]*/).toString().substr(8);
}
else if (_ua.str.indexOf("MSIE") >= 0) {
    _ua.browser.name = "IE";
    if (_ua.str.indexOf("MSIE 5.0") >= 0) _ua.browser.ver = "5.0";
    if (_ua.str.indexOf("MSIE 5.5") >= 0) _ua.browser.ver = "5.5";
    if (_ua.str.indexOf("MSIE 6.0") >= 0) _ua.browser.ver = "6.0";
    if (_ua.str.indexOf("MSIE 7.0") >= 0) _ua.browser.ver = "7.0";
    if (_ua.str.indexOf("MSIE 8.0") >= 0) _ua.browser.ver = "8.0";
}





// --------------------------------------------------------------------------------------
// -- AJAX / XML ------------------------------------------------------------------------
// --------------------------------------------------------------------------------------


//Creating, setting, and returning a XMLHTTP Request object 
function CreateXmlHttp() { //this takes nearly 1ms to run
return new XMLHttpRequest; //see XMLHttpRequest.js
//    if (typeof XMLHttpRequest != "undefined") {
//        return new XMLHttpRequest();
//    } else if (typeof ActiveXObject != "undefined") {
//        return new ActiveXObject("Microsoft.XMLHTTP");
//    } else {
//        throw new Error("XMLHttpRequest not supported");
//    }
}

var _GetXmlDocCounter = 0;
function GetXmlDoc(pXmlString) { //WARNING: this method takes an entire 1ms to run (brutal in loops)
//this works...but are we creating a useless doc on the first line?
//    var oDomDoc = Sarissa.getDomDocument();
//    oDomDoc = (new DOMParser()).parseFromString(pXmlString, "text/xml");
//    return oDomDoc;
_GetXmlDocCounter++;
//window.status = "GetXmlDoc() called " + _GetXmlDocCounter + " times. Stack Trace: " + getStackTrace(arguments.callee);
    
var oDomDoc = (new DOMParser()).parseFromString(pXmlString, "text/xml");
return oDomDoc;
}


function SelectSingleNode(pParentNode, pNodePath)
{
if (!pParentNode) return null;
var ownerDocument = (pParentNode.ownerDocument ? pParentNode.ownerDocument : pParentNode)
ownerDocument.setProperty("SelectionLanguage", "XPath"); //required for Sarissa's selectSingleNode() to work
return pParentNode.selectSingleNode(pNodePath);
}

function GetNodeText(pNode, pPath) {
return getInnerText(SelectSingleNode(pNode, pPath));
}

function GetAttributeValue(pNode, pAttributeName) {
return pNode.attributes.getNamedItem(pAttributeName).value;
}

// --------------------------------------------------------------------------------------
// -- DATE / TIME METHODS ---------------------------------------------------------------
// --------------------------------------------------------------------------------------


//returns ms diff between a start date and now
function getElapsedTime(pDateStartInMs) {
    // sets difference date to difference of first date and second date
    return (new Date().getTime() - pDateStartInMs);
}


// --------------------------------------------------------------------------------------
// -- KEYPRESS STUFF --------------------------------------------------------------------
// --------------------------------------------------------------------------------------

function isEnterKeyPress(pCharCode, pTarget)
{
return ((pCharCode == 13) && (pTarget.nodeName != 'TEXTAREA'));
}




// --------------------------------------------------------------------------------------
// -- EVENT STUFF -----------------------------------------------------------------------
// --------------------------------------------------------------------------------------

/// Wrapper method to abstract adding events in different browsers.
/// pEventName should not include the prefix "on".
function AttachEvent(pObject, pEventName, pEventHandler)
{
if (!pObject)
{
dalert ("Null pObject in AttachEvent");
return;
}
    
if (!IsValidInstance(pEventHandler))
{
dalert ("Empty pEventHandler in AttachEvent");
return;
}
    
if (pObject.addEventListener){ pObject.addEventListener(pEventName,pEventHandler,true); return true; }
else if (pObject.attachEvent){ return pObject.attachEvent("on"+pEventName,pEventHandler); }
else { return false; }
}

/// Wrapper method to abstract removing events in different browsers.
/// pEventName should not include the prefix "on".
function DetachEvent(pObject, pEventName, pEventHandler)
{
if (pObject.removeEventListener){ pObject.removeEventListener(pEventName,pEventHandler,false); return true; }
else if (pObject.detachEvent){ return pObject.detachEvent("on"+pEventName,pEventHandler); }
else { return false; }
}



// --------------------------------------------------------------------------------------
// -- UTILITY METHODS -------------------------------------------------------------------
// --------------------------------------------------------------------------------------

function goTo(link){
location.href=link;
}

function ReloadPage(pMsDelay) {
if (!IsValidInstance(pMsDelay) || pMsDelay == "" || pMsDelay < 1 ) {
window.location.reload(false);
} else {
setTimeout("ReloadPage(0)", pMsDelay);
}
}

//get a value from the querystring
function getQueryStringValue(pKey, pOptionalDefaultValue) {
    var query = window.location.search.substring(1);
    var vars = query.split('&');
    var varslength = vars.length;
    for (var i = 0; i < varslength; i++) {
        var pair = vars[i].split('=');
        if (pair[0] == pKey) {
            return pair[1];
        }
    }
    return pOptionalDefaultValue;
}

//Get an element given an id - will also return the instance if an object is passed in.
//7 times quicker than prototype's $() - only 10% slower than straight document.getElementById()
//saves 21 bytes of download per call.
function ge(id) {
    //if (!IsValidInstance(id)) //20% perf hit to do this check
    //    return null;
    if (typeof (id) == 'string') //4% perf hit to do this check
        return document.getElementById(id);
    return id; //already an object
}



function GetId(pElement) {
if (IsValidInstance(pElement)) {
if (typeof pElement == "string") {
return pElement; //they sent us the id probably
} else {
return pElement.id;
}
} else {
return "";
}
}


// function to set a global variable 
function setGlobal(pName,pValue) {
window[pName]=pValue;
}

//function to default the value of a global variable if it is not already set
function defaultGlobal(pName,pValue) {
if (!IsValidInstance(window[pName])) {
setGlobal(pName, pValue);
} else {
//already set
}
}

function openStrippedWindow(href, h, w)
{
thewin = window.open(href,'_blank','toolbar=0,location=0,directories=0,status=0,menubar=0,scrollbars=1,resizable=1,width='+w+',height='+h+',left=' + (window.screen.width-w)/2 + ',top=' + (window.screen.height-h)/2);
//thewin.focus();
}

function openStrippedWindowRelative(href, h, w)
{
//probably need to do some regex on the window.location.pathname and trim everything after the last /
openStrippedWindow(window.location.protocol + "//" + window.location.host + "/" + href, h, w);
}

function openWindow(href, pTarget) {
thewin = window.open(href, pTarget, '');
}

//
// Build a 'callback' script which "backfills" the given fields with values.
//
function buildCallback( pFormName, pFieldNames, pResultValues) {

var lLength = pFieldNames.length;
var lCallback = "";
for (i=0; i<lLength; i++) {
var lField = document.forms[pFormName].elements[pFieldNames[i]];
lCallback += ((lField != null) ?
("opener.setValue(opener.document.forms['"+pFormName+"'].elements['"+pFieldNames[i]+"'],"+pResultValues[i]+"); ") : "");
}
//alert(lCallback);
return lCallback;
}

//
// Build a URL with embedded fieldname=value pairs.
//
function buildUrl(pUrl, pFormName, pFieldNames, pIncludeEmpty) {
if (!IsValidInstance(pIncludeEmpty) || pIncludeEmpty != true)
pIncludeEmpty = false;

var lLength = pFieldNames.length;
var lArgs = "";
for (i = 0; i < lLength; i++) {
var lField = document.forms[pFormName].elements[pFieldNames[i]];
var lValue = getValue(lField);
if (!pIncludeEmpty)
lArgs += ((lValue.length > 0) ? (((lArgs.length > 0) ? '&' : '') + (pFieldNames[i]+'='+escape(lValue))) : '');
else
lArgs += ( ((lArgs.length > 0) ? '&' : '') + (pFieldNames[i]+'='+escape(lValue)) );
}
var lNewUrl = pUrl.replace(/replace=me/,lArgs);
//alert(lNewUrl);
return lNewUrl;
}








// --------------------------------------------------------------------------------------
// -- VISUAL BEHAVIOR METHODS -----------------------------------------------------------
// --------------------------------------------------------------------------------------

var maxOpacity = 99.999;

function showIt(pElementId, pIsInline)
{
    var element = ge(pElementId);
    if (element == null) {
        dalert ("showIt Can't find element by id: " + pElementId);
    } else {
        if (typeof pIsInline == "undefined")
            pIsInline = false;    

        //try to recover the setting set by hideIt()
        if (getElementAttribute(pElementId, "oldStyleDisplay") != null)
            element.style.display = getElementAttribute(pElementId, "oldStyleDisplay");
        else
            element.style.display = (pIsInline ? "inline" : "block");
    }
}



function hideIt(pElementId) {
    var element = ge(pElementId);
    if (element == null)
        dalert("hideIt can't find element by id: " + pElementId);
    else {
        if (isVisible(pElementId))
            setElementAttribute(pElementId, "oldStyleDisplay", element.style.display); //save this for use in showIt
        //say("<p>" + pElementId + " " + element.style.display);
        element.style.display = "none";
    }
}

function hideThem(pObjArray) {
    var listlength = pObjArray.length;
    for (var i = 0; i < listlength; i++) {
        hideIt(pObjArray[i], true);
    }
}
function showThem(pObjArray) {
    var listlength = pObjArray.length;
    for (var i = 0; i < listlength; i++) {
        showIt(pObjArray[i], true);
    }
}

function showHideIt(pElementId, pIsInline) {
    if (isVisible(pElementId))
        hideIt(pElementId);
    else
        showIt(pElementId, pIsInline);
}

function isVisible(pElementId) {
    var element = ge(pElementId);
    if (element == null)
        dalert("isVisible can't find element by id: " + pElementId);
    else {
        if (typeof element.style.display == 'undefined')
        if (element.style.display == "")
            return false;
        if (element.style.display.toUpperCase() == "NONE")
            return false;
        return true;
    } 
}

function focusIt(objID) {
    var el = ge(objID);
    if (el != null)
        el.focus();
}

function setOpacity(pObject, pOpacity) {
if (!IsValidInstance(pObject)) {
dalert("setOpacity given a null object");
return;
}
pObject = ge(pObject);
pOpacity = (pOpacity >= 100) ? maxOpacity : pOpacity;
  
// IE/Win
pObject.style.filter = "alpha(opacity:"+pOpacity+")";
  
// Safari<1.2, Konqueror
pObject.style.KHTMLOpacity = pOpacity/100;
  
// Older Mozilla and Firefox
pObject.style.MozOpacity = pOpacity/100;
  
// Safari 1.2, newer Firefox and Mozilla, CSS3
pObject.style.opacity = pOpacity/100;
}

function setOpacityToReadOnly(pObjId) {
lObj = ge(pObjId);
if (lObj)
{
setOpacity(lObj, 50); //called for browsers other than IE first
lObj.style.filter += "gray alpha(opacity:50)"; //overrides the IE filter from above
}
}

function fadeIn(pObjId, pOpacity) {
lObj = ge(pObjId);
if (lObj)
{
if (pOpacity <= 100) {
setOpacity(lObj, pOpacity);
pOpacity += 1;
window.setTimeout("fadeIn('"+pObjId+"',"+pOpacity+")", 100);
}
}
}

function fadeOut(pObjId, pOpacity, pHideMeTF)
{
    lObj = ge(pObjId);
    if (lObj)
    {
        if (pOpacity > 0) {
            setOpacity(lObj, pOpacity);
            pOpacity -= 1;
            window.setTimeout("fadeOut('" + pObjId + "'," + pOpacity + ", " + pHideMeTF + ")", 100);
        } else {
            if (pHideMeTF == true)
            hideIt(pObjId);
        }
    }
}


function makeTaller(pObjId, pPixels, pMax) {
    var el = ge(pObjId);
    if (IsValidInstance(el)) {
        if (!IsValidInstance(pMax))
            pMax = 99999;
        else
            pMax = parseInt(pMax);

        pPixels = parseInt(pPixels);
        var desired = parseInt(el.style.height) + pPixels;
        if (desired > pMax)
            desired = pMax;
        if (desired > GetWindowHeight())
            desired = GetWindowHeight();
        if (desired > 0)
            el.style.height = desired + "px";
    }
}
function makeShorter(pObjId, pPixels, pMin) {
    var el = ge(pObjId);
    if (IsValidInstance(el)) {
        if (!IsValidInstance(pMin))
            pMin = 0;
        else
            pMin = parseInt(pMin);
        
        pPixels = parseInt(pPixels);
        var desired = parseInt(el.style.height) - pPixels;
        if (desired < pMin)
            desired = pMin;
        if (desired > 0)
            el.style.height = desired + "px";
    }
}  






// --------------------------------------------------------------------------------------
// -- FUNCTIONS FOR MANIPULATING CSS CLASSES --------------------------------------------
// --------------------------------------------------------------------------------------


function setCssClass(pObj, pClass) {
    pObj = ge(pObj);
    if (!IsValidInstance(pObj))
        return;
saveCssClass(pObj);
//setLastCssClass(pObj, pClass);
pObj.className = pClass;
}


function revertCssClass(pObj) {
    pObj = ge(pObj);
    if (!IsValidInstance(pObj))
        return;
    saveCssClass(pObj);
//setLastCssClass(pObj, pClass);
if (pObj.originalClassName)
pObj.className = pObj.originalClassName;
}

//do not use this function directly
function saveCssClass(pObj) {
    pObj = ge(pObj);
    if (!IsValidInstance(pObj))
        return;
    //save the original style
if (IsEmptyNullOrInvalid(pObj.originalClassName)) {
setOriginalCssClass(pObj, pObj.className);
} 

if (IsEmptyNullOrInvalid(pObj.lastClassName)) { //no last css class name
//might as well save the original style as the lastClassStyle as well
setLastCssClass(pObj, pObj.originalClassName);
} 
}
//do not use this function directly
function setLastCssClass(pObj, pClass) {
pObj.lastClassName = pClass;
}
//do not use this function directly
function setOriginalCssClass(pObj, pClass) {
pObj.originalClassName = pClass;
}


function addCssClass(pObj, pClassName) {
//only add the classname if it doesn't already exist
if (pObj) {
//alert(pObj.className);
removeCssClass(pObj, pClassName); //remove existing so we don't duplicate it
//HACK This will break if classname looks like "class class1 class2" and you want to remove 'class', you'll be left with '1 2'
setCssClass(pObj, pObj.className + " " + pClassName);
//alert(pObj.className);
}
}

function removeCssClass(pObj, pClassName) {
if (pObj && pObj.className) {
var re = new RegExp(pClassName, 'g');
pObj.className = pObj.className.replace(re, '');
}
}









// --------------------------------------------------------------------------------------
// -- DOM MODIFICATION ------------------------------------------------------------------
// --------------------------------------------------------------------------------------

function removeElement(pId, pDelay) {
    var el = ge(pId); 
    if (el != null) {
        //	    if (IsValidInstance(pDelay))
        //            window.setTimeout("el.parentNode.removeChild("+ge(pId)+")", pDelay);
        //	    else
        el.parentNode.removeChild(el); 
    }
}


// call this function from form of html 
function CreateDiv(pId, pPixelsFromTop, pPixelsFromLeft, pHeight, pWidth, pInnerHtml, pCssClass, pCloseable, pDisplayNone, pOnCloseJs){
if (!IsValidInstance(pCloseable))
pCloseable = false;
else {
if (typeof pCloseable == "string") {
if (pCloseable.toUpperCase() == "YES" || pCloseable.toUpperCase() == "TRUE" || pCloseable.toUpperCase() == "T" || pCloseable.toUpperCase() == "Y")
pCloseable = true;
}
}
    
if (!IsValidInstance(pId))
pId = generateGuid();

dv = document.createElement('div'); // create dynamically div tag
dv.setAttribute('id',pId);       //give id to it
dv.className=pCssClass;                 // set the style classname  
    
if (typeof pDisplayNone == "string" ) {
if (pDisplayNone.toUpperCase() == "YES" || pDisplayNone.toUpperCase() == "TRUE" || pDisplayNone.toUpperCase() == "T" || pDisplayNone.toUpperCase() == "Y")
pDisplayNone = true;
} 
if (pDisplayNone)
dv.style.display = "NONE";


//set the inner styling of the div tag 
dv.style.position="absolute";
dv.style.pixelLeft=pPixelsFromLeft;
dv.style.pixelTop=pPixelsFromTop;
dv.style.left=pPixelsFromLeft;
dv.style.top=pPixelsFromTop;
if (IsValidInstance(pWidth))
dv.style.pixelWidth=pWidth;
if (IsValidInstance(pHeight))
dv.style.pixelHeight=pHeight;
//set the html content inside the div tag
    
if (pCloseable)
    dv.innerHTML = "<img src='http://media.domainofheroes.com/clear.gif' alt='close' class='img-button_close clickable' style='float:right;margin:1px;' onmousedown=\"removeElement('" + pId + "', 50); " + pOnCloseJs + ";\"/>";

dv.innerHTML+=pInnerHtml;

// attach event onmouseclick to the created div tag 
//AttachEvent(dv, "click", function(){removeElement(pId)}); 
//finally add the div id to ur form 
document.forms[0].appendChild(dv);
}


function CreatePopupNote(pId, pInnerHtml, pAssociatedElementId, pHeight, pWidth, pClass, pCloseable) {
if (!IsValidInstance(pClass))
pClass = "";
        
CreateDiv(pId, GetY(ge(pAssociatedElementId), false) - 10, GetX(ge(pAssociatedElementId), true) + 10, pHeight, pWidth, pInnerHtml, "popupNote " + pClass, pCloseable);
}


//accepts an arbitrary number of parameters for column html
function appendRowToTable(pTableId, pParams_ColContent1) {
    var tbl = document.getElementById(pTableId);
    if (typeof (tbl) == "undefined" || tbl == null)
        return false;
    //var lastRow = tbl.rows.length;
    var row = tbl.insertRow(-1); //-1 means it will add to the end, or specify an index

    var paramCount = arguments.length;
    var cell;
    for (var i = 1; i < paramCount; i++) {
        cell = row.insertCell(i - 1);
        if (typeof(arguments[i]) != "undefined")
            cell.appendChild(document.createTextNode(arguments[i]));
    }
    return row; //in case the called wants to modify the new row
}


function MoveIt(pObject, pX, pY, pDuration) {
    dalert('why is MoveIt empty');
}

function addListItem(pListId, pHtml, pMaxItems, pItemId, pBoolAddToTop, pClassForLi, pSetDisplayNone) {
var ul = ge(pListId); 
if (ul == null)
dalert("addListItem couldn't find a list using Id: " + pListId);

if (!IsValidInstance(pBoolAddToTop))
pBoolAddToTop = false;

if (!IsValidInstance(pSetDisplayNone))
pSetDisplayNone = false;
    
if (IsValidInstance(pMaxItems) && pMaxItems > 0 && ul.childNodes.length > (pMaxItems - 1)) {
//trim the list to pMaxItems - 1
//window.status = (pMaxItems - ul.childNodes.length);
        
if (pBoolAddToTop) {
while(ul.childNodes.length > (pMaxItems - 1))
ul.removeChild(ul.childNodes[ul.childNodes.length - 1]);
} else {
while(ul.childNodes.length > (pMaxItems - 1))
ul.removeChild(ul.childNodes[0]);
}
}

var li = document.createElement('li');
if (IsValidInstance(pItemId) && pItemId != -187) {
li.id = pItemId;
}

if (IsValidInstance(pClassForLi) && pItemId != "") {
li.className = pClassForLi;
}

if (pSetDisplayNone) {
li.style.display = "none";
}

setInnerHtml(li, pHtml);
    
if (pBoolAddToTop && IsValidInstance(ul.childNodes[0]))
ul.insertBefore(li, ul.childNodes[0]);
else
ul.appendChild(li);
//li.scrollIntoView(); //this is very bad - lists all over the screen are getting modified, so don't do this
    
}



/*************************************************************
Function name:  setElementAttribute
Purpose:  generically set an attribute value on an element
Inputs:  pField - the element reference or its id, pAttribute, pValue
Outputs:  nothing
Returns:  nothing 
Creator:  Aaron K. Murray
*************************************************************/
function setElementAttribute(pField, pAttribute, pValue)
{
    var el = typeof(pField) == "string" ? ge(pField) : pField;
    if (IsValidInstance(el))
        el.setAttribute(pAttribute, pValue);
    else 
        dalert("common.setElementAttribute: Unable to set attribute value on null field: [" + pField + "]");
}

/*************************************************************
   Function name:  getElementAttribute
         Purpose:  generically get an attribute value of an element
          Inputs:  pElementId, pAttribute
         Outputs:  nothing
         Returns:  element attribute value, null if not found
         Creator:  Aaron K. Murray
*************************************************************/
function getElementAttribute(pField, pAttribute) 
{
    var el = typeof(pField) == "string" ? ge(pField) : pField;
    if (IsValidInstance(el)) {
        if (el.getAttribute)
            return el.getAttribute(pAttribute);
        else
            return null;
    }
    else 
        dalert("common.getElementAttribute: Unable to get attribute value on null field: [" + pField + "]");

    return null;
}



// --------------------------------------------------------------------------------------
// -- COOKIE METHODS -------------------------------------------------------------
// --------------------------------------------------------------------------------------

var _cookieToday = new Date();
var _cookieNextMonth = new Date(_cookieToday.getYear(), _cookieToday.getMonth() + 1, _cookieToday.getDate());
var _cookieNextYear = new Date(_cookieToday.getYear() + 1, _cookieToday.getMonth(), _cookieToday.getDate());


//only name & value are required
function setCookie(Name, Value, Expires, Path, Domain, bSecure) {
    if (Expires == null || Expires == "")
        Expires = _cookieNextYear;
        
    var CookieText = escape(Name) + '=' + escape(Value);
    CookieText += (Expires ? '; EXPIRES=' + Expires.toGMTString() : '');
    CookieText += (Path ? '; PATH=' + Path : '');
    CookieText += (Domain ? '; DOMAIN=' + Domain : '');
    CookieText += (bSecure ? '; SECURE' : '');

    document.cookie = CookieText;
}

function getCookie(Name) {
    var Value = null;
    if (document.cookie)	   //only if exists
    {
        var arr = document.cookie.split((escape(Name) + '='));
        if (2 <= arr.length) {
            var arr2 = arr[1].split(';');
            Value = unescape(arr2[0]);
        }
    }
    return Value;
}

function deleteCookie(Name) {
    var tmp = getCookie(Name);
    if (tmp)
    { setCookie(Name, tmp, (new Date(1))); }
}


// --------------------------------------------------------------------------------------
// -- ARRAY METHODS   -------------------------------------------------------------------
// --------------------------------------------------------------------------------------


//Source: http: //www.hunlock.com/blogs/Mastering_Javascript_Arrays
function isArray(testObject) {
    return testObject && !(testObject.propertyIsEnumerable('length')) && typeof testObject === 'object' && typeof testObject.length === 'number';
}

//http://www.phpied.com/dom-access-optimization/
//Copy a collection to an array. 
//Used when looping through DOM collections because DOM hits are 2-200 times slower 
function toArray(coll) {
    for (var i = 0, a = [], len = coll.length; i < len; i++) {
        a[i] = coll[i];
    }
    return a;
}


// --------------------------------------------------------------------------------------
// -- TEXT / STRING METHODS -------------------------------------------------------------
// --------------------------------------------------------------------------------------


function Pad(pTextToPad, pTargetLength, pPadString) 
{ 
    pTextToPad = pTextToPad.toString();
    
    if (!IsValidInstance(pPadString))
        pPadString = " ";
    
    while (pTextToPad.length < pTargetLength) {
        pTextToPad = pPadString + pTextToPad;
    }
    return pTextToPad; 
}

function validateEmail(elementValue) {
    var emailPattern = /^[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}$/;
    return emailPattern.test(elementValue);
}

//get true/false
function getBool() {
    return Math.floor(Math.random() * 1.9999) == 0;
}

//make a 32 char GUID
function generateGuid()
{
    var guid, i, j;
    guid = '';
    for(j=0; j<32; j++)
    {
        if(j == 8 || j == 12|| j == 16|| j == 20)
            guid = guid + '-';
        i = Math.floor(Math.random()*16).toString(16).toUpperCase();
        guid = guid + i;
    }
    return guid;
}

function ValidateAlphaNumeric(evt)
{
    if (!e) var e = window.event;
	if (e.keyCode) code = e.keyCode;
	else if (e.which) code = e.which;

    // 0 = navigation keys (IE doesn't trigger on these)
    // 8 = backspace       (   nor on this)
    // 32 = space
    // 13 = enter
    // 44 = ,
    return (code >= 48 && code <= 57) 
            || (code >= 65 && code <= 90) 
            || (code >= 97 && code <= 122)
            || (code == 0)
            || (code == 8)
            || (code == 13)
            || (code == 32)
            || (code == 44);
}

//http://www.mredkj.com/javascript/numberFormat.html
//addCommas(1000)
// 1,000
//addCommas(1231.897243)
// 1,231.897243
//addCommas('9999999.00')
// 9,999,999.00
//addCommas(-500000.99)
// -500,000.99 
function addCommas(nStr) {
    nStr += '';
    x = nStr.split('.');
    x1 = x[0];
    x2 = x.length > 1 ? '.' + x[1] : '';
    var rgx = /(\d+)(\d{3})/;
    while (rgx.test(x1)) {
        x1 = x1.replace(rgx, '$1' + ',' + '$2');
    }
    return x1 + x2;
}



function replaceThisWithThat(pString, pThis, pThat) {
	//the regular expression version wasn't working well with variables and special chars, and required much escaping
    //	rExp = /pThis/gi;
    //	rExp = /<br \/>/gi;
    //	alert("This: " + pThis + "\nThat: " + pThat + "\nRegExp: " + rExp + "\nString: " + pString);
    //	return pString.replace(rExp, pThat);

	//new version without reg exp
	var newString = pString;
	while (newString.indexOf(pThis) != -1) {
	    newString = newString.replace(pThis, pThat);
	}
	return newString;
}

// Converts the data in the given field to upper case.
function upperCase(pField) {
    if (typeof pField.type == "undefined")
        pField = ge(pField);

	pField.value = pField.value.toUpperCase();
}


//check a char to see if it is whitespace
function isWhitespace(charToCheck) {
	var whitespaceChars = " \t\n\r\f";
	return (whitespaceChars.indexOf(charToCheck) != -1);
}

function IsCharNumber(pCharacter) {
    var acceptable = "1234567890";
    return acceptable.indexOf(pCharacter, 0) >= 0;
}

function IsLetterOrNumber(pCharacter) {
    var acceptable = "1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
    return acceptable.indexOf(pCharacter, 0) >= 0;
}

function IsLetterOrNumberOrSpace(pCharacter) {
    var acceptable = "1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ ";
    return acceptable.indexOf(pCharacter, 0) >= 0;
}

function IsNumber(pText) {
    for (i = 0; i < pText.length; i++) {
        if (!IsCharNumber(pText.charAt(i)))
            return false;
    }
    return true;
}

function toYesNo(pBool) {
    if (pBool == null || pBool == undefined || !pBool || pBool == "N")
        return "No"
    return "Yes"
}

// --------------------------------------------------------------------------------------
// -- GETTING / SETTING CONTENT / VALUES ------------------------------------------------
// --------------------------------------------------------------------------------------



//Returns the node text value - cross browser because node.text is IE, and nodeValue in FF is diff than ie
function getInnerText(pNode)
{
    if (!IsValidInstance(pNode)) {
        return ""; 
    } else {
        if (IsEmptyNullOrInvalid(pNode.textContent) && IsEmptyNullOrInvalid(pNode.innerText) && IsEmptyNullOrInvalid(pNode.text) && IsEmptyNullOrInvalid(pNode.nodeValue)) {
            return "";
        } else {
            return (pNode.textContent || pNode.innerText || pNode.text || pNode.nodeValue) ;
        }
    }
}

//set the node inner html value (takes about 0.8ms to run..)
function setInnerHtml(pNode, pValue)
{
    if (typeof pNode == "string") 
        pNode = ge(pNode);

    if (!IsValidInstance(pNode) || !IsValidInstance(pValue)) {
        dstatus("setInnerHtml could not find the target element");
        return false; 
    } else {
        try { 
            //alert(pNode.type);
            if (pNode.type == "select-one") {
                SetSelectInnerHtml(pNode, pValue);
            } else {
                pNode.innerHTML = pValue;
            }
        } catch (err) {
            dalert(err.description);
            pNode.innerHTML = "";
            var dv = document.createElement('div'); //  dynamically create div tag and insert into that
            dv.innerHTML=pValue;
            pNode.appendChild(dv);
        }
    }
}



// Set the "value" of the given field in a control-independent fashion.
//TODO currently not working for radios
function setValue(pField, pValue, pValueProperty) 
{
    var origField = pField;
    var field = ((typeof pField == 'string') ? ge(pField) : pField);

    if (!IsValidInstance(field))
    {
        dalert("common.setValue: Unable to set value on null field: [" + pField + "]");
        return;
    }
    
    if (IsValidInstance(pValueProperty) && pValueProperty != "")
    {
        eval ("field." + pValueProperty + " = (pValue == null ? '' : pValue)");
        return;
    } else {
        pValueProperty = "";
    }


    //dalert('setValue: ' + field.id + " (type: " + field.type + ") value: " + pValue);
    extendedType = getElementAttribute(field, "ExtendedType");
    if (!extendedType)
    {
	    if (typeof field.ComboBox != 'undefined')
	    {
            var box = eval(field.id);
            if (box)
                box.SetValue(pValue == null ? "" : pValue);
        }
        else
        {
            switch (field.type)
            {
                case "text":
    	            field.value = (pValue == null ? "" : pValue); //most common - check first for speed
    	            break;
    	        case "select-one":
    	            if (pValue == null) 
    	            {
    	                field.selectedIndex = 0;
    	            }
    	            else {
    	                var fieldoptionslength = field.options.length;
	                    for (i=0; i < fieldoptionslength; i++)
	                    {
		                    if (field.options[i].value == pValue) 
		                    {
			                    field.selectedIndex = i;
			                    break;
		                    }
		                }
		            }
		            break;
                case "checkbox":
                    field.checked = (pValue == true || pValue == "Y" || pValue == "True" || pValue == "true" || pValue == 1 || pValue == "1")
	                break;
                case "radio":
	                setCheckedRadioValue(field, pValue == null ? "" : pValue);
	                break;
                case "button":
	                pField.value = (pValue == null ? "" : pValue);
	                break;
	            default:
	                //no type property - check the tagName
                    switch (field.tagName)
                    {
                        case "DIV":
                            setInnerHtml(field, (pValue == null ? "" : pValue));
    	                    break;
                        case "SPAN":
    	                    setInnerHtml(field, (pValue == null ? "" : pValue));
    	                    break;
                        case "LABEL":
    	                    field.innerText = (pValue == null ? "" : pValue);
    	                    break;
                        case "FIELDSET":
    	                    field.lastChild.nodeValue = (pValue == null ? "" : pValue);
    	                    break;
                        case "LEGEND":
    	                    field.innerText = (pValue == null ? "" : pValue);
    	                    break;
                        case "LI":
    	                    field.innerText = (pValue == null ? "" : pValue);
    	                    break;
                        case "UL":
    	                    setInnerHtml(field, (pValue == null ? "" : pValue));
    	                    break;
                        case "TD":
    	                    setInnerHtml(field, (pValue == null ? "" : pValue));
    	                    break;
                        case "TR":
    	                    setInnerHtml(field, (pValue == null ? "" : pValue));
    	                    break;
                        case "TABLE":
    	                    setInnerHtml(field, (pValue == null ? "" : pValue));
    	                    break;
	                    default:
                            //dalert("common.setValue: Defaulting set value on field: [" + pField.id + "]");
    	                    field.value = (pValue == null ? "" : pValue);
	                }
            } //end switch
        }
    }
}

function appendValue(pField, pValue, pValueProperty) {
    var str = getValue(pField, pValueProperty) + '' + pValue;
    setValue(pField, str, pValueProperty);
}

//getValue, wrapped by encodeURIComponent()
function getValueForUri(pElementId) {
    return encodeURIComponent(getValue(pElementId));
}


function gv(pField, pValueProperty) {
    return getValue(pField, pValueProperty);
}

//TODO currently not working for radios
function getValue(pField, pValueProperty) {
    var field = ((typeof pField == 'string') ? ge(pField) : pField);
    if (!IsValidInstance(field))
    {
        dalert("common.getValue: Unable to get value on null field: [" + pField + "]");
        return "";
    }
    
    if (IsValidInstance(pValueProperty) && pValueProperty != "")
    {
        return eval ("field." + pValueProperty);
    }
    
    extendedType = getElementAttribute(field, "ExtendedType");
    if (!extendedType)
    {
	    if (typeof field.ComboBox != 'undefined')
		    lValue = field.Value;
	    else
	    {
	        switch (field.type)
	        {
	            case "checkbox":
        		    lValue = field.checked ? true : false; //"Y" : "";
        		    break;
                case "text": case "hidden": case "image": case "password": case "textarea":
        		    lValue = field.value;
                    break;
                case "radio":
		            lValue = getCheckedRadioValue(field);
		            break;
		        case "reset": case "select-multiple":  case "file": case "button":
		            lValue = '';
		            break;
	            case "select-one":
	                if (field.selectedIndex >= 0)
	                    lValue = field.options[field.selectedIndex].value;
	                else
	                    lValue = '';
	                break;
	                break;
		        default:
	                if (field.tagName == "DIV" || field.tagName == "SPAN")
		                lValue = field.innerHTML;
		            else
		                lValue = "";
		            break;
		    }
        }
    } else {
        switch (extendedType)
        {
            case "TandemKeyValueTextBox":
                lValue = field.keyOfPair;
                break;
            case "TandemDropDown":
                var dropDownObject = eval(field.id);
                if (dropDownObject)
                    lValue = dropDownObject.GetValue();
                break;
        }
    }
    
	if (lValue == null || lValue == 'null')
		lValue = '';
		
	return lValue;
}

//clear field value - doesn't matter the control type
function clearValue(pField, pValueProperty) {
    var field = ((typeof pField == 'string') ? ge(pField) : pField);
    if (!IsValidInstance(field))
    {
        dalert("common.clearValue: Unable to clear value on null field: [" + pField + "]");
        return;
    }
    
    if (IsValidInstance(pValueProperty) && pValueProperty != "")
        setValue(pField, null, pValueProperty);
    else
        setValue(pField, null);
}


function isElementEmpty(pField, pEmptyValue, pValueProperty)
{
    var isEmpty; var extendedType;
    var field = ((typeof pField == 'string') ? ge(pField) : pField);
    if (!IsValidInstance(field))
    {
        dalert("common.isElementEmpty: Unable to evaluate value on null field: [" + pField + "]");
        return true;
    }
    
    if (!IsValidInstance(pEmptyValue)) pEmptyValue = "";
    if (IsValidInstance(pValueProperty) && pValueProperty != "")
        return eval("field." + pValueProperty + " == pEmptyValue");

    
    isEmpty = true;
    extendedType = field.ExtendedType;
    if (!extendedType)
    {
        switch (field.type)
        {
            case "checkbox":
		        isEmpty = !field.checked;
		        break;
            case "text": case "hidden": case "password": case "textarea":
		        isEmpty = (field.value == pEmptyValue);
                break;
            case "radio":
                isEmpty = (getCheckedRadioValue(field) == "");
                break;
            case "select-multiple":
                alert("common.isElementEmpty: select-multiple not implemented.");
                break;
            case "select-one":
                isEmpty = (field.options[field.selectedIndex].value == pEmptyValue);
                break;
            default:
                if ((field.tagName == "DIV") || (field.tagName == "SPAN"))
                    isEmpty = (field.innerHTML == pEmptyValue);
                else
                    isEmpty = false;
                break;
        }
    }
    return isEmpty;
}

// AKM - return the value of the radio button that is checked
// return an empty string if none are checked, or
// there are no radio buttons
function getCheckedRadioValue(pField) {
    var field = ((typeof pField == 'string') ? ge(pField) : pField);

	if(!field)
	{
	    dalert("common.getCheckedRadioValue: Attempt to get value on null field: '" + pField + "'.");
		return "";
    }
    if (field.type != "radio")
    {
	    dalert("common.getCheckedRadioValue: Attempt to get value on non-radio field: '" + field.id + "'.");
		return "";
    }
		
	var radioLength = field.length;
	if(typeof radioLength == "undefined" || radioLength == 0)
        return field.checked ? field.value : "";
    else
	    for(var i = 0; i < radioLength; i++) 
		    if(field[i].checked) 
			    return field[i].value;
	return "";
}

// AKM - set the radio button with the given value as being checked, unchecks 
// if the given value does not exist, all the radio buttons are reset to unchecked
function setCheckedRadioValue(pField, newValue) {
	if(!IsValidInstance(pField))
		return;
		
	if (typeof pField.length == "undefined")
	{
		pField.checked = (pField.value == newValue.toString());
    } else {
	    var pFieldlength = pField.length;
	    for(var i = 0; i < pFieldlength; i++) {
		    pField[i].checked = false;
		    if(pField[i].value == newValue.toString()) {
			    pField[i].checked = true;
		    }
	    }
	}
}

// SetSelectInnerHtml - http://support.microsoft.com/default.aspx?scid=kb;en-us;276228
function SetSelectInnerHtml(obj,innerHTML){
	obj.innerHTML = ""
	var selTemp = document.createElement("micoxselect")
	var opt;
	selTemp.id="micoxselect1"
	document.body.appendChild(selTemp)
	selTemp = document.getElementById("micoxselect1")
	selTemp.style.display="none"
	if(innerHTML.toLowerCase().indexOf("<option")<0){//se não é option eu converto
		innerHTML = "<option>" + innerHTML + "</option>"
	}
	//innerHTML = innerHTML.toLowerCase().replace(/<option/g,"<span").replace(/<\/option/g,"</span") //This ruins the case
	innerHTML = innerHTML.replace(/<option/g,"<span").replace(/<\/option/g,"</span")
	selTemp.innerHTML = innerHTML
	  
	var selTempchildNodeslength = selTemp.childNodes.length;
	for(var i=0;i<selTempchildNodeslength;i++){
		var spantemp = selTemp.childNodes[i];
  
      if(spantemp.tagName){     
			opt = document.createElement("OPTION")
	
       if(document.all){ //IE
	    obj.add(opt)
       }else{
	    obj.appendChild(opt)
       }

       //getting attributes
       var spantempattributeslength = spantemp.attributes.length;
       for(var j=0; j<spantempattributeslength ; j++){
	    var attrName = spantemp.attributes[j].nodeName;
	    var attrVal = spantemp.attributes[j].nodeValue;
	    if(attrVal){
	     try{
	      opt.setAttribute(attrName,attrVal);
	      opt.setAttributeNode(spantemp.attributes[j].cloneNode(true));
	     }catch(e){}
	    }
       }
       //getting styles
       if(spantemp.style){
           for (var y in spantemp.style) {
               if (opt.style[y] != null && y != "length") {
    	        try{
    	            opt.style[y] = spantemp.style[y];
    	        } catch (e) {
    	            var f = 1; //breakpoint
            	}
    	    }
	    }
       }
       //value and text
       opt.value = spantemp.getAttribute("value")
       opt.text = spantemp.innerHTML
       //IE
       opt.selected = spantemp.getAttribute('selected');
       opt.className = spantemp.className;
    } 
 }    
 document.body.removeChild(selTemp)
 selTemp = null
}

function deleteOptionByValue(pSelectId, pOptionValue) {
    var sel = ge(pSelectId);
    var optionToDelete = null;
    var sellength = sel.length;
    for (var i = 0; i < sellength; i++) {
        if (sel.options[i].value == pOptionValue) {
            optionToDelete = sel.options[i];
            break;
        }
    }
    if (optionToDelete != null)
        sel.removeChild(optionToDelete);
}

function deleteSelectedOption(pSelectId) {
    var sel = ge(pSelectId);
    var optionToDelete = null;
    var sellength = sel.length;
    for (var i = 0; i < sellength; i++) {
        if (sel.options[i].selected) {
            optionToDelete = sel.options[i];
            break;
        }
    }
    if (optionToDelete != null)
        sel.removeChild(optionToDelete);
}

function IsValidInstance(pItem)
{
    return !((typeof pItem == "undefined") || (pItem == null));
}

function IsEmptyNullOrInvalid(pItem)
{
    var valid = IsValidInstance(pItem);
    if (valid) {
        if (typeof pItem == "string") {
            if (pItem == "")
                return true;  //empty string
            else 
                return false;
        } else {
            var v = getValue(pItem);
            if (v == null || v == "")
                return true; //value is empty
        }       
    } else {
        return true; //null or undefined
    }
    return false; //valid, and has a value that isn't blank
}

function formatCurrency(num) {
    num = num.toString().replace(/\$|\,/g, '');
    if (isNaN(num))
        num = "0";
    sign = (num == (num = Math.abs(num)));
    num = Math.floor(num * 100 + 0.50000000001);
    cents = num % 100;
    num = Math.floor(num / 100).toString();
    if (cents < 10)
        cents = "0" + cents;
    for (var i = 0; i < Math.floor((num.length - (1 + i)) / 3); i++)
        num = num.substring(0, num.length - (4 * i + 3)) + ',' +
num.substring(num.length - (4 * i + 3));
    return (((sign) ? '' : '-') + '$' + num + '.' + cents);
}


//http://www.irt.org/script/916.htm
function deleteOption(theSel, index) {
    theSel.options[index] = null;
}
function addOption(theSel, text, value) {
    var defaultSelected = false;
    var selected = false;
    var optionName = new Option(text, value, defaultSelected, selected)
    theSel.options[theSel.length] = optionName;
    theSel.options[theSel.length - 1].selected = false;
}

function moveOptions(theSelFrom, theSelTo) {
    var selLength = theSelFrom.length;
    var selectedText = [];
    var selectedValues = [];
    var selectedCount = 0;

    var i;

    // Find the selected Options in reverse order
    // and delete them from the 'from' Select.
    for (i = selLength - 1; i >= 0; i--) {
        if (theSelFrom.options[i].selected) {
            selectedText[selectedCount] = theSelFrom.options[i].text;
            selectedValues[selectedCount] = theSelFrom.options[i].value;
            deleteOption(theSelFrom, i);
            selectedCount++;
        }
    }

    // Add the selected text/values in reverse order.
    // This will add the Options to the 'to' Select
    // in the same order as they were in the 'from' Select.
    for (i = selectedCount - 1; i >= 0; i--) {
        addOption(theSelTo, selectedText[i], selectedValues[i]);
    }
}

function getOptionValues(theSel, pGetOnlySelected, pSeperator) {
    var selLength = theSel.length;
    var selectedValues = [];
    var foundCount = 0;
    var returnStr = "";
    for (var i = 0; i < selLength; i++) {
        if (!pGetOnlySelected || (pGetOnlySelected && theSel.options[i].selected)) {
            returnStr += theSel.options[i].value;
            if (foundCount < (selLength - 1))
                returnStr += pSeperator;
            foundCount++;
        }
    }
    return returnStr;
}

function compareOptionText(a, b) {
    /*
    * return >0 if a>b
    *         0 if a=b
    *        <0 if a<b
    */
    // textual comparison
    return a.text != b.text ? a.text < b.text ? -1 : 1 : 0;
    // numerical comparison
    //  return a.text - b.text;

}

function sortOptions(list) {
    list = ge(list);
    var items = list.options.length;
    // create array and make copies of options in list
    var tmpArray = new Array(items);
    for (var i = 0; i < items; i++)
        tmpArray[i] = new Option(list.options[i].text, list.options[i].value);
    // sort options using given function
    tmpArray.sort(compareOptionText);
    // make copies of sorted options back to list
    for (var i = 0; i < items; i++)
        list.options[i] = new Option(tmpArray[i].text, tmpArray[i].value);

}


// --------------------------------------------------------------------------------------
// -- NUMBER METHODS --------------------------------------------------------------------
// --------------------------------------------------------------------------------------
function rand(pMin, pMax) {
    return Math.floor(Math.random() * (pMax - pMin + 1) + pMin);
}


// --------------------------------------------------------------------------------------
// -- POSITIONING METHODS ---------------------------------------------------------------
// --------------------------------------------------------------------------------------


/// Get the X position of an object on the page.        
function GetX(pDomElement, pAddWidth) 
{
    var offsetLeft = 0;

    if (IsValidInstance(pAddWidth) && pAddWidth == true) {
        if (pDomElement.offsetWidth)
            offsetLeft += pDomElement.offsetWidth;
    }
    
    if (pDomElement.offsetParent)
    {
        while (pDomElement.offsetParent)
        {
            offsetLeft += pDomElement.offsetLeft;
            pDomElement = pDomElement.offsetParent;
        }
    }
    else if (pDomElement.x)
    {
        offsetLeft += pDomElement.x;
    }
    
    return offsetLeft;
}

/// Get the Y position of an object on the page.        
function GetY(pDomElement, pAddHeight) 
{
    var offsetTop = 0;

    if (IsValidInstance(pAddHeight) && pAddHeight == true ) {
        if (pDomElement.offsetHeight)
            offsetTop += pDomElement.offsetHeight;
    }
    
    if (pDomElement.offsetParent)
    {
        while (pDomElement.offsetParent)
        {
            offsetTop += pDomElement.offsetTop;
            pDomElement = pDomElement.offsetParent;
        }
    }
    else if (pDomElement.y)
    {
        offsetTop += pDomElement.y;
    }
    
    return offsetTop;
}




// --------------------------------------------------------------------------------------
// -- DEBUG SECTION ---------------------------------------------------------------------
// --------------------------------------------------------------------------------------


//only alert in debug mode
function dalert(pString) {
    if (DEBUG_ENABLED)
        alert(pString);
}

//only set statusbar text in debug mode
function dstatus(pString) {
    if (DEBUG_ENABLED)
        window.status = pString;
}

//key has been pressed - check for special events
function KeyUp(e)
{
    if (!e) var e = window.event;
	if (e.keyCode) code = e.keyCode;
	else if (e.which) code = e.which;

   switch(code)
   {
      case 16:
      __special__shift = true;
      break; 

      case 17:
      __special__ctrl = true;
      break;

      case 18:
      __special__alt = true;
      break;

      case 19:
      __special__pause = true;
      break;

      case 32:
      __special__space = true;
      break;

      case 37:
      __special__arrow_left = true;
      break;

      case 38:
      __special__arrow_up = true;
      break;

      case 39:
      __special__arrow_right = true;
      break;

      case 40:
      __special__arrow_down = true;
      break;


      
   }
   specialKeyComboCheck();
   window.setTimeout("clearSpecialCommandKeys()", 2000);
}

function specialKeyComboCheck() {
    //check to see if a special developer key combination has been pressed
    jsDebugFlagKeyCheck();

    if (DEBUG_ENABLED) {
        openDebugWindowKeyCheck();
        traceKeyCheck();
        jsAjaxDebugFlagKeyCheck();
        goToAdminPageCheck();
    }
}

function jsDebugFlagKeyCheck() {
    //CTRL ALT SHIFT Up

    //toggle js debugger flag
    
    if (__special__shift && __special__alt && __special__ctrl && __special__arrow_up) {
        DEBUG_ENABLED = !DEBUG_ENABLED;
    } 

    if (DEBUG_ENABLED) {
        window.status = "Javascript debugging has been turned ON.";
    } else {
        //window.status = "Javascript debugging has been turned OFF."; //Press CTRL ALT SHIFT RIGHT to enable it.
        //setTimeout("window.status=''", 3000);
    }
}

function openDebugWindowKeyCheck() {
    //CTRL ALT SHIFT Right
    //check to see if all debug keys are pressed. 
    //If they are, pop-up the debugger
    //If not, set them all to false because a certain amount of time has passed 
    //and we don't want to pop this thing randomly
    
    if (__special__shift && __special__alt && __special__ctrl && __special__arrow_right) {
        //openStrippedWindowRelative("Log.aspx", 500, 800);
        ShowClientCacheReport();
    } 
}

function jsAjaxDebugFlagKeyCheck() {
    //CTRL ALT SHIFT Left

    //toggle js debugger flag
    
    if (__special__shift && __special__alt && __special__ctrl && __special__arrow_left) {
        ShowAjaxHistory();
    } 
}

function traceKeyCheck() {
    //CTRL ALT SHIFT Down
    //check to see if all keys are pressed for tracing
    
    if (__special__shift && __special__alt && __special__ctrl && __special__arrow_down) {
        var currentUrl = window.location.href;
        if (currentUrl.indexOf("trace=true") != -1) {
            //we already have the tracing args in the URL. Just reload this page
            window.location.href = window.location.href;
        } else {
            if (currentUrl.indexOf("?") != -1) {
                window.location.href = window.location.href + "&trace=true"; //we already have a ? in the querystring
            } else {
                window.location.href = window.location.href + "?trace=true"; //start of querystring args
            }
        }
    } 
}


function goToAdminPageCheck() {
    //CTRL ALT SHIFT SPACE
    //check to see if all debug keys are pressed. 
    //If they are, go to the admin URL
    
    if (__special__shift && __special__alt && __special__ctrl && __special__space) {
        goTo("AdminDefault.aspx");
    } 
}

function clearSpecialCommandKeys() {
    //we don't want these flag lingering around for random triggering
    __special__shift  = false;
    __special__alt = false;
    __special__ctrl = false;
    __special__arrow_up = false;
    __special__arrow_down = false;
    __special__arrow_left = false;
    __special__arrow_right = false;
    __special__pause = false;
    __special__space = false;
}


function GetWindowHeight() {
    var h;
    // Window dimensions: 
    if (window.innerHeight)
        h=window.innerHeight;
    else if (document.documentElement && document.documentElement.clientHeight)
        h=document.documentElement.clientHeight;
    else if (document.body)
        h=document.body.clientHeight;
    return h;
}

function GetWindowWidth() {
    var w, theHeight;
    // Window dimensions: 
    if (window.innerWidth) 
        w=window.innerWidth;
    else if (document.documentElement && document.documentElement.clientWidth) 
        w=document.documentElement.clientWidth;
    else if (document.body) 
        w=document.body.clientWidth;
    return w;
}

function blinkTitle() {
    if (!window.oldtitle) window.oldtitle = document.title;
    if (document.title == '*') {
        document.title = window.oldtitle;
    } else {
        document.title = '*';
    }
}
//pIntervalMs=200 is good; pDurationMs=2000 is good
function startBlinkTitle(pIntervalMs, pDurationMs) {
    window.blinkinterval = setInterval(blinkTitle, pIntervalMs);
    setTimeout(stopBlinkTitle, pDurationMs);
}
function stopBlinkTitle() {
    clearInterval(window.blinkinterval);
    document.title = window.oldtitle;
}

//stacktrace debug stuff from http://www.helephant.com/article.aspx?ID=675
function getFunctionName(theFunction) {
    // mozilla makes it easy. I love mozilla.
    if (theFunction.name) {
        return theFunction.name;
    }

    // try to parse the function name from the defintion
    var definition = theFunction.toString();
    var name = definition.substring(definition.indexOf('function') + 8, definition.indexOf('('));
    if (name)
        return name;

    // sometimes there won't be a function name 
    // like for dynamic functions
    return "anonymous";
}
function getSignature(theFunction) {
    var signature = getFunctionName(theFunction);
    signature += "(";
    if (theFunction.arguments !== undefined && theFunction.arguments.length !== undefined) {
        for (var x = 0; x < theFunction.arguments.length; x++) {
            // trim long arguments
            var nextArgument = theFunction.arguments[x];
            if (nextArgument == null || (!nextArgument.substring))
                continue;

            if (nextArgument.length > 30)
                nextArgument = nextArgument.substring(0, 30) + "...";

            // apend the next argument to the signature
            signature += "'" + nextArgument + "'";

            // comma separator
            if (x < theFunction.arguments.length - 1)
                signature += ", ";
        }
    }
    signature += ")";
    return signature;
}

function getStackTrace(startingPoint) {
    var stackTraceMessage = ""; //Stack trace: <br>";
    var nextCaller = startingPoint;
    while (nextCaller) {
        stackTraceMessage += getSignature(nextCaller) + "<br>";
        nextCaller = nextCaller.caller;
    }
    stackTraceMessage += "<br>";
    return stackTraceMessage;
}


AttachEvent(document, "mousedown", commonMouseDown);
AttachEvent(document, "keydown", commonKeyDown);


//Human Input tracking
var _lastKeyDown = null;
var _lastMouseDown = null;


function getMsSinceLastHumanInput() {
    var lastInput = getLastHumanInput();
    if (lastInput == null)
        return 86400000; //1 day
    return ((new Date()) - lastInput);
}

function hasHumanActed() {
    return (getLastHumanInput() != null);
}

function getLastHumanInput() {
    if (_lastKeyDown == null && _lastMouseDown == null)
        return null;

    if (_lastMouseDown > _lastKeyDown)
        return _lastMouseDown;
    return _lastKeyDown;
}

function commonMouseDown() {
    _lastMouseDown = new Date();
    //alert("commonMouseDown: " + _lastMouseDown);
}

function commonKeyDown() {
    _lastKeyDown = new Date();
    //alert("commonKeyDown: " + _lastKeyDown);
}


//only use this during the page load, or it will replace the entire dom
function w(pHtml) {
    document.write(pHtml);
}
//only use this during the page load, or it will replace the entire dom
function wbr(pHtml) { 
    w("<br>" + pHtml); 
}
//safe to use after page load
function say(pText) {
    var e = document.createElement("SPAN");
    e.innerHTML = pText;
    if (document.body)
        document.body.appendChild(e);
}

var _playedSounds = [];
var _playedSoundIndex = -1;
function playSound(pUrl) {
    var el = null;
    if (_ua.browser.name == "IE") { //IE doesn't have a navigator.plugins array
        el = document.createElement("bgsound");
        el.id = "sound_" + pUrl;
        el.src = pUrl;
        el.loop = 0;
        el.autostart = true;
        el.hidden = true;
        el.style.height = 0;
    } else if (browserHasPlugin('QuickTime')) {
        el = document.createElement("object");
        el.id = "sound_" + pUrl;
        el.data = pUrl;
        el.type = "audio/mpeg";
        el.style.height = 0;
        el.style.width = 0;
    } else if (browserHasPlugin('Windows Media')) {
        el = document.createElement("object");
        el.id = "sound_" + pUrl;
        el.data = pUrl;
        el.type = "application/x-mplayer2";
    } else if (browserHasPlugin('RealPlayer')) {
        el = document.createElement("embed");
        el.id = "sound_" + pUrl;
        el.type = "audio/x-pn-realaudio-plugin";
        el.src = pUrl;
        el.loop = false;
        el.autostart = true;
        el.hidden = true;
        el.style.height = 0;
    }

    if (el != null) {
        _playedSoundIndex++;
        document.body.appendChild(el);
        _playedSounds[_playedSoundIndex] = el;
    } else {
        dalert("playSound fail: " + pUrl);
    }
}

function removePlayedSounds() {
    for (var i = 0; i <= _playedSoundIndex; i++) {
        document.body.removeChild(_playedSounds[i]);
        _playedSounds[i] = null;
    }
    _playedSounds = [];
    _playedSoundIndex = -1;
}

//only works for non-IE browsers. In IE you have to use VB script to examine an ActiveX object http://developer.apple.com/internet/webcontent/examples/detectplugins_source.html
function browserHasPlugin(pPluginName) {
    if (!navigator.plugins)
        return false;
    pPluginName = pPluginName.toLowerCase();
    for (var i = 0; i < navigator.plugins.length; i++)
        if (navigator.plugins[i].name.toLowerCase().indexOf(pPluginName) > -1)
        return true;
    return false;
}





//http://www.shawnolson.net/a/503/altering-css-class-attributes-with-javascript.html
function changecss(theClass, element, value) {
    var cssRules;

    var added = false;
    for (var S = 0; S < document.styleSheets.length; S++) {

        if (document.styleSheets[S]['rules']) {
            cssRules = 'rules';
        } else if (document.styleSheets[S]['cssRules']) {
            cssRules = 'cssRules';
        } else {
            //no rules found... browser unknown
        }

        for (var R = 0; R < document.styleSheets[S][cssRules].length; R++) {
            if (document.styleSheets[S][cssRules][R].selectorText == theClass) {
                if (document.styleSheets[S][cssRules][R].style[element]) {
                    document.styleSheets[S][cssRules][R].style[element] = value;
                    added = true;
                    break;
                }
            }
        }
        if (!added) {
            if (document.styleSheets[S].insertRule) {
                document.styleSheets[S].insertRule(theClass + ' { ' + element + ': ' + value + '; }', document.styleSheets[S][cssRules].length);
                added = true;
            } else if (document.styleSheets[S].addRule) {
                document.styleSheets[S].addRule(theClass, element + ': ' + value + ';');
                added = true;
            }
        }
    }
    return added;
}

//Aaron Murray, 4/1/10
function getCssValue(theClass, element) {
    var cssRules;

    for (var S = 0; S < document.styleSheets.length; S++) {
        if (document.styleSheets[S]['rules']) {
            cssRules = 'rules';
        } else if (document.styleSheets[S]['cssRules']) {
            cssRules = 'cssRules';
        } else {
            //no rules found... browser unknown
        }

        for (var R = 0; R < document.styleSheets[S][cssRules].length; R++) {
            if (document.styleSheets[S][cssRules][R].selectorText == theClass) {
                if (document.styleSheets[S][cssRules][R].style[element]) {
                    return document.styleSheets[S][cssRules][R].style[element];
                }
            }
        }
    }
    return "";
}


var MAX_DUMP_DEPTH = 10;

function dumpObj(obj, name, indent, depth) {
    if (depth > MAX_DUMP_DEPTH) {
        return indent + name + ": <Maximum Depth Reached>\n";
    }
    if (typeof obj == "object") {
        var child = null;
        var output = indent + name + "\n";
        indent += "\t";
        for (var item in obj) {
            try {
                child = obj[item];
            } catch (e) {
                child = "<Unable to Evaluate>";
            }
            if (typeof child == "object") {
                output += dumpObj(child, item, indent, depth + 1);
            } else {
                output += indent + item + ": " + child + "\n";
            }
        }
        return output;
    } else {
        return obj;
    }
}