/*
** Common routines and constants that are required
** by the AWPX framework
*/

//---------------------------------------------------------------
// Constants
//---------------------------------------------------------------

/* Possible SetTo Values */
var AWPX_TRUE   = true;
var AWPX_FALSE  = false;
var AWPX_TOGGLE = "toggle";

/* Dynamic Styles */
var AWPX_CLASS_HIGHLIGHT = "highlight";
var AWPX_CLASS_SELECTED  = "selected";

/* Separator used to encode multiple values */
var AWPX_VALUE_SEPARATOR = ",";

/* Internal */
var AWPX_LAST_SINGLE_SELECTED_PREFIX = "_awpxLastSingleSelected_";

//---------------------------------------------------------------
// Browser Detection
//---------------------------------------------------------------
var isMSIE = (navigator.appName.indexOf("Microsoft") != -1);
var isNS = ! isMSIE;

//---------------------------------------------------------------
// Global Variables
//---------------------------------------------------------------

/* Parse base url to the application (i.e., context) */
var endIdx = document.location.pathname.indexOf("http://express.amberpoint.com/", 1);
var gBaseUrl = document.location.protocol + "//" + document.location.host + document.location.pathname.substring(0, endIdx);

//---------------------------------------------------------------
// Events
//---------------------------------------------------------------

/*
 * Attempt to resolve the event object in a portable way
 */
function awpxGetEvent(event) {
  if(!event) {
    event = window.event;
  }
  return event;
}

/*
 * Get the event source in a portable way
 */
function awpxGetEventSource(event) {
  var evt = awpxGetEvent(event)
  return (evt.target ? evt.target : evt.srcElement);
}

/*
 * Cancel any further event bubbling
 */
function awpxCancelEvent(event) {
  var evt = awpxGetEvent(event);
    if (evt.stopPropagation) evt.stopPropagation();
    evt.cancelBubble = true;

  /* DUMMY FUNCTION TO CAUSE ERROR THAT PREVENTS FURTHER PROCESSING */
  if(isNS) undefinedFunctionToCauseError();
}

//---------------------------------------------------------------
// Forms
//---------------------------------------------------------------

/*
 * Handler used to submit actions
 */
function awpxSubmitHandler(event, formId, actionValue, urlEncodedString, confirmFunction)
{
    /*
     * Check for help
     */
    if (window.awpxHelp_captureKeyEvent) {
        if(!awpxHelp_captureKeyEvent(event)) {
            return false;
        }
    }

    return awpxSubmitWithValue(formId, actionValue, urlEncodedString, confirmFunction);
}

/*
 * Submits the form, but first sets the given url encoded
 * string to allow arbitrary name/value pairs to be set prior
 * to the form being submitted.
 */
function awpxSubmitWithValue(formId, actionValue, urlEncodedString, confirmFunction)
{
    var hidden = document.getElementById(formId + "~action");
    var form = document.getElementById(formId);

    hidden.value = actionValue;

    var doSubmit = true;
    if(confirmFunction)
    {
	doSubmit = confirmFunction();
    }

    if(doSubmit)
    {
        if(urlEncodedString && urlEncodedString.length > 0)
        {
            var sep = '?';
            if(form.action.indexOf('?') != -1)
            {
                sep = '&';
            }
            form.action = form.action + sep + urlEncodedString;
        }

        form.submit();
    }

    return false;
}

/*
 * Submits the form associated with the given form id and
 * sets the hidden action field, if exists, to the specified
 * action.
 */
function awpxSubmit(formId, actionValue, confirmFunction)
{
    return awpxSubmitWithValue(formId, actionValue, '', confirmFunction);
}

/*
 * Ensures that the focus is put on the first visible non-button
 * element in the form, specified by the form name.
 */
function awpxSetFocusOnFirstElement(formName)
{
    if (document.forms.length > 0)
    {
        var elts;
        if (formName)
        {
            elts = document.forms[formName].elements;
        }
        else
        {
            elts = document.forms[0].elements;
        }
        var numElts = elts.length;
        for (var i = 0; i < numElts; i++)
        {
            var type = elts[i].type;
            if(type != "hidden" &&
               type != "submit" &&
               type != "button" &&
               type.indexOf("select") == -1 &&
               ! elts[i].disabled)
            {
                elts[i].focus();
                break;
            }
        }
    }
}

//---------------------------------------------------------------
// Element Navigation/Lookup
//---------------------------------------------------------------
/*
 * Returns the given element.  If the argument is already
 * an object, then it returns it.  Otherwise, it assumes the
 * element is an id that it will lookup using the
 * getElementById mechanism
 */
function awpxGetElement(element)
{
    if (typeof element == "object") {
        return element;
    } else if(typeof element == "string") {
        return document.getElementById(element);
    } else {
        return null;
    }
}

/*
 * Returns an array of elements that have the given class
 *
 * element: The element in which all the elements must reside
 * styleClass: The style class to look for
 * exact: Whether this is an exact match or if the
 *        class simple be one of the classes in the element.
 */
function awpxGetElementsByClass(element, styleClass, exact)
{
    var root = awpxGetElement(element);
    var res = new Array();
    if (isMSIE)
    {
        var all = root.all;
    }
    else
    {
        var all = root.getElementsByTagName("*");
    }

    for(var i=0; i<all.length; i++)
    {
        var el = all[i];
        if(el.className)
        {
            if(!styleClass ||
               (!exact && awpxHasClassName(el, styleClass)) ||
               (exact && el.className == styleClass))
            {
                res[res.length] = el;
            }
        }
    }
    return res;
}

/*
 * Returns the next sibling that is an element.  An element
 * is identified if it has a tagName
 */
function awpxNextElement(element, inclusive)
{
  if(inclusive && element && element.nodeType == 1) {
    return element;
  }

  var cur = element.nextSibling;
  while(cur && cur.nodeType != 1) {
    cur = cur.nextSibling;
  }
  return cur;
}

/*
 * Returns the previous sibling that is an element.  An element
 * is identified if it has a tagName
 */
function awpxPreviousElement(element, inclusive)
{
  if(inclusive && element && element.nodeType == 1) {
    return element;
  }

  var cur = element.previousSibling;
  while(cur && cur.nodeType != 1) {
    cur = cur.previousSibling;
  }
  return cur;
}

//---------------------------------------------------------------
// Highlighting
//---------------------------------------------------------------

/*
 * Specifies that the given object be highlighted or not.  The
 * highlight is performed by applying the given "highlight" class.
 *
 * setTo: true  - turn on highlight,
 *        false - turn off hight
 *        toggle - toggle highlight
 * elements: List of elements to apply this to.  Note that this
 *           traverses all child elements as well.
 */
function awpxHighlight(setTo, elements)
{
    for(var i=1; i<arguments.length; i++)
    {
        awpxSetClassName(arguments[i], setTo, AWPX_CLASS_HIGHLIGHT);
    }
}

//---------------------------------------------------------------
// Selection
//---------------------------------------------------------------

/*
 * Selects multiple values from the value on the given input
 * element.  This is used to transmit a number of selected values
 * into a single field.
 *
 * input: Input id or element into which the values will be put
 * value: The value to use
 * selector: The selector id or element which displays the selections
 * leaveSelectAlone: true - Select element will not add "selected" style
 */
function awpxSelectMultiple(input, value, selector, leaveSelectAlone)
{
    awpxSelect(0, input, value, selector, leaveSelectAlone);
}

/*
 * Selects a single value from the value on the given input
 * element.
 *
 * input: Input id or element into which the values will be put
 * value: The value to use
 * selector: The selector id or element which displays the selections
 * leaveSelectAlone: true - Select element will not add "selected" style
 */
function awpxSelectSingle(input, value, select, leaveSelectAlone)
{
    awpxSelect(1, input, value, select, leaveSelectAlone);
}

/*
 * Selects one or more values from the value on the given input
 * element.
 *
 * maxValues: Maximum number of values to set, 0 - unbounded
 * input: Input id or element into which the values will be put
 * value: The value to use
 * selectof: The selector id or element which displays the selections
 * leaveSelectAlone: true - Select element will not add "selected" style
 */
function awpxSelect(maxValues, input, value, selector, leaveSelectAlone)
{
    var inputElement = awpxGetElement(input);
    var selectorElement = awpxGetElement(selector);
    var currentValue = inputElement.value;
    var setClassNameToSelected;
    if (! currentValue)
        currentValue = "";
    value = escape(value);
    if (maxValues == 1)
    {
        var lastId = AWPX_LAST_SINGLE_SELECTED_PREFIX + inputElement.id;
        var stashOldValueName = "document." + lastId;
        if (currentValue == value)
        {
            setClassNameToSelected = false;
            currentValue = "";
            eval(stashOldValueName + " = '';");
        } else {
            setClassNameToSelected = true;
            currentValue = value;
            var oldElementId = eval(stashOldValueName);
            if (oldElementId)
            {
                var oldElement = document.getElementById(oldElementId);
                awpxSetClassNameDescendants(AWPX_FALSE, AWPX_CLASS_SELECTED, oldElement);
            }
            eval(stashOldValueName + " = '" + selectorElement.id + "';");
        }
    } else {
        var iFound = currentValue.indexOf(value);
        if (iFound == -1)
        {
            // add the selected value
            if (maxValues)
            {
                // check the current number of elements in the input
                var elementArray = currentValue.split(AWPX_VALUE_SEPARATOR);
                if (elementArray.length >= maxValues)
                    return false;
            }
            setClassNameToSelected = true;
            if (currentValue
             && currentValue.lastIndexOf(AWPX_VALUE_SEPARATOR) != currentValue.length)
                currentValue += AWPX_VALUE_SEPARATOR;
            currentValue += value;
        } else {
            // remove the selected value
            setClassNameToSelected = false;
            var valLength = value.length;
            if (currentValue.charAt(valLength + iFound) == AWPX_VALUE_SEPARATOR)
                valLength++;
            currentValue = currentValue.substring(0,iFound) + currentValue.substring(iFound + valLength);
            if (currentValue.charAt(currentValue.length -1) == AWPX_VALUE_SEPARATOR)
                currentValue = currentValue.substring(0,currentValue.length -1);
        }
    }
    inputElement.value = currentValue;
    if (selectorElement && ! leaveSelectAlone)
    {
        awpxSetClassNameDescendants(setClassNameToSelected, AWPX_CLASS_SELECTED, selectorElement);
    }
    return true;
}

//---------------------------------------------------------------
// Dynamically Alter Display
//---------------------------------------------------------------

/*
 * Sets the display state of the given elements.
 *
 * setTo: true - Display on
 *        false - Display off
 *        toggle - Toggle display
 * elements: Elements to affect
 */
function awpxDisplay(setTo, elements)
{
    for(var i=1; i<arguments.length; i++)
    {
        var element = awpxGetElement(arguments[i]);

        /* Handle array argument */
        if(element.length)
        {
            for(var j=0; j<element.length; j++)
            {
                awpxDisplay(setTo, element[j]);
            }
        }
        else
        {
            var curDisplay = element.style.display;
            if(!curDisplay || curDisplay == "")
            {
                curDisplay = "block";
            }

            if(setTo == AWPX_TRUE || (setTo == AWPX_TOGGLE && curDisplay == "none"))
            {
                element.style.display = "block";
            }
            else if(setTo == AWPX_FALSE || (setTo == AWPX_TOGGLE && curDisplay == "block"))
            {
                element.style.display = "none";
            }
        }
    }
}

//---------------------------------------------------------------
// Dynamic Element Style Changes
//---------------------------------------------------------------

/*
 * Specifies that a given set of elements should have a
 * style class either added or removed.  This traverses all
 * child elements as well.
 *
 * setTo: true  - turn on highlight,
 *        false - turn off hight
 *        toggle - toggle highlight
 * styleClass: The style class to add/remove
 * elements: List of elements to apply this to.  Note that this
 *           traverses all child elements as well.
 */
function awpxSetClassNameDescendants(setTo, styleClass, elements)
{
    for(var i=2; i<arguments.length; i++)
    {
        var element = awpxGetElement(arguments[i]);

        /* Handle array argument */
        if(element.length)
        {
            for(var j=0; j<element.length; j++)
            {
                awpxSetClassNameDescendants(setTo, styleClass, element[j]);
            }
        }
        else
        {
            awpxSetClassName(element, setTo, styleClass);
            if(element.firstChild)
            {
                var child = awpxNextElement(element.firstChild, true);
                while(child) {
                  awpxSetClassNameDescendants(setTo, styleClass, child);
                  child = awpxNextElement(child);
                }
            }
        }
    }
}

/*
 * Adds/Removes a style class to/from a specified target element
 *
 * element: The element of interest
 * setTo: true - Add, false - Remove, toggle - Add/Remove
 * styleClass: The class to add/remove/toggle
 */
function awpxSetClassName(element, setTo, styleclass)
{
    if(!element) return;

    var isOn = awpxHasClassName(element, styleclass);
    if(setTo == AWPX_TOGGLE)
    {
        setTo = !isOn;
    }

    if(setTo && !isOn)
    {
        awpxAddClassName(element, styleclass);
    }
    else if(!setTo && isOn)
    {
        awpxRemoveClassName(element, styleclass);
    }
}

/*
 * Returns if the given styleclass resides in the
 * element.
 */
function awpxHasClassName(element, styleclass)
{
    var el = awpxGetElement(element);

    if(el.className)
    {
        var elStyles = el.className.split(' ');
        for(var i=0; i<elStyles.length; i++)
        {
            if(elStyles[i] == styleclass)
            {
                return true;
            }
        }
        return false;
    }
    else
    {
        return false;
    }
}

/*
 * Adds a given style class from the specified
 * element.  This returns the modified style class.
 * This does not perform any checking if the
 * class already exists.
 */
function awpxAddClassName(element, styleclass)
{
    var el = awpxGetElement(element);

    if(!el.className)
    {
        el.className = styleclass;
        return el.className;
    }
    else
    {
        var elStyles = el.className.split(' ');
        elStyles[elStyles.length] = styleclass;
        el.className = elStyles.join(' ');
        return el.className;
    }
}

/*
 * Removes a given style class from the specified
 * element.  This returns the modified style class.
 */
function awpxRemoveClassName(element, styleclass)
{
    var el = awpxGetElement(element);

    var result = new Array();
    var elStyles = el.className.split(' ');
    for(var i=0; i<elStyles.length; i++)
    {
        if(elStyles[i] != styleclass)
        {
            result[result.length] = elStyles[i];
        }
    }
    el.className = result.join(' ');
    return el.className;
}

//---------------------------------------------------------------
// Absolute Positioning
//---------------------------------------------------------------

/*
 * Returns the absolute pixel position of the left edge of the
 * given element
 */
function awpxAbsoluteLeft(element)
{
    var absLeft = element.offsetLeft;
    if(element.offsetParent)
    {
       absLeft += awpxAbsoluteLeft(element.offsetParent);
    }
    return absLeft;
}

/*
 * Returns the absolute pixel position of the top edge of the
 * given element
 */
function awpxAbsoluteTop(element)
{
    var absTop = element.offsetTop;
    if(element.offsetParent)
    {
       absTop += awpxAbsoluteTop(element.offsetParent);
    }
    return absTop;
}

//---------------------------------------------------------------
// String Functions
//---------------------------------------------------------------

/*
 * Add trim() functionality to Strings
 */
String.prototype.trim = function () {
    var re = /^\s*(\S.*\S)\s*$/;
    if(this.search(re) != -1) {
       return RegExp.$1;
    }
    return this;
}

//---------------------------------------------------------------
// Array Functions
//---------------------------------------------------------------

/*
 * Returns the index of the element in the array or -1 if
 * not found
 */
Array.prototype.indexOf = function(element) {
    var array  = this;
    var length = array.length;
    for(var index = 0; index<length; index++) {
        if(element == array[index]) {
            return index;
        }
    }
    return -1;
}

//---------------------------------------------------------------
// Cookie Objects
//---------------------------------------------------------------

/*
 * Creates a new cookie in the current document
 * document: The document the cookie will be stored with
 * name: The name of the cookie
 * value: The value of the cookie (will be escaped)
 * days: Optional number of days before cookie should expire
 * path: Optional path for the cookie
 * domain: Optional domain for the cookie
 * secure: Optional boolean that indicates if the cookie must be secure
 */
function Cookie(document, name, value, days, path, domain, secure)
{
    this.document = document;
    this.name     = name;
    this.value    = escape(value);
    if(days) {
        var today = new Date();
        this.expires = new Date(today.getTime() + days*24*3600*1000);
    } else {
        this.expires = null;
    }
    this.path   = path;
    this.domain = domain;
    this.secure = secure;
}

Cookie.prototype.save = function() {
    var cookie = this.name + "=" + this.value;
    if(this.expires) {
        cookie += "; expires=" + this.expires.toGMTString();
    }
    if(this.path) {
        cookie += "; path=" + this.path;
    }
    if(this.domain) {
        cookie += "; domain=" + this.domain;
    }
    if(this.secure) {
        cookie += "; secure";
    }
    this.document.cookie = cookie;
}

Cookie.prototype.load = function() {
    var allcookies = this.document.cookie;
    if(allcookies == "") return false;

    // Extract cookie value from all cookies in document
    var startIdx = allcookies.indexOf(this.name + "=");
    if(startIdx == -1) return false;
    startIdx += this.name.length + 1;
    var endIdx = allcookies.indexOf(';', startIdx);
    if(endIdx == -1) endIdx = allcookies.length;

    // Store cookie value
    this.value = unescape(allcookies.substring(startIdx, endIdx));
    return true;
}

//---------------------------------------------------------------
// Link Functions
//---------------------------------------------------------------

/*
 * Performs the click just as if the user clicked the link
 * through the UI
 */
function awpxClick(link)
{
    var linkEl = awpxGetElement(link);
    if(isMSIE) {
        linkEl.click();
    } else {
        var executeAction = true;
        if(linkEl.onclick) {
            executeAction = this.onclick({type: 'click'});
        }
        if(executeAction) {
            open (linkEl.href, linkEl.target ? linkEl.target : '_self');
        }
    }
}