if (ll == null) var ll = {};
if (ll.util == null) ll.util = {};

//Formatting
var USER_DATE_FORMAT = 0;
var USER_NUMBER_FORMAT = 0;

//Temporary function for testing, to be removed prior to production deployment
var DATA_FORMAT_ERROR_MESSAGE_SHOWN = false;
function _check_and_alert_data_format() {
/*    if (!DATA_FORMAT_ERROR_MESSAGE_SHOWN && (USER_NUMBER_FORMAT == 0 || USER_DATE_FORMAT == 0)) {
        alert("Date/Number formats haven't been initialized prior to use.  Please report this bug.");
        DATA_FORMAT_ERROR_MESSAGE_SHOWN = true;
    }*/
}

ll.util.initFormats = function (date, number) {
    USER_DATE_FORMAT = date;
    USER_NUMBER_FORMAT = number;

    if (USER_DATE_FORMAT == DATE_FORMAT_MIDDLE_ENDIAN) {
        iDate = "This field must be a valid date (like 01/31/2000).  Please re-enter it now.";
    } else if (USER_DATE_FORMAT == DATE_FORMAT_LITTLE_ENDIAN) {
        iDate = "This field must be a valid date (like 31/01/2000).  Please re-enter it now.";
    } else if (USER_DATE_FORMAT == DATE_FORMAT_BIG_ENDIAN) {
        iDate = "This field must be a valid date (like 2000-01-31).  Please re-enter it now.";
    }
}

// JavaScript library for form field validation

var digits = "0123456789";
var lowercaseLetters = "abcdefghijklmnopqrstuvwxyz";
var uppercaseLetters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";

var allowedSpecialCharacters = "/-,.;()";
var allowedRefNumCharacters = digits + lowercaseLetters + uppercaseLetters + "-_/\\:.#$()+";
var maxRefNumLength = 50;
var doubleQuote = '\"';

var allowedSeparatorCharacters = ", ;";
var whitespace = " \t\n\r\xA0"; // \xA0 is unicode char 160: &nbsp;

var phoneNumberDelimiters = "()- ";
var validUSPhoneChars = digits + phoneNumberDelimiters;
var validWorldPhoneChars = digits + phoneNumberDelimiters + "+";

var digitsInUSPhoneNumber = 10;
var ZIPCodeDelimiters = "-";
var ZIPCodeDelimeter = "-";
var validZIPCodeChars = digits + ZIPCodeDelimiters;
var digitsInZIPCode1 = 5;
var digitsInZIPCode2 = 9;
var mPrefix = "A value must be entered into the ";
var mSuffix = " field. This is a required field. Please enter it now.";

var sUSLastName = "Last Name";
var sUSFirstName = "First Name";
var sWorldLastName = "Family Name";
var sWorldFirstName = "Given Name";
var sTitle = "Title";
var sCompanyName = "Company Name";
var sUSAddress = "Street Address";
var sWorldAddress = "Address";
var sCity = "City";
var sStateCode = "State Code";
var sWorldState = "State, Province, or Prefecture";
var sCountry = "Country";
var sZIPCode = "ZIP Code";
var sWorldPostalCode = "Postal Code";
var sPhone = "Phone Number";
var sFax = "Fax Number";
var sDateOfBirth = "Date of Birth";
var sExpirationDate = "Expiration Date";
var sEmail = "Email";
var sSSN = "Social Security Number";
var sOtherInfo = "Other Information";

var iZIPCode = "This field must be a 5 or 9 digit U.S. Postal Code (like 94043). Please re-enter it now.";
var iUSPhone = "This field must be a 10 digit U.S. phone number (like 415 555 1212). Please re-enter it now.";
var iWorldPhone = "This field must be a valid international phone number. Please re-enter it now.";
var iSSN = "This field must be a 9 digit U.S. social security number (like 123 45 6789). Please re-enter it now.";
var iEmail = "This field must be a valid email address (like foo@bar.com). Please re-enter it now.";
var iDay = "This field must be a day number between 1 and 31.  Please re-enter it now.";
var iMonth = "This field must be a month number between 1 and 12.  Please re-enter it now.";
var iYear = "This field must be a 2 or 4 digit year number.  Please re-enter it now.";
var iDatePrefix = "The Day, Month, and Year for ";
var iDateSuffix = " do not form a valid date.  Please re-enter them now.";
var iDate = "This field must be a valid date (like 04/01/2000).  Please re-enter it now.";
var iTime = "This field must be a valid time (like 13:30).  Please re-enter it now.";

var iInteger = "This field must be a whole number value. Please re-enter it now.";
var iPositiveInteger = "This field must be a positive whole number value. Please re-enter it now.";
var iAlphabetic = "This field must contain only letters. Please re-enter it now.";
var iAlphaNumeric = "This field must contain only letters or numbers.  Please re-enter it now.";
var iAlphaNumericSlashOrDash = "This field must contain only letters, numbers, / ( ) , . or -.  Please re-enter it now.";
var iNumber = "This field must contain only numeric values. Please re-enter it now.";
var iCustom = "Invalid value.  Please re-enter.";
var iFloat  = "This field must contain only decimal numeric values.  Please re-enter it now.";

var pEntryPrompt = "Please enter a ";
var pStateCode = "2 character code (like CA).";
var pZIPCode = "5 or 9 digit U.S. Postal Code (like 94043).";
var pUSPhone = "10 digit U.S. phone number (like 415 555 1212).";
var pWorldPhone = "international phone number.";
var pEmail = "valid email address (like foo@bar.com).";
var pDay = "day number between 1 and 31.";
var pMonth = "month number between 1 and 12.";
var pYear = "2 or 4 digit year number.";

var timerInUse = false;

/*These dimensions are also referenced in LoadReport2.jsp, but are not referenced as JavaScript variables.
 *Therefore, if you change these values here, please change them in LoadReport2.jsp as well.
 */
var fixedPopupWindowWidth = 1024;
var fixedPopupWindowHeight = 768;

//Variables for window dimensions
var windowTitleBarHeight = 32;
var windowScrollBarWidth = 17;
var windowSideBarWidth = 6;

//The amount of space desired between the outside of a window and the screen borders (excluding the start bar)
var windowSizeBuffer = 30;

var defaultEmptyOK = false;

var daysInMonth = new Array();
daysInMonth[1] = 31;
daysInMonth[2] = 29;   // must programmatically check this
daysInMonth[3] = 31;
daysInMonth[4] = 30;
daysInMonth[5] = 31;
daysInMonth[6] = 30;
daysInMonth[7] = 31;
daysInMonth[8] = 31;
daysInMonth[9] = 30;
daysInMonth[10] = 31;
daysInMonth[11] = 30;
daysInMonth[12] = 31;

function isEmpty(s) {
    return ((s == null) || (s.length == 0));
}

function isEmptyNumber(s) {
    return (isEmpty(s) || s*1 == 0);
}

function isWhitespace (s) {
    var i;
    if (isEmpty(s)) {
        return true;
    }
    for (i = 0; i < s.length; i++) {
        var c = s.charAt(i);
        if (whitespace.indexOf(c) == -1) {
            return false;
        }
    }
    return true;
}

function containsWhitespace(s) {
    var i;
    var toReturn = false;
    if (isEmpty(s)) {
        toReturn = true;
    }
    for (i = 0; i < s.length; i++) {
        var c = s.charAt(i);
        if (whitespace.indexOf(c) >= 0) {
            toReturn = true;
        }
    }
    return toReturn;
}

function stripCharsInBag (s, bag) {
    var i;
    var returnString = "";
    for (i = 0; i < s.length; i++) {
        var c = s.charAt(i);
        if (bag.indexOf(c) == -1) {
            returnString += c;
        }
    }
    return returnString;
}

function stripCharsNotInBag (s, bag) {
    var i;
    var returnString = "";
    for (i = 0; i < s.length; i++) {
        var c = s.charAt(i);
        if (bag.indexOf(c) != -1) {
            returnString += c;
        }
    }
    return returnString;
}

function stripWhitespace (s) {
    return stripCharsInBag (s, whitespace);
}


function charInString (c, s) {
    for (var i = 0; i < s.length; i++) {
        if (s.charAt(i) == c) {
           return true;
        }
    }
    return false;
}

function trim(str) {
    return stripTrailingWhitespace(stripInitialWhitespace(str));
}

function stripInitialWhitespace (s) {
    var i = 0;
    while ((i < s.length) && charInString (s.charAt(i), whitespace)) {
       //alert(i + ": " + s.charCodeAt(i));
       i++;
    }
    return s.substr(i);
}

function stripTrailingWhitespace (s) {
    var i = s.length - 1;
    while ((i >= 0) && charInString(s.charAt(i), whitespace)) {
       //alert(i + ": " + s.charCodeAt(i));
       i--;
    }
    return s.substring (0, i+1);
}

//Allows blanks as well as letters
function isLetter (c) {
    return ( ((c >= "a") && (c <= "z")) || ((c >= "A") && (c <= "Z")) || (c==" "));
}

function isDigit (c) {
    return ((c >= "0") && (c <= "9"));
}

function isLetterOrDigit (c) {
    return (isLetter(c) || isDigit(c));
}

function isInteger (s) {
    var i;
    if (isEmpty(s)) {
        if (isInteger.arguments.length == 1) {
           return defaultEmptyOK;
        } else {
            return isInteger.arguments[1];
        }
    }
    for (i = 0; i < s.length; i++) {
        var c = s.charAt(i);
        if (!isDigit(c)) {
            return false;
        }
    }
    return true;
}

function isSignedInteger (s) {
    if (isEmpty(s)) {
        if (isSignedInteger.arguments.length == 1) {
           return defaultEmptyOK;
        } else {
            return isSignedInteger.arguments[1];
        }
    } else {
        var startPos = 0;
        var secondArg = defaultEmptyOK;
        if (isSignedInteger.arguments.length > 1) {
            secondArg = isSignedInteger.arguments[1];
        }
        if ( (s.charAt(0) == "-") || (s.charAt(0) == "+") ) {
           startPos = 1;
        }
        return (isInteger(s.substr(startPos), secondArg));
    }
}

function isPositiveInteger (s) {
    var secondArg = defaultEmptyOK;
    if (isPositiveInteger.arguments.length > 1) {
        secondArg = isPositiveInteger.arguments[1];
    }
    return (isSignedInteger(s, secondArg)
         && ( (isEmpty(s) && secondArg)  || (parseInt (s) > 0) ) );
}

function isNonnegativeInteger (s) {
    var secondArg = defaultEmptyOK;
    if (isNonnegativeInteger.arguments.length > 1) {
        secondArg = isNonnegativeInteger.arguments[1];
    }
    return (isSignedInteger(s, secondArg)
         && ( (isEmpty(s) && secondArg)  || (parseInt (s) >= 0) ) );
}

function isNegativeInteger (s) {
    var secondArg = defaultEmptyOK;
    if (isNegativeInteger.arguments.length > 1) {
        secondArg = isNegativeInteger.arguments[1];
    }
    return (isSignedInteger(s, secondArg)
         && ( (isEmpty(s) && secondArg)  || (parseInt (s) < 0) ) );
}

function isNonpositiveInteger (s) {
    var secondArg = defaultEmptyOK;
    if (isNonpositiveInteger.arguments.length > 1) {
        secondArg = isNonpositiveInteger.arguments[1];
    }
    return (isSignedInteger(s, secondArg)
         && ( (isEmpty(s) && secondArg)  || (parseInt (s) <= 0) ) );
}

function isFloat (s) {
    var i;
    var seenDecimalPoint = false;
    if (isEmpty(s)) {
        if (isFloat.arguments.length == 1) {
            return defaultEmptyOK;
        } else {
            return isFloat.arguments[1];
        }
    }
    if (s == ".") {
        return false;
    }
    for (i = 0; i < s.length; i++) {
        // Check that current character is number.
        var c = s.charAt(i);
        if ((c == ".") && !seenDecimalPoint) {
            seenDecimalPoint = true;
        } else if (!isDigit(c)) {
            return false;
        }
    }
    return true;
}

function isNonNegativeFloat (s, emptyOK) {
    if(emptyOK == null) {
        emptyOK = defaultEmptyOK;
    }
    if(isEmpty(s)) {
        return emptyOK;
    } else {
        // if the leading char is -, it is a negative number
        var c = s.charAt(0);
        if(c == "-") {
            return false;
        } else {
            return (isFloat(s,emptyOK));
        }
    }
}

function isSignedFloat (s) {
    if (isEmpty(s)) {
        if (isSignedFloat.arguments.length == 1) {
            return defaultEmptyOK;
        } else {
            return isSignedFloat.arguments[1];
        }
    } else {
        var startPos = 0;
        var secondArg = defaultEmptyOK;
        if (isSignedFloat.arguments.length > 1) {
            secondArg = isSignedFloat.arguments[1];
        }
        // skip leading + or -
        if ( (s.charAt(0) == "-") || (s.charAt(0) == "+") ) {
           startPos = 1;
        }
        return (isFloat(s.substr(startPos), secondArg));
    }
}

// returns true if s does not have more than specified number of decimals
function isPrecise(s, maxNumDecimals, emptyOK) {
    if(emptyOK == null) {
        emptyOK = defaultEmptyOK;
    }
    if(isEmpty(s)) {
        return emptyOK;
    } else {
        if(isFloat(s,emptyOK)) {
            // search s for a decimal point
            for(var i = 0; i < s.length; i++) {
                if(s.charAt(i) == ".") {
                    if( s.length - 1 - i > maxNumDecimals ) {
                        // There were more decimals than the maxNumDecimals
                        return false;
                    } else {
                        return true;
                    }
                }
            }
            // no decimal point was found, input was an integer
            return true;
        } else {
            return false;
        }
    }
}

function isAlphabetic (s) {
    if (isEmpty(s)) {
        if (isAlphabetic.arguments.length == 1) {
            return defaultEmptyOK;
        } else {
            return isAlphabetic.arguments[1];
        }
    }
    for (var i=0; i < s.length; i++) {
        // Check that current character is letter.
        var c = s.charAt(i);
        if (!isLetter(c)) {
            return false;
        }
    }
    // All characters are letters.
    return true;
}

function isAlphanumeric (s) {
    if (isEmpty(s)) {
        if (isAlphanumeric.arguments.length == 1) {
            return defaultEmptyOK;
        } else {
            return isAlphanumeric.arguments[1];
        }
    }
    for (var i=0; i < s.length; i++) {
        var c = s.charAt(i);
        if (! (isLetter(c) || isDigit(c) ) ) {
            return false;
        }
    }
    return true;
}

function isString(s) {
    var secondArg = defaultEmptyOK;
    if (isString.arguments.length > 1) {
        secondArg = isString.arguments[1];
    }
    return isAlphanumericSlashOrDash(s, secondArg);
}

function isCityString(s) {
    var secondArg = defaultEmptyOK;
    if (isCityString.arguments.length > 1) {
        secondArg = isCityString.arguments[1];
    }
    return isAlphanumericSlashOrDashOrApostrophe(s, secondArg);
}

function isAlphanumericSlashOrDash (s) {
    if (isEmpty(s)) {
        if (isAlphanumericSlashOrDash.arguments.length == 1) {
            return defaultEmptyOK;
        } else {
            return isAlphanumericSlashOrDash.arguments[1];
        }
    }
    for (var i=0; i < s.length; i++) {
        var c = s.charAt(i);
        if (! (isLetter(c) || isDigit(c) || charInString (c, allowedSpecialCharacters)) ) {
            return false;
        }
    }
    return true;
}

function isAlphanumericSlashOrDashOrApostrophe (s) {
    if (isEmpty(s)) {
        if (isAlphanumericSlashOrDashOrApostrophe.arguments.length == 1) {
            return defaultEmptyOK;
        } else {
            return isAlphanumericSlashOrDashOrApostrophe.arguments[1];
        }
    }
    for (var i=0; i < s.length; i++) {
        var c = s.charAt(i);
        if (! (c == "'" || isLetter(c) || isDigit(c) || charInString (c, allowedSpecialCharacters)) ) {
            return false;
        }
    }
    return true;
}

function reformat (s) {
    var arg;
    var sPos = 0;
    var resultString = "";
    for (var i = 1; i < reformat.arguments.length; i++) {
       arg = reformat.arguments[i];
       if (i % 2 == 1) {
           resultString += arg;
       } else {
           resultString += s.substring(sPos, sPos + arg);
           sPos += arg;
       }
    }
    return resultString;
}


function isUSPhoneNumber (s) {
    if (isEmpty(s)) {
        if (isUSPhoneNumber.arguments.length == 1) {
            return defaultEmptyOK;
        } else {
            return isUSPhoneNumber.arguments[1];
        }
    }
    return (isInteger(s) && s.length == digitsInUSPhoneNumber);
}

function isInternationalPhoneNumber (s) {
    if (isEmpty(s)) {
        if (isInternationalPhoneNumber.arguments.length == 1) {
            return defaultEmptyOK;
        } else {
            return isInternationalPhoneNumber.arguments[1];
        }
    }
    return (isPositiveInteger(s));
}

function isZIPCode (s) {
    if (isEmpty(s)) {
        if (isZIPCode.arguments.length == 1) {
            return defaultEmptyOK;
        } else {
            return isZIPCode.arguments[1];
        }
    }
   return (isInteger(s) &&
            ((s.length == digitsInZIPCode1) ||
             (s.length == digitsInZIPCode2)));
}

function isvalidEmailChar (s) {
    var i;
    for (i = 0; i < s.length; i++) {
        var c = s.charAt(i);
        if (! (isLetter(c) || isDigit(c) || (c=='@') || (c=='.') || (c=='_') || (c=='-') || (c=='+')) ) {
            return false;
        }
    }
    return true;
}

function isEmail (s) {
    if (isEmpty(s)) {
        if (isEmail.arguments.length == 1) {
            return defaultEmptyOK;
        } else {
            return isEmail.arguments[1];
        }
    }
    if (isWhitespace(s)) {
        return false;
    }
    if (!isvalidEmailChar(s)) {
        return false;
    }
    atOffset = s.lastIndexOf('@');
    if ( atOffset < 1 ) {
        return false;
    } else {
        dotOffset = s.indexOf('.', atOffset);
        if ( dotOffset < atOffset + 2 || dotOffset > s.length - 2 ) {
            return false;
        }
    }
    return true;
}

function isIntegerInRange (s, a, b) {
    if (isEmpty(s)) {
        if (isIntegerInRange.arguments.length == 1) {
            return defaultEmptyOK;
        } else {
            return isIntegerInRange.arguments[1];
        }
    }
    if (!isInteger(s, false)) {
        return false;
    }
//    var num = parseInt(s);  //flakes out on '08' and '09'
    var num = s*1;
    return ((num >= a) && (num <= b));
}

function isFloatInRange(s,a,b) {
    if (isEmpty(s)) {
        if (isFloatInRange.arguments.length == 1) {
            return defaultEmptyOK;
        } else {
            return isFloatInRange.arguments[1];
        }
    }
    if (!isFloat(s, false)) {
        return false;
    }
    var num = s*1.0;
    return ((num >= a) && (num <= b));
}

function isYear (s) {
    if (isEmpty(s)) {
        if (isYear.arguments.length == 1) {
            return defaultEmptyOK;
        } else {
            return isYear.arguments[1];
        }
    }
    if (!isNonnegativeInteger(s)) {
        return false;
    }
    return ((s.length == 2) || (s.length == 4));
}

function isMonth (s) {
    if (isEmpty(s)) {
        if (isMonth.arguments.length == 1) {
            return defaultEmptyOK;
        } else {
            return isMonth.arguments[1];
        }
    }
    return isIntegerInRange (s, 1, 12);
}

function isDay (s) {
    if (isEmpty(s)) {
        if (isDay.arguments.length == 1) {
            return defaultEmptyOK;
        } else {
            return isDay.arguments[1];
        }
    }
    return isIntegerInRange (s, 1, 31);
}

function daysInFebruary (year) {
    return ( ((year % 4 == 0) && (!(year % 100 == 0) || (year % 400 == 0) ) ) ? 29 : 28 );
}

function isDate (year, month, day) {
    if (! (isYear(year, false) && isMonth(month, false) && isDay(day, false))) {
        return false;
    }

    var intYear = year*1;
    var intMonth = month*1;
    var intDay = day*1;
    if (intDay > daysInMonth[intMonth]) {
        return false;
    }
    if ((intMonth == 2) && (intDay > daysInFebruary(intYear))) {
        return false;
    }
    return true;
}

function isHour (s) {
    return isIntegerInRange (s, 0, 23);
}

function isMinute (s) {
    return isIntegerInRange (s, 0, 59);
}

function isTime (hour, minute) {
    if (! (isHour(hour) && isMinute(minute))) {
        return false;
    }
    return true;
}

function promptEntry (s) {
    window.status = pEntryPrompt + s
}

function warnEmpty (theField, s) {
    theField.focus();
    alert(mPrefix + s + mSuffix);
    return false;
}

function warnInvalid (theField, s) {
    // fix for firefox .focus() bug
    var formName;
    if (theField.form) {
        formName = theField.form.name;
    }
    var fieldName = theField.name;
    var fieldID = theField.id;
    if( !timerInUse) {
        if (fieldID || (formName && document.forms[formName] && document.forms[formName].elements[fieldName])) {
            timerInUse = true;
            setTimeout("warnInvalidTimer('" + fieldID + "', '" + formName + "', '" + fieldName + "', '" + s + "');", 10);
        } else {
            //Fall back to just showing the alert if we can't trigger the focus asynchronously
            alert(s);
        }
    }
    return false;
}

function warnInvalidTimer(fieldID, formName, fieldName, s) {
    alert(s);
    var element = null;
    if (fieldID) {
        element = document.getElementById(fieldID);
    } else if (formName && document.forms[formName]) {
        element = document.forms[formName].elements[fieldName];
    }
    if (element) {
        element.focus();
        element.select();
    }
    setTimeout('timerInUse = false;', 10);
}

//Special for for NAB
function checkExpression(theField, sExpr, emptyOK) {
    if (checkExpression.arguments.length == 2) {
        emptyOK = defaultEmptyOK;
    }
    if (emptyOK && isEmpty(theField.value)) {
        return true;
    }
    if (!theField.eval(sExpr)) {
        return warnInvalid(theField, iCustom)
    } else {
        return true;
    }
}

//NAB
function checkNumber (theField, emptyOK) {
    if (checkNumber.arguments.length == 1) {
        emptyOK = defaultEmptyOK;
    }
    if (emptyOK && isEmpty(theField.value)) {
        return true;
    } else if (!isSignedFloat(theField.value, false)) {
        return warnInvalid (theField, iNumber);
    } else {
        return true;
    }
}

//NAB
function checkInteger (theField, emptyOK) {
    if (checkInteger.arguments.length == 1) {
        emptyOK = defaultEmptyOK;
    }
    if (emptyOK && isEmpty(theField.value)) {
        return true;
    } else if (!isSignedInteger(theField.value, false)) {
        return warnInvalid (theField, iInteger);
    } else {
        return true;
    }
}

//NAB
function checkPositiveInteger (theField, emptyOK) {
    if (checkPositiveInteger.arguments.length == 1) {
        emptyOK = defaultEmptyOK;
    }
    if (emptyOK && isEmpty(theField.value)) {
        return true;
    }
    if (theField.value.substring(0,1)=="+") {
        sNum = theField.value.substr(1);
    } else {
        sNum = theField.value;
    }
    if (!isInteger(sNum, false)) {
        return warnInvalid (theField, iPositiveInteger);
    } else {
        return true;
    }
}

function checkFloat (theField, emptyOK) {
    if (checkFloat.arguments.length == 1) {
        emptyOK = defaultEmptyOK;
    }
    if (emptyOK && isEmpty(theField.value)) {
        return true;
    } else if (!isFloat(theField.value, false)) {
        return warnInvalid (theField, iFloat);
    } else {
        return true;
    }
}

//NAB
function checkAlphabetic (theField, emptyOK) {
    if (checkAlphabetic.arguments.length == 1) {
        emptyOK = defaultEmptyOK;
    }
    if (emptyOK && isEmpty(theField.value)) {
        return true;
    } else if (!isAlphabetic(theField.value, false)) {
        return warnInvalid (theField, iAlphabetic);
    } else {
        return true;
    }
}

function checkAlphaNumeric (theField, emptyOK) {
    if (checkAlphaNumeric.arguments.length == 1) {
        emptyOK = defaultEmptyOK;
    }
    if (emptyOK && isEmpty(theField.value)) {
        return true;
    } else if (!isAlphanumeric(theField.value, false)) {
        return warnInvalid (theField, iAlphaNumeric);
    } else {
        return true;
    }
}

function checkAlphaNumericSlashOrDash (theField, emptyOK) {
    if (checkAlphaNumericSlashOrDash.arguments.length == 1) {
        emptyOK = defaultEmptyOK;
    }
    if (emptyOK && isEmpty(theField.value)) {
        return true;
    } else if (!isAlphanumericSlashOrDash(theField.value, false)) {
        return warnInvalid (theField, iAlphaNumericSlashOrDash);
    } else {
        return true;
    }
}

function checkString (theField, s, emptyOK) {
    if (checkString.arguments.length == 2) {
        emptyOK = defaultEmptyOK;
    }
    if (emptyOK && isEmpty(theField.value)) {
        return true;
    }
    if (isWhitespace(theField.value)) {
        return warnEmpty (theField, s);
    } else {
        return true;
    }
}

function reformatZIPCode (ZIPString) {
    if (ZIPString.length == 5) {
        return ZIPString;
    } else {
        return (reformat (ZIPString, "", 5, "-", 4));
    }
}

function checkZIPCode (theField, emptyOK) {
    if (checkZIPCode.arguments.length == 1) {
        emptyOK = defaultEmptyOK;
    }
    if (emptyOK && isEmpty(theField.value)) {
        return true;
    } else {
        var normalizedZIP = stripCharsInBag(theField.value, ZIPCodeDelimiters);
        if (!isZIPCode(normalizedZIP, false)) {
            return warnInvalid (theField, iZIPCode);
        } else {
            theField.value = reformatZIPCode(normalizedZIP)
            return true;
        }
    }
}

function reformatUSPhone (USPhone) {
    return (reformat (USPhone, "(", 3, ") ", 3, "-", 4));
}

function checkUSPhone (theField, emptyOK) {
    if (checkUSPhone.arguments.length == 1) {
        emptyOK = defaultEmptyOK;
    }
    if (emptyOK && isEmpty(theField.value)) {
        return true;
    } else {
        var normalizedPhone = stripCharsInBag(theField.value, phoneNumberDelimiters);
        if (!isUSPhoneNumber(normalizedPhone, false)) {
            return warnInvalid (theField, iUSPhone);
        } else {
            // theField.value = reformatUSPhone(normalizedPhone)
            return true;
        }
    }
}

function checkInternationalPhone (theField, emptyOK) {
    if (checkInternationalPhone.arguments.length == 1) {
        emptyOK = defaultEmptyOK;
    }
    if (emptyOK && isEmpty(theField.value)) {
        return true;
    } else {
        if (!isInternationalPhoneNumber(theField.value, false)) {
            return warnInvalid (theField, iWorldPhone);
        } else {
            return true;
        }
    }
}

function checkEmail (theField, emptyOK) {
    if (checkEmail.arguments.length == 1) {
        emptyOK = defaultEmptyOK;
    }
    if (emptyOK && isEmpty(theField.value)) {
        return true;
    } else if (!isEmail(theField.value, false)) {
        return warnInvalid (theField, iEmail);
    } else {
        return true;
    }
}

function checkYear (theField, emptyOK) {
    if (checkYear.arguments.length == 1) {
        emptyOK = defaultEmptyOK;
    }
    if (emptyOK && isEmpty(theField.value)) {
        return true;
    }
    if (!isYear(theField.value, false)) {
        return warnInvalid (theField, iYear);
    } else {
        return true;
    }
}

function checkMonth (theField, emptyOK) {
    if (checkMonth.arguments.length == 1) {
        emptyOK = defaultEmptyOK;
    }
    if (emptyOK && isEmpty(theField.value)) {
        return true;
    }
    if (!isMonth(theField.value, false)) {
        return warnInvalid (theField, iMonth);
    } else {
        return true;
    }
}

function checkDay (theField, emptyOK) {
    if (checkDay.arguments.length == 1) {
        emptyOK = defaultEmptyOK;
    }
    if (emptyOK && isEmpty(theField.value)) {
        return true;
    }
    if (!isDay(theField.value, false)) {
        return warnInvalid (theField, iDay);
    } else {
        return true;
    }
}

//-----------------------------------------------
// converts a date string (formatted mm/dd/yyyy) to a javascript Date object
function jsDate(inDateString) {
    var mm = (inDateString.substring(0, inDateString.indexOf("/")*1)-1);
    var dd = inDateString.substring(inDateString.indexOf("/")+1, inDateString.lastIndexOf("/"));
    var yyyy = inDateString.substr(inDateString.lastIndexOf("/")+1);
    return new Date(yyyy, mm, dd);
}

//-----------------------------------------------
// converts a date string (formatted mm/dd/yyyy) to a javascript Date object and adds hours and minutes
function jsDateTime(inDateString, hours, minutes) {
    var newDate = jsDate(inDateString);
    newDate.setHours(hours);
    newDate.setMinutes(minutes);
    return newDate;
}

//converts a date string (formatted mm/dd/yyyy) to a javascript Date object and adds a date time string (formatted hh:mm) if it exists
function getJSDateMilitaryTime(inDateString, inTimeString) {
    var newDate = jsDate(inDateString);
    if (inTimeString != null) {
        var sArray = inTimeString.split(":");
        if (sArray.length == 2) {
            var hour = sArray[0];
            var minutes = sArray[1];
            if (isTime(hour, minutes)) {
                newDate.setHours(hour);
                newDate.setMinutes(minutes);
            }
        }
    }
    return newDate;
}

//-----------------------------------------------
// change from format: mm/dd/yy
//    to format mm/dd/yyyy
function changeDateFmt(theField) {
    var m, d, y;
    if ( theField.value.indexOf("-") >= 0 ) {
        tmp = theField.value + "";
        m = tmp.substring(0, tmp.indexOf("-"));
        d = tmp.substring(tmp.indexOf("-")+1, tmp.lastIndexOf("-"));
        y = tmp.substr(tmp.lastIndexOf("-")+1)*1;
    } else {
        tmp = theField.value + "";
        m = tmp.substring(0,tmp.indexOf("/"));
        d = tmp.substring(tmp.indexOf("/")+1, tmp.lastIndexOf("/"));
        y = tmp.substr(tmp.lastIndexOf("/")+1)*1;
    }
    if (y < 100) {
        y += 2000;
    }
    // theField.value = m + "/" + d + "/" + y;
    theField.value = getPad(2,m,'0') + m + "/" + getPad(2,d,'0') + d + "/" + y;
}

// Return the characters to add to a string to
// increase the string to the required length.
// padchar - The character to use when padding.
// strlen - the length to pad to
// instr  - the string to pad
function getPad(strlen, instr, padchar) {
    instr = instr + "";
    var padstr = "";
    for (var i=0; i < (strlen - instr.length); i++) {
        padstr = padstr + padchar;
    }
    return padstr;
}  //getPad

// Date of format month/day
// if difference to today > warnDiff ask to confirm
function getDateFromShortDate(dateString, warnDiff) {
    if (getDateFromShortDate.arguments.length == 1) {
        warnDiff = 90; //warn if > 90 days in the past --> really, it controls whether to roll the date to next year
    }

    var dateFld = stripCharsNotInBag(dateString, "0123456789/-");

    // dateFld = (dateFld.length != 4) ? "0" + dateFld : dateFld;
    var dateNbrs = stripCharsNotInBag(dateString, "0123456789");

    var idx = dateFld.indexOf('/');
    if (idx < 0) {
        idx = dateFld.indexOf('-');
        if (idx < 0) {   //if neither '/' or '-' then assume MMDD format
            idx = 2;
        }
    }

    var month = dateNbrs.substring(0,idx);
    var day = dateNbrs.substr(idx);

    if (month.length < 2) {
        month = "0" + month;
    }
    if (day.length < 2) {
        day = "0" + day;
    }
    if ((month.length + day.length) != 4) {
        return dateString;
    }

    var today = new Date();
    var lowerBound = new Date(today.getTime() - (warnDiff*24*60*60*1000));
    var yr = today.getFullYear();

    var tmp = month + "/" + day + "/" + yr;
    var tmpDate = jsDateTime(tmp, 23, 59);
    tmpDate.setSeconds(59);

    if (tmpDate < lowerBound) {
        tmp = month + "/" + day + "/" + (1*yr + 1);
    }
    return tmp;
}

function isUSDate(theField, emptyOK, warnDiff) {
    if (isUSDate.arguments.length == 1) {
        emptyOK = defaultEmptyOK;
        warnDiff = 90;
    }
    if (isUSDate.arguments.length == 2) {
        warnDiff = 90;
    }

    var tmpDate = theField.value + "";

    if (emptyOK && isEmpty(tmpDate)) {
        return true;
    }
    if (theField.value == null) {
        return defaultEmptyOK;
    }

    if (tmpDate.length < 6) {
        tmpDate = getDateFromShortDate(tmpDate, warnDiff);
    }

    if (tmpDate.length >= 6 && tmpDate.indexOf("/") < 0 && tmpDate.indexOf("-") < 0) {
        var m = tmpDate.substr(0,2);
        var d = tmpDate.substr(2,2);
        var y = (tmpDate.substr(4) * 1);
        if (y < 100) {
            y += 2000;
        }

        tmpDate = m + "/" + d + "/" + y;
    }

    var sArray = tmpDate.split("/");

    if ((sArray.length < 3) || (sArray.length > 3)) {
        sArray = tmpDate.split("-");
    }
    if ((sArray.length < 3) || (sArray.length > 3)) {
        return false;
    }

    var month = sArray[0];
    var day = sArray[1];
    var year = sArray[2];
    if (month.length < 2) {
        month = "0" + month;
    }
    if (day.length < 2) {
        day = "0" + day;
    }
    if ((year*1) < 100) {
        year = (year*1) + 2000;
    }

    tmpDate = month + "/" + day + "/" + year;

    if (isDate("" + year, month, day)) {
        theField.value = tmpDate;
        return true;
    }

    return false;
}

// Date of format month/day/year
function checkUSDate (theField, emptyOK, warnDiff) {
    if (checkUSDate.arguments.length == 1) {
        emptyOK = defaultEmptyOK;
        warnDiff = 90;
    }
    if (checkUSDate.arguments.length == 2) {
        warnDiff = 90;
    }

    var tmpDate = theField.value + "";

    if (emptyOK && isEmpty(tmpDate)) {
        return true;
    }
    if (theField.value == null) {
        return defaultEmptyOK;
    }

    if (tmpDate.length < 6) {
        tmpDate = getDateFromShortDate(tmpDate, warnDiff);
    }

    if (tmpDate.length >= 6 && tmpDate.indexOf("/") < 0 && tmpDate.indexOf("-") < 0) {
        var m = tmpDate.substr(0,2);
        var d = tmpDate.substr(2,2);
        var y = (tmpDate.substr(4) * 1);
        if (y < 100) {
            y += 2000;
        }

        tmpDate = m + "/" + d + "/" + y;
    }

    var sArray = tmpDate.split("/");

    if ((sArray.length < 3) || (sArray.length > 3)) {
        sArray = tmpDate.split("-");
    }
    if ((sArray.length < 3) || (sArray.length > 3)) {
        return warnInvalid(theField, iDate);
    }

    var month = sArray[0];
    var day = sArray[1];
    var year = sArray[2];
    if (month.length < 2) {
        month = "0" + month;
    }
    if (day.length < 2) {
        day = "0" + day;
    }
    if(year.length == 0) {
        year = new Date().getFullYear();
    }

    if ((1*year) < 100) {
        year = (1*year) + 2000;
    }

    tmpDate = month + "/" + day + "/" + year;

    if (isDate("" + year, month, day)) {
        theField.value = tmpDate;
        return true;
    }
    else {
        return warnInvalid(theField, iDate);
    }
}

// Date of format day/month/year
function checkIntlDate (theField, emptyOK) {
    if (checkIntlDate.arguments.length == 1) {
        emptyOK = defaultEmptyOK;
    }
    if (emptyOK && isEmpty(theField.value)) {
        return true;
    }

    if (theField.value==null) {
        return defaultEmptyOK;
    }

    sArray = theField.value.split("/");

    if ( (sArray.length < 3) || (sArray.length > 3)) {
        sArray = theField.value.split("-");
    }

    if ( (sArray.length < 3) || (sArray.length > 3)) {
        return warnInvalid (theField, iDate);
    }

    day = sArray[0];
    month = sArray[1];
    year = sArray[2];

    if (isDate(year, month, day)) {
        return true;
    } else {
       return warnInvalid (theField, iDate);
    }
}

// For backward-compatibility
function checkDate(theField, emptyOK) {
    return checkUSDate(theField, emptyOK)
}


function formatToTime(inTime) {
    //This is a sorta, kinda hack.  If the user enters "am" or "pm" for their time;
    //return what they entered and let the checkMilitaryTime function yell at them
    //for an invalid date entry.

    if ( inTime.indexOf("am") > 0 || inTime.indexOf("AM") > 0 || inTime.indexOf("pm") > 0 || inTime.indexOf("PM") > 0 ) {
        return inTime;
    }

    var outTime = inTime;

    inTime = stripCharsNotInBag (inTime, "0123456789");

    if (inTime.length == 4) {
        outTime = inTime.substring(0,2) + ":" + inTime.substring(2,4);
    } else if (inTime.length == 3) {
        outTime = "0" + inTime.substring(0,1) + ":" + inTime.substring(1,3);
    } else if (inTime.length == 2) {
        outTime = inTime.substring(0,2) + ":00";
    } else if (inTime.length == 1) {
        outTime = "0" + inTime.substring(0,1) + ":00";
    }

    return outTime;  //return format: xx:xx
}

function isMilitaryTime(theField, emptyOK) {
    if (isMilitaryTime.arguments.length == 1) {
        emptyOK = defaultEmptyOK;
    }
    if (emptyOK && isEmpty(theField.value)) {
        return true;
    }

    if (theField.value==null) {
        return defaultEmptyOK;
    }

    theField.value = formatToTime(theField.value);

    sArray = theField.value.split(":");

    if ( (sArray.length < 2) || (sArray.length > 2)) {
        return false;
    }

    hour = sArray[0];
    minutes = sArray[1];

    if (isTime(hour, minutes)) {
        return true;
    } else {
        return false;
    }
}

// time of format 00:00
function checkMilitaryTime (theField, emptyOK) {
    if (checkMilitaryTime.arguments.length == 1) {
        emptyOK = defaultEmptyOK;
    }
    if (emptyOK && isEmpty(theField.value)) {
        return true;
    }

    if (!isMilitaryTime(theField, emptyOK)) {
       return warnInvalid (theField, iTime);
    }

    return true;
}

function checkCreditCard (theField, emptyOK) {
    if (checkCreditCard.arguments.length == 1) {
        emptyOK = defaultEmptyOK;
    }
    if (emptyOK && isEmpty(theField.value)) {
        return true;
    }
    if (!isAnyCard(theField.value)) {
       return warnInvalid (theField, iCreditCard)
    } else {
        return true;
    }
}

// For NAB
function checkFields(theForm) {
    clientOK = false;
    returnValue = true;

    if ( (navigator.appName.indexOf("Microsoft")!=-1) && (navigator.appVersion.indexOf("4.")!=-1) ) {
        undef = void 0;
        clientOK = true;
    } else if ( (navigator.appName.indexOf("Netscape")!=-1) && ( (navigator.appVersion.indexOf("4.")!=-1) || (navigator.appVersion.indexOf("3.")!=-1) )) {
        undef = "undefined";
        clientOK = true;
    }

    if (clientOK) {
        for (i=0; i<theForm.elements.length; i++) {
            e = theForm.elements[i]
            if ( ((e.type=="text") || (e.type=="textarea") || (e.type=="password")) && e.required && (e.value=="")) {
                returnValue = false
                break;
            }
        }

        if (!returnValue) {
            alert("Form not submitted - please enter a value for this field")
            e.focus()
        } else {
            for (i=0; i<theForm.elements.length; i++) {
                e = theForm.elements[i]
                if ( (e.type=="text") || (e.type=="textarea") || (e.type=="password")) {
                    if ( undef != e.onChange ) {
                        returnValue = e.onChange;  //();
                        if (!returnValue) {
                            break;
                        }
                    }
                }
            }
        }
    }
    return returnValue;
}



////////////Added//////////////

function stripQuotes(theVal, ignoreSingleQuotes) {
    if(!ignoreSingleQuotes) {
        theVal = stripCharsInBag(theVal, "'");   //strip
    }
    theVal = stripCharsInBag(theVal, "\"");   //strip
    return theVal;
}

function popup( pageToLoad, winName, directORcenter, width_left, height_right, window_args, theopener) {  //    popup('calendar.html','popup_win', 'center',310,324);
    //Sample: <A HREF="#" onClick="window.dateField=document.Form1.newdate;calendar=popup('calendar.html', 'cal', 'direct', 200, 250)"><IMG SRC="images/calendar.gif" BORDER=0 width="16" height="16"></A>
    if (popup.arguments.length < 6) {
        window_args = "location=0,menubar=0,resizable=1,scrollbars=1,status=0,titlebar=0,toolbar=0,hotkeys=0,";
    }
    if (popup.arguments.length < 7 || !theopener) {
        theopener = window;
    }

    if (window_args.charAt(window_args.length-1) != ",") {
        window_args += ",";
    }

    if (width_left > screen.availWidth) {
        width_left = screen.availWidth - 60;
    }
    if (height_right > screen.availHeight) {
        height_right = screen.availHeight - 60;
    }

    var xposition=0;
    var yposition=0;

    if (parseInt(navigator.appVersion) >= 4) {
        xposition = (screen.availWidth - width_left) / 2;
        yposition = (screen.availHeight - height_right) / 2;

////////////////////////////////////////////////////////////////////
//  Direct placement of the window will require some additional work
//  using event handling and screenx and screeny
//
//          if (directORcenter == 'center')
//          {
//              xposition = (screen.width - width_left) / 2;
//              yposition = (screen.height - height_right) / 2;
//          }
//          else if (directORcenter == 'direct')
//          {
//              xposition = screen.width + width_left;
//              yposition = screen.height + height_right;
//          }
///////////////////////////////////////////////////////////////////
    }

    args = "width=" + width_left + "," + "height=" + height_right + ","
         + window_args
         + "screenx=" + xposition + "," + "screeny=" + yposition + ","
         + "left=" + xposition + "," + "top=" + yposition;

    var handle = theopener.open(pageToLoad, winName, args);
    if (handle == self) {
        setTimeout("self.location.href = '" + pageToLoad + "'", 50);
        return false;
    }
    return handle;

}

//Resizes a window to pre-set width and height and then centers the window
function repositionThisPopupWindow() {
    resizeToMaximumForResolutionSize();
    centerThisWindow();
}

//Resizes the current window to the maximum available size
function resizeToMaximum() {
    window.moveTo(0,0);
    resizeToSize(screen.availWidth, screen.availHeight);
}

//Resizes the current window to the maximum for the resolution size
function resizeToMaximumForResolutionSize() {
    if(screen.width <= fixedPopupWindowWidth && screen.height <= fixedPopupWindowHeight) {
        resizeToMaximum();
    } else {
        if (document.all) {
            resizeToSize(fixedPopupWindowWidth, fixedPopupWindowHeight);
        } else if (document.layers || document.getElementById) {
            if (top.window.outerWidth < fixedPopupWindowWidth || top.window.outerHeight < fixedPopupWindowHeight) {
                top.window.outerWidth = fixedPopupWindowWidth;
                top.window.outerHeight = fixedPopupWindowHeight;
            }
        }
    }
}


/*Resizes the current window to width x height
  If width or height is too large, the window will be made slightly smaller than maximum
  If width or height is 0, only the cooresponding non-zero value of the window will be changed
*/
function resizeToSize(width, height) {

    var maxWindowWidth = getLeanMaxWindowWidth();
    var maxWindowHeight = getLeanMaxWindowHeight();

    var resizeToWidth = (width == 0) ? getWindowWidth() : width;
    var resizeToHeight = (height == 0) ? getWindowHeight() : height;

    if(resizeToWidth >= maxWindowWidth) {
        resizeToWidth = maxWindowWidth;
    }
    if(resizeToHeight >= maxWindowHeight) {
        resizeToHeight = maxWindowHeight;
    }

    if(arguments.length == 2) {
        if(document.all) {
            try {
                top.window.resizeTo(resizeToWidth, resizeToHeight);
            }
            catch(e) {}
        } else if (document.layers || document.getElementById) {
            if (top.window.outerWidth < resizeToWidth || top.window.outerHeight < resizeToHeight){
                top.window.outerWidth = resizeToWidth;
                top.window.outerHeight = resizeToHeight;
            } else if (top.window.outerWidth > maxWindowWidth || top.window.outerHeight > maxWindowHeight) {
                top.window.outerWidth = resizeToWidth;
                top.window.outerHeight = resizeToHeight;
            }
        }
    }
}

//Returns the maximum window width that LeanLogistics will allow
function getLeanMaxWindowWidth() {
    return screen.availWidth - windowSizeBuffer;
}

//Returns the maximum window height that LeanLogistics will allow
function getLeanMaxWindowHeight() {
    return screen.availHeight - windowSizeBuffer;
}

//Returns the maximum width that can be added to a window during a resize
function getMaximumHorizontalResize(addedWidth) {
    var maximumValue = getLeanMaxWindowWidth() - (getWindowWidth() + addedWidth);
    if(maximumValue > 0) {
        return addedWidth;
    } else {
        //Value is negative, so add it
        return addedWidth + maximumValue;
    }
}

//Returns the maximum height that can be added to a window during a resize
function getMaximumVerticalResize(addedHeight) {
    var leanMax = getLeanMaxWindowHeight();
    var docHt = document.body.clientHeight + 75; // This is an IE hack
    var windowHt = getWindowHeight();

    if (docHt >= leanMax) {
        return leanMax - windowHt + addedHeight;
    }
    else {
        return docHt - windowHt + addedHeight;
    }
}

//Returns the width of the current window (only for popups with no toolbars)
function getWindowWidth() {
    if(document.all) {
        var width = document.body.clientWidth + 2 * windowSideBarWidth;
        //IE seems to always add a scrollBar on the right, even if it isn't needed
        width += windowScrollBarWidth;

        return width;
    } else {
        return window.outerWidth;
    }
}

//Returns the height of the current window (only for popups with no toolbars)
function getWindowHeight() {
    if(document.all) {
        var clientHeight = document.documentElement.clientHeight;
        if (clientHeight == 0) {
            clientHeight = document.body.clientHeight;
        }
        var height = clientHeight + windowTitleBarHeight + windowSideBarWidth;

        if(document.body.scrollWidth > document.body.clientWidth) {
            height += windowScrollBarWidth;
        }

        return height;
    } else {
        return window.outerHeight;
    }
}

//Centers the current window on the screen
//clientWidth, clientHeight and their usage found at from http://www.perlscriptsjavascripts.com/tutorials/javascript/window.html
function centerThisWindow() {
    var screenCenterX = screen.availWidth / 2;
    var screenCenterY = screen.availHeight / 2;

    var halfWindowSizeX = getWindowWidth() / 2;
    var halfWindowSizeY = getWindowHeight() / 2;

    var moveToX = screenCenterX - halfWindowSizeX;
    var moveToY = screenCenterY - halfWindowSizeY;

    try {
        top.window.moveTo(moveToX, moveToY);
    }
    catch(e) {}
}


//Resizes (and recenters) a window to the dimensions that fit the html element inside (eliminates the need for scrollbars if possible)
function repositionPageToFit(){

    if(document.all) {
        //Save the original scroll position
        var origScrollTop = document.body.scrollTop;
        var origScrollLeft = document.body.scrollLeft;

        window.scrollTo(0, document.body.clientHeight);

        resizeBy(0, getMaximumVerticalResize(document.body.scrollTop));

        window.scrollTo(document.body.clientWidth, 0);

        resizeBy(getMaximumHorizontalResize(document.body.scrollLeft), 0);

        //Must repeat because of object wrapping issues
        resizeBy(getMaximumHorizontalResize(document.body.scrollLeft), 0);

        /*Restore the original scroll position:
        If the window has been resized and still scrolls, this may scroll to a different place than the original location
        (because of wrapping issue)
        */
        window.scrollTo(origScrollLeft, origScrollTop);
    } else {
        //This function must be called 2x to work consistently
        window.sizeToContent();
        window.sizeToContent();

        //This will resize the window down if it grew past the desired border(s)
        resizeToSize(getWindowWidth(), getWindowHeight());
    }
    centerThisWindow();
}

function refreshPopupOpener(dt) {
    if (window.opener != null && !window.opener.closed) {
        var link = window.opener.location + "";
        if (link.indexOf("?") > 0) {
            link = link.substring(0, link.indexOf("?"));
        }
        window.opener.location = link + "?dt=" + dt;
    }
}

function refocusPopupOpener() {
    if (window.opener != null && !window.opener.closed) {
        window.opener.focus();
    }
}

///// Parses a delimited string
// EXAMPLE:
//    var strings = new parse(testString, "|");
//    for (var i=0; i<strings.length; i++)
//    {
//        var str = strings.next();
//        alert("Next" + i + ":" + str);
//    }
/////
function parse(inStr, delim) {
    this.delimiter = delim;
    this.inString = inStr;
    this.currentRec = 0;
    this.length = 0;

    this.parseMeth = parseIt;
    this.parsedStrings = this.parseMeth();
    this.next = next;
}

function parseIt() {        //a method of parse()
    var strs = new Array();

    var n=0;
    var f=0;
    var finished=false;

    if ( this.inString.length != this.inString.lastIndexOf(this.delimiter)+1) {
        this.inString += this.delimiter;
    }

    while( f>=0 ) {
        f = this.inString.indexOf(this.delimiter, n);
        if ( f == this.inString.lastIndexOf(this.delimiter) ) {
            f = this.inString.length-1;
            finished = true;
        }

        strs[this.length] = this.inString.substring(n,f);
        this.length++;

        if (finished) {
            break;
        }
        n = f + 1;
    }
    return strs;
}  //parseIt

function next() {        //a method of parse()
        var i = this.currentRec;
        this.currentRec++;
        return this.parsedStrings[i];
}

function getSelectedValue(field) {
    if (field != null && field.selectedIndex != null && field.selectedIndex >= 0) {
        return field.options[field.selectedIndex].value;
    }
    return null;
}

function isValueSelected(field, val) {
    if (field != null && field.options != null && field.selectedIndex != null && field.selectedIndex >= 0) {
        for (var i=field.selectedIndex; i < field.options.length; i++) {
            if (field.options[i].value == val) {
                return field.options[i].selected;
            }
        }
    }
    return false;
}

function getSelectedValues(field, optionListName) {
    if (field != null && field.selectedIndex != null && field.selectedIndex >= 0) {
        var selectedIDs = [];
        for(var i = 0; i < field.options.length; i++) {
            if(field.options[i].selected) {
                selectedIDs.push(field.options[i].value);
            }
        }

        if (isEmpty(optionListName)) {
            return selectedIDs;
        }

        //get selected values
        var theList = [];
        for(var j = 0; j < selectedIDs.length; j++) {
            var selectedInfo = eval(optionListName + "[" + selectedIDs[j] + "]");
            for(var k = 0; selectedInfo != null && k < selectedInfo.length; k++) {
                theList.push(selectedInfo[k]);
            }
        }

        return theList;
    }
    return null;
}

function getCheckedValue(field) {
    if (field == null) {
        return null;
    }
    if (field.length != null) {
        for (var a=0; a<field.length; a++) {
            if (field[a].checked) {
                return field[a].value;
            }
        }
    } else if (field.checked) {
        return field.value;
    }
    return null;
}

function getBooleanValue(s) {
    if (s == null) {
        return false;
    }
    try {
        return s == "true" || s == true || s == "1" || s == 1;
    } catch (e) {
        return false;
    }
}

function formatToCurrency(n, useParensForNegatives) {
    if (arguments.length < 2) {
        useParensForNegatives = true;
    }
    return ll.util.formatDecimalOld(n, 2, 2, useParensForNegatives);
}

ll.util.formatDecimalOld = function (val, minNbrDecimals, maxNbrDecimals, useParensForNegatives) {
    maxNbrDecimals = Math.max(minNbrDecimals, maxNbrDecimals);

    //First round to get rid of extra decimals
    var roundFactor = 1 * Math.pow(10.0, maxNbrDecimals);
    var s = (Math.round(val * roundFactor + 0.0000000001) / roundFactor) + "";

    var decimalIdx = s.indexOf('.');
    if (decimalIdx < 0 && minNbrDecimals > 0) {
        s += ".";
        decimalIdx = s.indexOf('.');
    }

    var currentNbrDecimals = (decimalIdx != -1) ? s.length - decimalIdx - 1 : 0;
    //Make sure we have the minimum # of decimals
    if (currentNbrDecimals < minNbrDecimals) {
        for (var i = currentNbrDecimals; i < minNbrDecimals; i++) {
            s += "0";
        }
        currentNbrDecimals = s.length - decimalIdx - 1;
    //Make sure we have no more than the maximum # of decimals
    } else if (currentNbrDecimals > maxNbrDecimals && decimalIdx > 0) {
        s = s.substring(0, decimalIdx + maxNbrDecimals);
        currentNbrDecimals = s.length - decimalIdx - 1;
    }

    //Make sure we have no "0" values between min and max
    if (minNbrDecimals != maxNbrDecimals && currentNbrDecimals > minNbrDecimals) {
        for (var i = s.length - 1; i > (decimalIdx + minNbrDecimals); i--) {
            if (s.charAt(i) == '0') {
                s = s.substring(0, i);
            } else {
                break;
            }
        }
    }

    if (useParensForNegatives && s.charAt(0) == '-') {
        s = '(' + s.substr(1) + ')';
    }

    return s;
}

//JS implementation of java.lang.String.trim()
String.prototype.trim = function() {
    return this.replace(/^\s*(\b.*\b|)\s*$/, "$1");
}

function popupError(msg) {
    if(popupError.arguments.length==0) {
        msg = "Unable to process your request.";
    }
    alert(msg);
}

function noop() {}

function setSelectedValue(field, val) {
    if (setSelectedValue.arguments.length == 3 && setSelectedValue.arguments[2]) {
        field.selectedIndex = 0;
    }

    for(var i = 0; i < field.options.length; i++) {
        if (field.options[i].value == val) {
            field.selectedIndex = i;
            break;
        }
    }
}

function setCheckedValue(field, val) {
    if (field == null) {
        return;
    }
    var unCheck = true;
    if (setCheckedValue.arguments.length == 3 && setCheckedValue.arguments[2] == false) {
        unCheck = false;
    }

    if (field.length == null) {
        if (field.value == val) {
            field.checked = true;
        } else if (unCheck) {
            field.checked = false;
        }
    } else {
        for (var i=0; i < field.length; i++) {
            if (field[i].value == val) {
                if (!field[i].checked) {
                    field[i].click();
                }
            } else if (unCheck) {
                field[i].checked = false;
            }
        }
    }
}

function setSelectedValues(field, vals) {
    field.selectedIndex = -1;

    var hasOne = false;
    if (vals != null && vals.length > 0) {
        for(var i = 0; i < field.options.length; i++) {
            for(var j = 0; j < vals.length; j++) {
                if (field.options[i].value == vals[j]) {
                    field.options[i].selected = true;
                    hasOne = true;
                    break;
                }
            }
        }
    }

    if (!hasOne && setSelectedValues.arguments.length == 3 && setSelectedValues.arguments[2]) {
        field.selectedIndex = 0;
    }
}

// set the options of a select box with data from a javascrpt hashtable
function setOptions(field, values, reset) {
    // save selected value
    var curVal = getSelectedValue(field);
    // clear list
    var optLen = field.options.length;
    for (var i = 0; i < optLen; i++) {
        field.options[0] = null;
    }
    // add options from hashtable
    var indx = 0;
    for (var key in values) {
        field.options[indx++] = new Option(values["" + key], key);
    }
    if (!reset && curVal != null) {
        setSelectedValue(field, curVal);
    } else {
        field.selectedIndex = 0;
    }
}

function roundHundredWeight(weight) {
    var hwt = weight*1*0.01;
    var tmp = Math.floor(hwt);
    if(hwt > tmp) {
        tmp++;
    }
    return tmp;
}

function hundredWeight(weight) {

    var hwt = weight*1*0.01;

    return hwt;
}

function shortTon(weight) {
    var hwt = ((weight*1)/2000);
    return hwt;
}

/**
 * function to validate and reformat the form fields such as Ref Nbr, Scac, and LeanID
 * that provide one input field for multiple entries (usually for searches)
 *
 * @param formObj    the form from the page (as an object, not a string)
 * @param fieldName  the name of the field to check
 * @param valueType  either 'integer' (value must be a number)
 *                       or 'string'  (value can be letters and numbers)
 *                       or 'refnum'  (value can be letters, numbers, and certain special characters)
 *                       or 'quotableRefNum'  (value can be letters, numbers, and certain special characters surround by quotes, separated by spaces)
 *                       or 'ignored' (value will not be validated, only reformated)
 */
function validateMultipleFields(formObj, fieldName, valueType) {
    var theField = formObj.elements[fieldName];
    var IDString = (theField != null)? theField.value : null;
    var maxLength = 0;
    var allowSeparatorsInQuotedStrings = false; // set to true for individual value types, where supported

    if (!isEmpty(IDString)) {
        if (valueType == "integer") {
            // if id string is anything but numbers and separators, alert the user and stop
            for (var i=0; i < IDString.length; i++) {
                var c = IDString.charAt(i);
                if (!isDigit(c) && !isValidSeparatorChar(c)) {
                    alert("Please enter only numbers into this field,\nseparated by commas, semi-colons or spaces.");
                    theField.focus();
                    return false;
                }
            }
        } else if (valueType == "string") {
            // if id string is anything but numbers and letters and the allowed special characters, alert the user and stop
            if (!isString(IDString, false)) {
                alert("Please enter only numbers and letters into this field,\n separated by commas, semi-colons or spaces.");
                theField.focus();
                return false;
            }
        } else if ((valueType == "refnum") || (valueType == "quotableRefNum")) {
            allowSeparatorsInQuotedStrings = (valueType == "quotableRefNum");
            maxLength = maxRefNumLength;
            // if id string is anything but valid refnums and valid separator characters, alert the user and stop
            IDString = IDString.toUpperCase();
            for (var i=0; i < IDString.length; i++) {
                var c = IDString.charAt(i);
                var charOK = false;

                if (isValidRefnumChar(c)) {
                    charOK = true;
                } else if (isValidSeparatorChar(c)) {
                    charOK = true;
                } else if (allowSeparatorsInQuotedStrings && (c == doubleQuote)) {
                    charOK = true;
                }

                if (!charOK) {
                    alert("The character '" + c + "' is not allowed in a reference number.");
                    theField.focus();
                    return false;
                }
            }
        }

        // Split the string into an array of strings, using valid separator characters to split.
        // EXCEPTION: if quoted strings are allowed, then do not split on separator characters inside quotes
        var newIDs = new Array();
        var newIDIndex = 0;
        newIDs[0] = "";
        var insideQuotes = false;
        for (var i=0; i < IDString.length; i++) {
            var c = IDString.charAt(i);
            if (allowSeparatorsInQuotedStrings && (c == doubleQuote)) {
                insideQuotes = !insideQuotes;
            } else {
                if (!insideQuotes && (isValidSeparatorChar(c))) {
                    newIDIndex++;
                    newIDs[newIDIndex] = "";
                } else {
                    newIDs[newIDIndex] += c;
                }
            }
        }

        if (insideQuotes) {
            alert("Unbalanced quotation marks.");
            theField.focus();
            return false;
        }

        // reassemble the string, checking maxlength as we go.
        // if quotes are allowed, put quotes around every ID.
        var newIDString = "";
        for (var i = 0; i < newIDs.length; i++) {
            if (maxLength > 0) {
                if (newIDs[i].length > maxLength) {
                    alert("Please limit each item to " + maxLength + " characters.");
                    theField.focus();
                    return false;
                }
            }
            if (!isEmpty(newIDs[i])) {
                if (allowSeparatorsInQuotedStrings && containsSeparator(newIDs[i])) newIDString += doubleQuote;
                newIDString += newIDs[i];
                if (allowSeparatorsInQuotedStrings && containsSeparator(newIDs[i])) newIDString += doubleQuote;
                newIDString += ", ";
            }
        }

        // strip off leading and trailing separators
        while (newIDString.length > 0 && isValidSeparatorChar(newIDString.charAt(0))) {
            newIDString = newIDString.substr(1);
        }
        while (newIDString.length > 0 && isValidSeparatorChar(newIDString.charAt(newIDString.length-1))) {
            newIDString = newIDString.substring(0, newIDString.length-1);
        }

        // Set the reformatted id string back into the form field
        theField.value = newIDString;
    }
    return true;
}

function containsSeparator(input) {
    for (var i = 0; i < input.length; i++) {
        if (allowedSeparatorCharacters.indexOf(input.charAt(i)) > -1) {
            return true;
        }
    }
    return false;
}

/**
 * Sets the given value into the given field, if it would change the field
 *
 * This is designed to get around a problem with tabbing in IE -
 * wherein a value is assigned to the field the user is tabbing to, and IE does not auto-select the field's text.
 */
function setTextFieldValue(fldObj, fldVal) {
    if (fldObj != null) {
        fldVal = (fldVal != null) ? fldVal + "" : "";
        if (fldObj.value != fldVal) {
            fldObj.value = fldVal;
        }
    }
}

function limit2Decimals(inputfld, e) {
    return limitDecimals(inputfld, e, 2);
}

/**
 *  limit2Decimals, containsElement, getIndex methods are added to restrict entering
 *  more than two decimal values.
 */

function limitDecimals(inputfld, e, limit) {

    var isNN = (navigator.appName.indexOf("Netscape")!=-1);
    var keyCode = (isNN) ? e.which : e.keyCode;

    var filter = (isNN) ? [0,8,9] : [0,8,9,16,17,18,37,38,39,40,46];


    var fieldValue = inputfld.value;
    var dotindx = fieldValue.indexOf('.');

    if(dotindx > -1 && !containsElement(filter,keyCode)) {

        var subIndx = (dotindx*1)+1;
        var dectext = fieldValue.substr(subIndx);
        if(dectext.length > limit) {

            inputfld.value = fieldValue.substring(0, (fieldValue.length-1));

            var inputfldindx = getIndex(inputfld);
            inputfldindx = (inputfldindx*1)+1;

            var form = inputfld.form;
            var formlen = form.length;

            for(i = inputfldindx; i < formlen; i++) {
                if((form[i].type == "text") ||
                    (form[i].type == "textarea") ||
                    (form[i].type.toString().charAt(0) == "s")) {

                    if(form[i].disabled) {

                    } else {

                        form[i].focus();

                        break;
                    }
                }
            }

            return true;
        }
    }

    return false;
}

function containsElement(arr, ele) {
    var found = false, index = 0;
    while(!found && index < arr.length) {
        if(arr[index] == ele) {
            found = true;
        } else {
            index++;
        }
    }
    return found;
}

function getIndex(inputFld) {
    var index = -1, i = 0, found = false;
    while (i < inputFld.form.length && index == -1) {
        if (inputFld.form[i] == inputFld) {
            index = i;
        } else {
            i++;
        }
    }
    return index;
}

//check the account code format based on the company's specifications
function checkACFormat(acCode, format, jsFormat) {
    var validFormat = true;
    var length = acCode.value.length;

    //check the lengths to make sure they are the same
    if (format.length != length) {
        validFormat = false;
    }

    var j = 0;
    for(var i=0; validFormat && i < jsFormat.length; i++) {

        //check all of the actual parts of the field
        switch(jsFormat.charAt(i)) {
        case '#':
            if(!(isDigit(acCode.value.charAt(j)))) {
                validFormat = false;
            }
            j++;
            break;
        case '@':
            if(!(isLetter(acCode.value.charAt(j)))) {
                validFormat = false;
            }
            j++;
            break;
        case '*':
            if(!(isAlphanumeric(acCode.value.charAt(j)))) {
                validFormat = false;
            }
            j++;
            break;
        case '\\':
            i++;
        default:
            if(jsFormat.charAt(i) != acCode.value.charAt(j)) {
                validFormat = false;
            }
            j++;
            break;
        }
    }

    return validFormat;
}

function isValidRefnumChar(c) {
    return (allowedRefNumCharacters.indexOf(c) != -1);
}

function isValidSeparatorChar(c) {
    return (allowedSeparatorCharacters.indexOf(c) != -1);
}

function validateRefNumField(refnumField) {
    if (refnumField == null) {
        return true;
    }
    if (!validateRefNum(refnumField.value)) {
        refnumField.focus();
        return false;
    }
    refnumField.value = refnumField.value.toUpperCase();
    return true;
}

function isValidRefNum(refnum, emptyOk) {
    if (isEmpty(refnum)) {
        if (emptyOk == null || emptyOk == false) {
            return false;
        }
        return true;
    }
    if (refnum.length > maxRefNumLength) {
        return false;
    }
    for (var i = 0; i < refnum.length; i++) {
        if (!isValidRefnumChar(refnum.charAt(i))) {
            return false;
        }
    }
    return true;
}

function validateRefNum(refnum) {
    if (isEmpty(refnum)) {
        if (validateRefNum.arguments.length > 1 &&
            validateRefNum.arguments[1] == false)
        {
            alert("Please enter a reference number.");
            return false;
        }
        return true;
    }
    if (refnum.length > maxRefNumLength) {
        alert("Please limit the reference number to " +maxRefNumLength+ " characters or fewer.");
        return false;
    }
    for (var i = 0; i < refnum.length; i++) {
        if (!isValidRefnumChar(refnum.charAt(i))) {
            alert("The character '" + refnum.charAt(i) + "' is not allowed in a reference number.");
            return false;
        }
    }
    return true;
}

function validateQuotedRefNumField(refnumField) {

    if (refnumField == null) {
        return true;
    }
    if (refnumField.value.charAt(0) == " " || refnumField.value.charAt(refnumField.value.length-1) == " ") {
        refnumField.value = trim(refnumField.value);
    }


    if (refnumField.value.charAt(0) == '"' && refnumField.value.charAt(refnumField.value.length-1) == '"') {
        var ref = refnumField.value.substring(1, refnumField.value.length-1);
        if (ref.charAt(0) == " " || ref.charAt(ref.length-1) == " ") {
            refnumField.value = '"' + trim(ref) + '"';
        }
    }

    if (!validateQuotedRefNum(refnumField.value)) {
        refnumField.focus();
        return false;
    }
    refnumField.value = refnumField.value.toUpperCase();
    return true;
}

function validateQuotedRefNum(refnum) {
    if (isEmpty(refnum)) {
        if (validateQuotedRefNum.arguments.length > 1 &&
            validateQuotedRefNum.arguments[1] == false)
        {
            alert("Please enter a reference number.");
            return false;
        }
        return true;
    }
    if (refnum.length > maxRefNumLength) {
        alert("Please limit the reference number to " +maxRefNumLength+ " characters or fewer.");
        return false;
    }


    var insideQuotes = false;
    for (var i = 0; i < refnum.length; i++) {
        var c = refnum.charAt(i);
        if (c == doubleQuote) {
            insideQuotes = !insideQuotes;

        } else {
            if (!isValidRefnumChar(c)) {
                if (isValidSeparatorChar(c)) {
                    if (insideQuotes == false) {
                        alert("The character '" + refnum.charAt(i) + "' is not allowed in a reference number unless the reference number is enclosed in quotes.");
                        return false;
                    }
                } else {
                    alert("The character '" + refnum.charAt(i) + "' is not allowed in a reference number.");
                    return false;
                }
            }
        }
    }
    if (insideQuotes) {
        alert("Unbalanced quotation marks.");
        return false;
    }


    return true;
}

function validateDateRangePair(startdate, enddate, message) {
    if (!checkUSDate(startdate, true)) {
        return false;
    }
    if (!checkUSDate(enddate, true)) {
        return false;
    }

    if (!isEmpty(message)) {
        if ((isEmpty(startdate.value) && !isEmpty(enddate.value)) ||
            (!isEmpty(startdate.value) && isEmpty(enddate.value)))
        {
            alert(message);
            return false;
        }
    }
    return true;
}
function validateRequiredDateRangePair(startdate, enddate, message) {
    if (!checkUSDate(startdate, true)) {
        return false;
    }
    if (!checkUSDate(enddate, true)) {
        return false;
    }

    if (!isEmpty(message)) {
        if ((isEmpty(startdate.value) && isEmpty(enddate.value)) ||
            (isEmpty(startdate.value) && !isEmpty(enddate.value)) ||
            (!isEmpty(startdate.value) && isEmpty(enddate.value)))
        {
            alert(message);
            return false;
        }
    }
    return true;
}

function checkStringField(theField, fieldName) { // optional emptyOK parameter
    var emptyOK = defaultEmptyOK;
    if (checkStringField.arguments.length > 2) {
        emptyOK = checkStringField.arguments[2];
    }

    if (isEmpty(theField.value)) {
        if (emptyOK) {
            return true;
        }
        alert(mPrefix + fieldName + mSuffix);
        theField.focus();
        return false;
    }

    if (isString(theField.value)) {
        return true;
    } else {
        alert(iAlphaNumericSlashOrDash);
        theField.focus();
        return false;
    }

}

function limitTextAreaLength(theField, maxlength) {
    if (theField.value.length > maxlength) {
        theField.value = theField.value.substring(0, maxlength);
        return false;
    } else if (theField.value.length == maxlength) {
        return false;
    }

    return true;
}

// insertAdjacentHTML(), insertAdjacentText() and insertAdjacentElement()
// for Netscape 6/Mozilla by Thor Larholm me@jscript.dk
if (typeof HTMLElement != "undefined" && !HTMLElement.prototype.insertAdjacentElement) {
    HTMLElement.prototype.insertAdjacentElement = function(where, parsedNode) {
        switch (where) {
            case 'beforeBegin':
                this.parentNode.insertBefore(parsedNode, this)
                break;
            case 'afterBegin':
                this.insertBefore(parsedNode, this.firstChild);
                break;
            case 'beforeEnd':
                this.appendChild(parsedNode);
                break;
            case 'afterEnd':
                if (this.nextSibling) {
                    this.parentNode.insertBefore(parsedNode, this.nextSibling);
                } else {
                    this.parentNode.appendChild(parsedNode);
                }
                break;
        }
    }

    HTMLElement.prototype.insertAdjacentHTML = function(where, htmlStr) {
        var r = this.ownerDocument.createRange();
        r.setStartBefore(this);
        var parsedHTML = r.createContextualFragment(htmlStr);
        this.insertAdjacentElement(where,parsedHTML);
    }

    HTMLElement.prototype.insertAdjacentText = function(where, txtStr) {
        var parsedText = document.createTextNode(txtStr);
        this.insertAdjacentElement(where,parsedText);
    }
}

function toggleTechnicalDetails() {
    var techInfoRow = document.getElementById("technicalDetailRow");
    var image = document.getElementById("technicalDetailImg");

    if (techInfoRow.className == "showrow") {
        techInfoRow.className = "hiderow";
        if (image != null) {
            image.src = "/images/closed_folder.gif";
            image.title = "Show Tech Info";
        }
    } else {
        techInfoRow.className = "showrow";
        if (image != null) {
            image.src = "/images/open_folder.gif";
            image.title = "Hide Tech Info";
        }
    }
}

/*
 *This function checks for the supported countries.
 *Currently the location UI validations are limited only to these supported countries.
 */
function countrySupportsUIValidation(country) {
    return (country == "US" || country == "CA" || country == "MX");
}


/** The DWR engine JS include must be included for this to work */
function useDWRLoadingImage() {

    var imageSrc = (useDWRLoadingImage.arguments.length > 0) ? useDWRLoadingImage.arguments[0] : '/images/ajax-loader.gif';
    var message = (useDWRLoadingImage.arguments.length > 1) ? useDWRLoadingImage.arguments[1] : 'Loading...';

    dwr.engine.setPreHook(function() {
        var disabledImageZone = $('disabledImageZone');
        if (!disabledImageZone) {
            disabledImageZone = document.createElement('div');
            disabledImageZone.setAttribute('id', 'disabledImageZone');
            disabledImageZone.style.position = "absolute";
            disabledImageZone.style.zIndex = "1000";
            disabledImageZone.style.left = "0px";
            disabledImageZone.style.top = "2px";
            disabledImageZone.style.width = "100%";
            disabledImageZone.style.height = "100%";
            var imageZone = document.createElement('img');
            imageZone.setAttribute('id', 'imageZone');
            imageZone.setAttribute('src', imageSrc);
            imageZone.style.position = "absolute";
            imageZone.style.top = "0px";
            imageZone.style.right = "0px";
            imageZone.alt = 'Activity Indicator';
            disabledImageZone.appendChild(imageZone);
            var textZone = document.createElement('div');
            textZone.setAttribute('id', 'textZone');
            textZone.innerHTML = message;
            textZone.style.position = "absolute";
            textZone.style.top = "4px";
            textZone.style.right = "30px";
            textZone.className = 'hmenu3';
            disabledImageZone.appendChild(textZone);
            document.body.appendChild(disabledImageZone);
        }
        else {
            $('imageZone').src = imageSrc;
            $('textZone').innerHTML = message;
            disabledImageZone.style.visibility = 'visible';
        }
    });
    dwr.engine.setPostHook(function() {
        $('disabledImageZone').style.visibility = 'hidden';
    });
}

/**
 *  Load the user's available countries
 *  Note: The DWR engine, util and GeographyLookup JS includes must be included for this to work.
 *
 *  @param countrySelects a single country selectbox or an array of multiple selectboxes
 *  @param defaultCountryVal the default country or an array of countries to select when the data is loaded (or null).  If countrySelects is an array, this must be a corresponding array.
 *  @param (optional) chooseVal value to be used as an additional "first" selection
 *  @param (optional) useLongCountryNames should the "Long" or "Short" country names be displayed (defaults to true)
 *  @param (optional) setCountryMapCB callback function to set the resulting country map param:(countries)
 *  @param (optional) maxLength maximum number of chars length to display (longer values will be truncated) - only applies if "useLongCountryNames" is true. Default is 20
 */
function loadThirdPartyDWRCountries(countrySelects, defaultCountryVal) {
    var chooseVal = (loadThirdPartyDWRCountries.arguments.length > 2) ? loadThirdPartyDWRCountries.arguments[2] : null;
    var useLongCountryNames = (loadThirdPartyDWRCountries.arguments.length > 3) ? loadThirdPartyDWRCountries.arguments[3] : true;
    var setCountryMapCB = (loadThirdPartyDWRCountries.arguments.length > 4) ? loadThirdPartyDWRCountries.arguments[4] : null;
    var maxLength = (loadThirdPartyDWRCountries.arguments.length > 5) ? loadThirdPartyDWRCountries.arguments[5] : 20;

    loadDWRCountries(GeographyLookup.getThirdPartyLongCountries, countrySelects, defaultCountryVal, chooseVal, useLongCountryNames, setCountryMapCB, maxLength);
}

/**
 *  Load the user's available countries
 *  Note: The DWR engine, util and GeographyLookup JS includes must be included for this to work.
 *
 *  @param countrySelects a single country selectbox or an array of multiple selectboxes
 *  @param defaultCountryVal the default country or an array of countries to select when the data is loaded (or null).  If countrySelects is an array, this must be a corresponding array.
 *  @param (optional) chooseVal value to be used as an additional "first" selection
 *  @param (optional) useLongCountryNames should the "Long" or "Short" country names be displayed (defaults to true)
 *  @param (optional) setCountryMapCB callback function to set the resulting country map param:(countries)
 *  @param (optional) maxLength maximum number of chars length to display (longer values will be truncated) - only applies if "useLongCountryNames" is true. Default is 20
 */
function loadUserDWRCountries(countrySelects, defaultCountryVal) {
    var chooseVal = (loadUserDWRCountries.arguments.length > 2) ? loadUserDWRCountries.arguments[2] : null;
    var useLongCountryNames = (loadUserDWRCountries.arguments.length > 3) ? loadUserDWRCountries.arguments[3] : true;
    var setCountryMapCB = (loadUserDWRCountries.arguments.length > 4) ? loadUserDWRCountries.arguments[4] : null;
    var maxLength = (loadUserDWRCountries.arguments.length > 5) ? loadUserDWRCountries.arguments[5] : 20;

    loadDWRCountries(GeographyLookup.getUserLongCountries, countrySelects, defaultCountryVal, chooseVal, useLongCountryNames, setCountryMapCB, maxLength);
}

/**
 *  Load all countries
 *  Note: The DWR engine, util and GeographyLookup JS includes must be included for this to work.
 *
 *  @param countrySelects a single country selectbox or an array of multiple selectboxes
 *  @param defaultCountryVal the default country or an array of countries to select when the data is loaded (or null).  If countrySelects is an array, this must be a corresponding array.
 *  @param (optional) chooseVal value to be used as an additional "first" selection
 *  @param (optional) useLongCountryNames should the "Long" or "Short" country names be displayed (defaults to "long")
 *  @param (optional) setCountryMapCB callback function to set the resulting country map param:(countries)
 *  @param (optional) maxLength maximum number of chars length to display (longer values will be truncated) - only applies if "useLongCountryNames" is true. Default is 20
 */
function loadAllDWRCountries(countrySelects, defaultCountryVal) {
    var chooseVal = (loadAllDWRCountries.arguments.length > 2) ? loadAllDWRCountries.arguments[2] : null;
    var useLongCountryNames = (loadAllDWRCountries.arguments.length > 3) ? loadAllDWRCountries.arguments[3] : true;
    var setCountryMapCB = (loadAllDWRCountries.arguments.length > 4) ? loadAllDWRCountries.arguments[4] : null;
    var maxLength = (loadAllDWRCountries.arguments.length > 5) ? loadAllDWRCountries.arguments[5] : 20;

    loadDWRCountries(GeographyLookup.getAllCountries, countrySelects, defaultCountryVal, chooseVal, useLongCountryNames, setCountryMapCB, maxLength);
}

/**
 *  Load a set of countries via the specified lookupFunction
 *  Note: The DWR engine, util and GeographyLookup JS includes must be included for this to work.
 *
 *  @param lookupFunction a country lookup function that returns a map of countryCode->countryName values
 *  @param countrySelects a single country selectbox or an array of multiple selectboxes
 *  @param defaultCountryVal the default country or an array of countries to select when the data is loaded (or null).  If countrySelects is an array, this must be a corresponding array.
 *  @param (optional) chooseVal value to be used as an additional "first" selection
 *  @param (optional) useLongCountryNames should the "Long" or "Short" country names be displayed (defaults to true)
 *  @param (optional) setCountryMapCB callback function to set the resulting country map param:(countries)
 *  @param (optional) maxLength maximum length to display (longer values will be truncated) - only applies if "useLongCountryNames" is true. Default is unlimited.
 */
function loadDWRCountries(lookupFunction, countrySelects, defaultCountryVal) {
    var chooseVal = (loadDWRCountries.arguments.length > 3) ? loadDWRCountries.arguments[3] : null;
    var useLongCountryNames = (loadDWRCountries.arguments.length > 4) ? loadDWRCountries.arguments[4] : true;
    var setCountryMapCB = (loadDWRCountries.arguments.length > 5) ? loadDWRCountries.arguments[5] : null;
    var maxLength = (loadDWRCountries.arguments.length > 6) ? loadDWRCountries.arguments[6] : -1;

    var countrySels = countrySelects;
    var defaultCountries = defaultCountryVal;
    try {
        if (countrySelects.type == 'select-one' || countrySelects.type == 'select-multiple') {
            countrySels = [countrySelects];
            defaultCountries = [defaultCountryVal];
        }
    } catch(error) {
        //this means that it is an Array (or something else bogus)
    }

    for (var i = 0; i < countrySels.length; i++) {
        dwr.util.removeAllOptions(countrySels[i]);
    }

    lookupFunction(function(countries) {
        if (setCountryMapCB) {
            setCountryMapCB(countries);
        }

        if (!useLongCountryNames) {
            var countryList = new Array();
            for (key in countries) {
                countryList.push(key);
            }
            countries = countryList.sort();
        } else if (maxLength > 0) {
            //We don't want to replace the cached version
            var countriesOrig = countries;
            countries = {};
            for (key in countriesOrig) {
                if (countriesOrig[key].length > (maxLength + 3)) {
                    countries[key] = countriesOrig[key].substring(0, maxLength) + "...";
                } else {
                    countries[key] = countriesOrig[key];
                }
            }
        }

        for (var i = 0; i < countrySels.length; i++) {
            var countrySel = countrySels[i];
            if(countrySel) {
                dwr.util.removeAllOptions(countrySel);
                if (chooseVal) {
                    dwr.util.addOptions(countrySel, [{name:chooseVal, id:''}], "id", "name");
                }
                dwr.util.addOptions(countrySel, countries);
                if (defaultCountries && defaultCountries[i]) {
                    dwr.util.setValue(countrySel, defaultCountries[i]);
                }
                if (countrySel.onchange) {
                    countrySel.onchange.call(countrySel);
                }
            }
        }
    });
}

var _countryStatesCache = {
    'US' : {AL:"Alabama",AK:"Alaska",AS:"American Samoa",AZ:"Arizona",AR:"Arkansas",CA:"California",CO:"Colorado",CT:"Connecticut",DE:"Delaware",DC:"District of Columbia",FL:"Florida",GA:"Georgia",GU:"Guam",HI:"Hawaii",ID:"Idaho",IL:"Illinois",IN:"Indiana",IA:"Iowa",KS:"Kansas",KY:"Kentucky",LA:"Louisiana",ME:"Maine",MD:"Maryland",MA:"Massachusetts",MI:"Michigan",MN:"Minnesota",MS:"Mississippi",MO:"Missouri",MT:"Montana",NE:"Nebraska",NV:"Nevada",NH:"New Hampshire",NJ:"New Jersey",NM:"New Mexico",NY:"New York",NC:"North Carolina",ND:"North Dakota",MP:"Northern Mariana Islands",OH:"Ohio",OK:"Oklahoma",OR:"Oregon",PA:"Pennsylvania",PR:"Puerto Rico",RI:"Rhode Island",SC:"South Carolina",SD:"South Dakota",TN:"Tennessee",TX:"Texas",UT:"Utah",VT:"Vermont",VI:"Virgin Islands",VA:"Virginia",WA:"Washington",WV:"West Virginia",WI:"Wisconsin",WY:"Wyoming"},
    'CA' : {AB:"Alberta",BC:"British Columbia",MB:"Manitoba",NB:"New Brunswick",NL:"Newfoundland and Labrador",NT:"Northwest Territories",NS:"Nova Scotia",NU:"Nunavut",ON:"Ontario",PE:"Prince Edward Island",QC:"Quebec",SK:"Saskatchewan",YT:"Yukon Territory"},
    'MX' : {AGU:"Aguascalientes",BCN:"Baja California",BCS:"Baja California Sur",CAM:"Campeche",CHP:"Chiapas",CHH:"Chihuahua",COA:"Coahuila",COL:"Colima",DIF:"Distrito Federal",DUR:"Durango",GUA:"Guanajuato",GRO:"Guerrero",HID:"Hidalgo",JAL:"Jalisco",MIC:"Michoac\u00E1n",MOR:"Morelos",MEX:"M\u00E9xico",NAY:"Nayarit",NLE:"Nuevo Le\u00F3n",OAX:"Oaxaca",PUE:"Puebla",QUE:"Quer\u00E9taro",ROO:"Quintana Roo",SLP:"San Luis Potos\u00ED",SIN:"Sinaloa",SON:"Sonora",TAB:"Tabasco",TAM:"Tamaulipas",TLA:"Tlaxcala",VER:"Veracruz",YUC:"Yucat\u00E1n",ZAC:"Zacatecas"}
};

/**
 *  Load the states for the specified country
 *  Note: The DWR engine, util and GeographyLookup JS includes must be included for this to work.
 *
 *  @param countryParam the specified country (this may be either a string value of a selectbox)
 *  @param stateSelects a single state selectbox or an array of multiple selectboxes
 *  @param defaultStateValue the default state or an array of states to select when the data is loaded (or null).  If stateSelects is an array, this must be a corresponding array.
 *  @param (optional) chooseVal value to be used as an additional "first" selection
 *  @param (optional) useLongStateNames should the "Long" or "Short" state names be displayed (defaults to true)
 *  @param (optional) setStatesMapCB callback function to set the resulting states map params:(states, country)
 *  @param (optional) maxLength maximum number of chars to display (longer values will be truncated) - only applies if "useLongStateNames" is true. Default is 20.
 */
function loadDWRStates(countryParam, stateSelects, defaultStateValue) {

    var chooseVal = (loadDWRStates.arguments.length > 3) ? loadDWRStates.arguments[3] : null;
    var useLongStateNames = (loadDWRStates.arguments.length > 4) ? loadDWRStates.arguments[4] : true;
    var setStatesMapCB = (loadDWRStates.arguments.length > 5) ? loadDWRStates.arguments[5] : null;
    var maxLength = (loadDWRStates.arguments.length > 6) ? loadDWRStates.arguments[6] : 20;

    var country = countryParam;
    var countrySel = null;
    try {
        if (typeof countryParam == "object" && countryParam.type && countryParam.type == 'select-one') {
            countrySel = countryParam;
            country = getSelectedValue(countrySel);
        }
    } catch(error) {}

    var stateSels = stateSelects;
    var defaultStates = defaultStateValue;
    try {
        if (stateSelects.type == 'select-one' || stateSelects.type == 'select-multiple') {
            stateSels = [stateSelects];
            defaultStates = [defaultStateValue];
        }
    } catch(error) {
        //this means that it is an Array (or something else bogus)
    }

    for (var i = 0; i < stateSels.length; i++) {
        dwr.util.removeAllOptions(stateSels[i]);
    }

    if (country != null && country.length > 0) {

        var fillCB = function(states) {
            _countryStatesCache[country] = states;
            if (setStatesMapCB) {
                setStatesMapCB(country, states);
            }

            //If the country has changed since the request was made, don't apply the values
            if (countrySel) {
                var currentCountry = getSelectedValue(countrySel);
                if (country != currentCountry) {
                    return;
                }
            }

            if (!useLongStateNames) {
                var stateList = new Array();
                for (key in states) {
                    stateList.push(key);
                }
                states = stateList.sort();
            } else if (maxLength > 0) {
                //We don't want to replace the cached version
                var statesOrig = states;
                states = {};
                for (key in statesOrig) {
                    if (statesOrig[key].length > (maxLength + 3)) {
                        states[key] = statesOrig[key].substring(0, maxLength) + "...";
                    } else {
                        states[key] = statesOrig[key];
                    }
                }
            }

            var hasResults = false;
            /*We can't use states.length because it isn't an array*/
            for (i in states) {
                hasResults = true;
                break;
            }

            for (var i = 0; i < stateSels.length; i++) {
                var stateSel = stateSels[i];

                dwr.util.removeAllOptions(stateSel);
                if (!hasResults) {
                    dwr.util.addOptions(stateSel, [{name:'None', id:''}], "id", "name");
                } else {
                    if (chooseVal) {
                        dwr.util.addOptions(stateSel, [{name:chooseVal, id:''}], "id", "name");
                    }
                    dwr.util.addOptions(stateSel, states);
                }

                if (defaultStates && defaultStates[i]) {
                    dwr.util.setValue(stateSel, defaultStates[i]);
                }
                if (stateSel.onchange) {
                    stateSel.onchange.call(stateSel);
                }
            }
        };

        if (_countryStatesCache[country]) {
            fillCB(_countryStatesCache[country]);
        } else {
            GeographyLookup.getLongStatesForCountry(country, fillCB);
        }
    }
}


/* Helper function for loading the timezone drop down*/
function loadTimezoneFields(timezoneSelect, defaultTimezoneValue, timezones) {

    var hasResults = false;
    /*We can't use states.length because it isn't an array*/
    for (i in timezones) {
        hasResults = true;
        break;
    }

    dwr.util.removeAllOptions(timezoneSelect);
    if (!hasResults) {
        dwr.util.addOptions(timezoneSelect, [{name:'None', id:''}], "id", "name");
    } else {
        dwr.util.addOptions(timezoneSelect, timezones);
    }

    if (defaultTimezoneValue) {
        dwr.util.setValue(timezoneSelect, defaultTimezoneValue);
    }
    if (timezoneSelect.onchange) {
        timezoneSelect.onchange.call(timezoneSelect);
    }
}


/**
 *  Load the timezones for the specified country
 *  Note: The DWR engine, util and GeographyLookup JS includes must be included for this to work.
 *
 *  @param countryParam the specified country (this may be either a string value of a selectbox)
 *  @param timezoneSelect a single timezone selectbox
 *  @param viewAllCheckBox checkbox for the view all timezones option
 *  @param defaultTimezoneValue the default timezone for the select box
 *  @param viewAllIfNotFound  view all timezones of time zone not found
 *
 */
function loadDWRTimezones(countryParam, timezoneSelect, viewAllCheckBox, defaultTimezoneValue, viewAllIfNotFound) {
    var retrieveAll = true;
    if(viewAllCheckBox) {
        retrieveAll = viewAllCheckBox.checked;
    }
    dwr.util.removeAllOptions(timezoneSelect);

    var country = countryParam;
    var countrySel = null;
    try {
        if (typeof countryParam == "object" && countryParam.type && countryParam.type == 'select-one') {
            countrySel = countryParam;
            country = getSelectedValue(countrySel);
        }
    } catch(error) {}

    if (retrieveAll || (country != null && country.length > 0)) {

        var fillAllCB = function(timezones) {
            var hasResults = false;
            for (i in timezones) {
                hasResults = true;
                break;
            }

            loadTimezoneFields(timezoneSelect, defaultTimezoneValue, timezones);
        };

        if (retrieveAll) {
            GeographyLookup.getAllTimeZones(fillAllCB);
        } else {
            var fillCB = function(timezones) {

                //If the country has changed since the request was made, don't apply the values
                if (countrySel) {
                    var currentCountry = getSelectedValue(countrySel);
                    if (country != currentCountry) {
                        return;
                    }
                }

                var hasResults = false;
                /*We can't use timezones.length because it isn't an array*/
                for (i in timezones) {
                    hasResults = true;
                    break;
                }

                var foundDefault = false;
                if (defaultTimezoneValue) {
                    for(key in timezones) {
                        if(key == defaultTimezoneValue) {
                            foundDefault = true;
                            break;
                        }
                    }
                }
                if(!hasResults || (defaultTimezoneValue && !foundDefault && viewAllIfNotFound)) {
                    viewAllCheckBox.checked = true;
                    GeographyLookup.getAllTimeZones(fillAllCB);
                    return;
                }

                loadTimezoneFields(timezoneSelect, defaultTimezoneValue, timezones);
            };
            GeographyLookup.getAllTimeZonesForCountry(country, fillCB);
        }
    }
}


/*
 * Utility function to format a message, filling argument placeholders ({0},{1},...) with specified values
 */
ll.util.formatMessage = function(msg) {
    var ret = msg;

    if (arguments.length > 1  && msg) {
        for (var i = 1; i < arguments.length; i++) {
            var re = new RegExp('\\{' + (i - 1) + '\\}', 'g');
            ret = ret.replace(re, arguments[i]);
        }
    }

    return ret;
};

/*
 * New Date Functionality for multi date formats
 */
var DATE_FORMAT_MIDDLE_ENDIAN = 1;
var DATE_FORMAT_LITTLE_ENDIAN = 2;
var DATE_FORMAT_BIG_ENDIAN = 3;

/**
  * Creates a string in the user's format for the given date information
  *  @param day
  *  @param month
  *  @param year
  */
ll.util.createDateString = function(day, month, year) {
_check_and_alert_data_format();
    var dateString;
    if (month.length < 2) {
        month = "0" + month;
    }
    if (day.length < 2) {
        day = "0" + day;
    }
    if ((year*1) < 100) {
        year = (year*1) + 2000;
    }

    if (USER_DATE_FORMAT == DATE_FORMAT_MIDDLE_ENDIAN) {
        dateString = month + "/" + day + "/" + year;
    } else if (USER_DATE_FORMAT == DATE_FORMAT_LITTLE_ENDIAN) {
        dateString = day + "/" + month + "/" + year;
    } else if (USER_DATE_FORMAT == DATE_FORMAT_BIG_ENDIAN) {
        dateString = year + "-" + month + "-" + day;
    }
    return dateString;
}

ll.util.quickKey = function(dateFld, timeFld, fieldType, dDate) {
    if ((dateFld != null && (dateFld.value == "c" || dateFld.value == "C")) ||
        (timeFld != null && (timeFld.value == "c" || timeFld.value == "C")))
    {
        var today = new Date();
        if (dateFld != null) {
            dateFld.value = ll.util.createDateString(today.getDate()+"", (today.getMonth()+1)+"", today.getFullYear()+"");
        }
        if (timeFld != null) {
            var min = today.getMinutes();
            min = ((min < 10) ? "0" : "") + min;
            timeFld.value = today.getHours() + ":" + min;
        }
    }
    else if (fieldType == "date" && dateFld != null) {
        if (dateFld.value == "t" || dateFld.value == "T"){
            var today = new Date();
            dateFld.value = ll.util.createDateString(today.getDate()+"", (today.getMonth()+1)+"", today.getFullYear()+"");
        }
        else if (dateFld.value == "y" || dateFld.value == "Y"){
            var today = new Date();
            today.setTime(today.getTime() - (24*60*60*1000));
            dateFld.value = ll.util.createDateString(today.getDate()+"", (today.getMonth()+1)+"", today.getFullYear()+"");
        }
        else if (dateFld.value == "m" || dateFld.value == "M"){
            var today = new Date();
            today.setTime(today.getTime() + (24*60*60*1000));
            dateFld.value = ll.util.createDateString(today.getDate()+"", (today.getMonth()+1)+"", today.getFullYear()+"");
        }
        else if (dateFld.value == "d" || dateFld.value == "D") {
            if (dDate == null) {
                dDate = "";
            }
            dateFld.value = dDate;
        }
    }
    else if (fieldType == "time" && timeFld != null &&
        (timeFld.value == "t" || timeFld.value == "T" ||
         timeFld.value == "y" || timeFld.value == "Y" ||
         timeFld.value == "m" || timeFld.value == "M" ||
         timeFld.value == "d" || timeFld.value == "D"))
    {
        alert("Sorry, that shortcut only works in the Date field.");
    }
}

ll.util.isDate = function (field, emptyOK, warnDiff) {
_check_and_alert_data_format();
    if(arguments.length == 1) {
        emptyOK = defaultEmptyOK;
        warnDiff = 90;
    }
    if(arguments.length == 2) {
        warnDiff = 90;
    }

    if(isEmpty(field.value)) {
        return emptyOK;
    }
    var tmpDate = field.value + ""; //Add "" so it is not null

    if (tmpDate.length < 6) {
        ll.util.getDateFromShortDate(field, warnDiff);
        tmpDate = field.value +  "";
    }

    if (tmpDate.search(/[\/-]/) < 0) {
        var m, d, y;
        if (USER_DATE_FORMAT == DATE_FORMAT_MIDDLE_ENDIAN) {
            m = tmpDate.substr(0, 2);
            d = tmpDate.substr(2, 2);
            y = tmpDate.substr(4);
            tmpDate = m + "/" + d + "/" + y;
        } else if (USER_DATE_FORMAT == DATE_FORMAT_LITTLE_ENDIAN) {
            d = tmpDate.substr(0, 2);
            m = tmpDate.substr(2, 2);
            y = tmpDate.substr(4);
            tmpDate = d + "/" + m + "/" + y;
        } else if (USER_DATE_FORMAT == DATE_FORMAT_BIG_ENDIAN) {
            y = tmpDate.substring(0, tmpDate.length - 4);
            m = tmpDate.substr(tmpDate.length - 4, 2);
            d = tmpDate.substr(tmpDate.length - 2, 2);
            tmpDate = y + "-" + m + "-" + d;
        }
    }

    var sArray = tmpDate.split(/[\/-]/);

    if (sArray.length != 3) {
        return false;
    }

    var day, month, year;
    if (USER_DATE_FORMAT == DATE_FORMAT_MIDDLE_ENDIAN) {
        month = sArray[0];
        day = sArray[1];
        year = sArray[2];
    } else if (USER_DATE_FORMAT == DATE_FORMAT_LITTLE_ENDIAN) {
        day = sArray[0];
        month = sArray[1];
        year = sArray[2];
    } else if (USER_DATE_FORMAT == DATE_FORMAT_BIG_ENDIAN) {
        year = sArray[0];
        month = sArray[1];
        day = sArray[2];
    }

    // Pad zero in front of year component (so that isDate() is happy)
    if (year && year.length  == 1) {
        year = "0" + year;
    }

    if (!isDate(year, month, day)) {
        return false;
    }

    field.value = ll.util.createDateString(day, month, year);
    return true;
}

ll.util.checkDate = function (field, emptyOK, warnDiff) {
    if (arguments.length == 1) {
        emptyOK = defaultEmptyOK;
        warnDiff = 90;
    }
    if (arguments.length == 2) {
        warnDiff = 90;
    }
    if (!ll.util.isDate(field, emptyOK, warnDiff)) {
        return warnInvalid(field, iDate);
        return false;
    } else {
        return true;
    }
}

ll.util.formatAndValidateDateInput = function(dateField, warnDiff) {
    // Function to reduce the length of two function calls
    ll.util.getDateFromShortDate(dateField, warnDiff);
    ll.util.validateDateField(dateField);
}

ll.util.getDateFromShortDate = function(dateField, warnDiff) {
_check_and_alert_data_format();
    if (arguments.length == 1) {
        warnDiff = 90; //warn if > 90 days in the past --> really, it controls whether to roll the date to next year
    }
    var dateString = dateField.value;

    // Pad zeros in front of date components if they are separated by separator (1-2 : 01-02)
    var dates = dateString.split(/[\/-]/);
    if (dates.length > 2) {//Not a short date
        return dateString;
    }
    if (dates.length == 2) {
        if (dates[0].length == 1) {
            dates[0] = "0" + dates[0];
        }
        if (dates[1].length == 1) {
            dates[1] = "0" + dates[1];
        }
        dateString = dates[0] + dates[1];
    }

    var dateNbrs = stripCharsNotInBag(dateString, "0123456789");

    // We only support that the user uses 4 digits. Formatting three digits is ambiguous.
    if (dateNbrs.length != 4) {
        return dateString;
    }

    var month;
    var day;
    if (USER_DATE_FORMAT == DATE_FORMAT_MIDDLE_ENDIAN) {
        month = dateNbrs.substr(0, 2);
        day = dateNbrs.substr(2);
    } else if (USER_DATE_FORMAT == DATE_FORMAT_LITTLE_ENDIAN) {
        day = dateNbrs.substr(0, 2);
        month = dateNbrs.substr(2);
    } else if (USER_DATE_FORMAT == DATE_FORMAT_BIG_ENDIAN) {
        month = dateNbrs.substr(0, 2);
        day = dateNbrs.substr(2);
    }

    var today = new Date();
    var lowerBound = new Date(today.getTime() - (warnDiff * 24 * 60 * 60 * 1000));
    var yr = today.getFullYear();

    var tmp = ll.util.createDateString(day, month, yr);

    var tmpDate = ll.util.jsDateTime(tmp, 23, 59);
    tmpDate.setSeconds(59);

    if (tmpDate < lowerBound) {
        tmp = ll.util.createDateString(day, month, (1 * yr + 1));
    }
    dateField.value = tmp;
}

ll.util.validateDateField = function(dateField) {
    if (!ll.util.isDate(dateField, true)) {
        if (dateField.className.indexOf("formfieldinputserror") == -1) {
            dateField.className = dateField.className+' formfieldinputserror';
        }
    } else {
        dateField.className = dateField.className.replace('formfieldinputserror', '');
    }
}

ll.util.jsDate = function(inDateString) {
_check_and_alert_data_format();
    var day, month, year;
    var sArray = inDateString.split(/[\/-]/);
    if (USER_DATE_FORMAT == DATE_FORMAT_MIDDLE_ENDIAN) {
        month = (sArray[0] * 1) - 1; //Month is zero indexed in JS Date object
        day = sArray[1];
        year = sArray[2];
    } else if (USER_DATE_FORMAT == DATE_FORMAT_LITTLE_ENDIAN) {
        day = sArray[0];
        month = (sArray[1] * 1) - 1; //Month is zero indexed in JS Date object
        year = sArray[2];
    } else if (USER_DATE_FORMAT == DATE_FORMAT_BIG_ENDIAN) {
        year = sArray[0];
        month = (sArray[1] * 1) - 1; //Month is zero indexed in JS Date object
        day = sArray[2];
    }

    return new Date(year, month, day);
}

ll.util.jsDateTime = function(inDateString, hours, minutes) {
    var newDate = ll.util.jsDate(inDateString);
    newDate.setHours(hours);
    newDate.setMinutes(minutes);
    return newDate;
}

ll.util.getJSDateMilitaryTime = function(inDateString, inTimeString) {
    var newDate = ll.util.jsDate(inDateString);
    if (inTimeString != null) {
        var sArray = inTimeString.split(":");
        if (sArray.length == 2) {
            var hour = sArray[0];
            var minutes = sArray[1];
            if (isTime(hour, minutes)) {
                newDate.setHours(hour);
                newDate.setMinutes(minutes);
            }
        }
    }
    return newDate;
}

ll.util.validateDateRangePair = function (startdate, enddate, message) {
    if (!ll.util.checkDate(startdate, true)) {
        return false;
    }
    if (!ll.util.checkDate(enddate, true)) {
        return false;
    }

    if (!isEmpty(message)) {
        if ((isEmpty(startdate.value) && !isEmpty(enddate.value)) ||
            (!isEmpty(startdate.value) && isEmpty(enddate.value)))
        {
            alert(message);
            return false;
        }
    }
    return true;
}
ll.util.validateRequiredDateRangePair = function (startdate, enddate, message) {
    if (!ll.util.checkDate(startdate, true)) {
        return false;
    }
    if (!ll.util.checkDate(enddate, true)) {
        return false;
    }

    if (!isEmpty(message)) {
        if ((isEmpty(startdate.value) && isEmpty(enddate.value)) ||
            (isEmpty(startdate.value) && !isEmpty(enddate.value)) ||
            (!isEmpty(startdate.value) && isEmpty(enddate.value)))
        {
            alert(message);
            return false;
        }
    }
    return true;
}

/*
* New Number Functionality to Handle different number formats
*/
var NUMBER_FORMAT_COMMA_DOT = 1;
var NUMBER_FORMAT_DOT_COMMA = 2;
var NUMBER_FORMAT_NONE_DOT = 3;

//Formatting functions

/**
 *   Convert a string representation of a number into a JS number value to be used
 *   with mathmataical operators
 */
ll.util.convertStringToNumber = function(stringValue) {
_check_and_alert_data_format();
    if (USER_NUMBER_FORMAT == NUMBER_FORMAT_COMMA_DOT) {
        stringValue = stringValue.replace(/\,/g, "");
    } else if (USER_NUMBER_FORMAT == NUMBER_FORMAT_DOT_COMMA) {
        stringValue = stringValue.replace(/\./g, "");
        stringValue = stringValue.replace(",", ".");
    } else if (USER_NUMBER_FORMAT == NUMBER_FORMAT_NONE_DOT) {
        //Do nothing, it is already in an XXXX.XX format
    }
    return stringValue * 1.0;
}

ll.util.convertStringToDecimal = function(stringValue, minNbrDecimals, maxNbrDecimals) {
    var value = ll.util.convertStringToNumber(stringValue);
    return ll.util.roundDecimal(value, maxNbrDecimals);
}

/**
 * These two functions take a string, convert it to a proper number (or decimal) then reformat it for proper display in a textbox or similar.
 */
ll.util.convertNumberStringForDisplay = function(stringValue, useParensForNegatives, useGrouping) {
    var value = ll.util.convertStringToNumber(stringValue);
    return ll.util.convertNumberToString(value, 0, 0, useParensForNegatives, useGrouping);
}
ll.util.convertDecimalStringForDisplay = function(stringValue, minNbrDecimals, maxNbrDecimals, useParensForNegatives, useGrouping) {
    var value = ll.util.convertStringToDecimal(stringValue, minNbrDecimals, maxNbrDecimals);
    return ll.util.convertNumberToString(value, minNbrDecimals, maxNbrDecimals, useParensForNegatives, useGrouping);
}

/**
  * Takes a number value and converts the number value for display depending on what the number format is
  */
ll.util.convertNumberToString = function(value, minNbrDecimals, maxNbrDecimals, useParensForNegatives, useGrouping) {
_check_and_alert_data_format();
    if (arguments.length < 2) {
        minNbrDecimals = 2;
    }
    if (arguments.length < 3) {
        maxNbrDecimals = 2;
    }
    if (arguments.length < 4) {
        useParensForNegatives = false;
    }
    if (arguments.length < 5) {
        useGrouping = false;
    }

    var valueString = ll.util.formatDecimal(value, minNbrDecimals, maxNbrDecimals);

    if (useGrouping && USER_NUMBER_FORMAT != NUMBER_FORMAT_NONE_DOT) {
        var number = valueString;
        var decimal = "";
        var idx = valueString.indexOf(".");

        // Seperate the whole number from the decimal portion.
        if (idx != -1) {
            number = valueString.substring(0, idx);
            decimal = valueString.substr(idx);
        }

        // Number of three digit groups
        var groups = Math.ceil(number.length / 3)-1;

        // Insert a comma every three digits from the right
        for (var i = 0; i < groups; i++) {
            var left = number.length - (3*(i+1) + i);
            number = number.substr(0, left)+","+number.substr(left, number.length);
        }
        valueString = number + decimal;
    }

    if (USER_NUMBER_FORMAT == NUMBER_FORMAT_COMMA_DOT) {
        //Only would be used for grouping
    } else if (USER_NUMBER_FORMAT == NUMBER_FORMAT_DOT_COMMA) {
        valueString = valueString.replace(/\,/g, "*");
        valueString = valueString.replace(".", ",");
        valueString = valueString.replace(/\*/g, ".");
    } else if (USER_NUMBER_FORMAT == NUMBER_FORMAT_NONE_DOT) {
        //This is the format that JS uses, so leave it alone
    }

    if (useParensForNegatives && valueString.charAt(0) == '-') {
        valueString = '(' + valueString.substr(1) + ')';
    }
    return valueString;
}
/**
  * This method will remove any parenthesis that may be on the field's value, check that it is a valid
  * number and in the case the min/max decimals are zero, it is a valid integer, output the value without
  * grouping, and give the field a proper style class based on the validation.
  */
ll.util.formatAndValidateDecimalInput = function(field, minNbrDecimals, maxNbrDecimals, emptyOK) {
    if (minNbrDecimals == null) {
        minNbrDecimals = 0;
    }
    if (maxNbrDecimals == null) {
        maxNbrDecimals = 0;
    }
    if (emptyOK == null) {
        emptyOK = defaultEmptyOK;
    }
    if (isEmpty(field.value)) {
        ll.util.updateFieldClassName(field, !emptyOK);
        return;
    }

    // Function to strip any parenthesis and place a '-' if applicable
    // In the event someone is displaying a total inside of a (disabled) text field.
    var fieldStr = ll.util.removeOuterParenthesis(field.value);

    // Convert the decimal string into a number
    var decimal = ll.util.convertStringToNumber(fieldStr);

    // Check for a valid number and possibly a valid integer when the min/max decimals are zero.
    var hasError = isNaN(decimal) || (minNbrDecimals == 0 && maxNbrDecimals == 0 && !ll.util.isInteger(decimal));

    // Update the field class
    ll.util.updateFieldClassName(field, hasError);

    // Update the field value
    if (!hasError) {
        field.value = ll.util.convertNumberToString(decimal, minNbrDecimals, maxNbrDecimals);
    }
}

/**
  * Removes the outer parenthesis of a string and inserts a "-" in front of it.
  */
ll.util.removeOuterParenthesis = function(decimal) {
    if (!isEmpty(decimal) && decimal.charAt(0) == "(" && decimal.charAt(decimal.length - 1) == ")") {
        return "-" + decimal.substring(1, decimal.length-1);
    }
    return decimal;
}

/**
  * Removes or adds the formfieldinputserror style class to a field depending on
  * the boolen provided.
  */
ll.util.updateFieldClassName = function(field, hasError) {
    if (hasError) {
        if (field.className.indexOf("formfieldinputserror") == -1) {
            field.className = field.className+' formfieldinputserror';
        }
    } else {
        field.className = field.className.replace('formfieldinputserror', '');
    }
}

//Float functions

/**
 *  Takes a string value and attempts to see if that string is an unsigned float
 */
ll.util.isFloat = function(stringValue, emptyOK) {
    if (emptyOK == null) {
        emptyOK = defaultEmptyOK;
    }
    if (isEmpty(stringValue)) {
        return emptyOK;
    }
    var value = ll.util.convertStringToNumber(stringValue);
    if (isNaN(value) || value < 0) {
        return false;
    }
    return true;
}

/**
 *  Takes a string value and attempts to see if that string is a positive float value
 */
ll.util.isNonNegativeFloat = function(stringValue, emptyOK) {
    if (emptyOK == null) {
        emptyOK = defaultEmptyOK;
    }
    if (isEmpty(stringValue)) {
        return emptyOK;
    } else {
        // if the leading char is -, it is a negative number
        var c = stringValue.charAt(0);
        if (c == "-") {
            return false;
        } else {
            return ll.util.isFloat(stringValue, emptyOK);
        }
    }
}

/**
 *  Takes a string value and attempts to see if that string is a float, accepting values with a "-" infront of them
 */
ll.util.isSignedFloat = function(stringValue, emptyOK) {
    if (emptyOK == null) {
        emptyOK = defaultEmptyOK;
    }
    if (isEmpty(stringValue)) {
        return emptyOK;
    } else {
        var startPos = 0;
        //Skip negative character
        if (stringValue.charAt(0) == "-") {
           startPos = 1;
        }
        return ll.util.isFloat(stringValue.substr(startPos), emptyOK);
    }
}

// Decimal Functions

ll.util.limit2Decimals = function(inputfld, e) {
    ll.util.limitDecimals(inputfld, e, 2);
}

ll.util.limitDecimals = function(inputfld, e, limit) {
_check_and_alert_data_format();
    var isNN = (navigator.appName.indexOf("Netscape")!=-1);
    var keyCode = (isNN) ? e.which : e.keyCode;

    var filter = (isNN) ? [0,8,9] : [0,8,9,16,17,18,37,38,39,40,46];

    var value = inputfld.value;
    var dotindx;
    if (USER_NUMBER_FORMAT == NUMBER_FORMAT_COMMA_DOT) {
        dotindx = value.indexOf('.');
    } else if (USER_NUMBER_FORMAT == NUMBER_FORMAT_DOT_COMMA) {
        dotindx = value.indexOf(',');
    } else if (USER_NUMBER_FORMAT == NUMBER_FORMAT_NONE_DOT) {
        dotindx = value.indexOf('.');
    }

    if (dotindx > -1 && !containsElement(filter,keyCode)) {
        var subIndx = (dotindx*1)+1;
        var dectext = value.substr(subIndx);
        if (dectext.length > limit) {

            inputfld.value = value.substring(0, (value.length-1));

            //After the decimals are reformatted, it will skip to the next text area
            var inputfldindx = getIndex(inputfld);
            inputfldindx = (inputfldindx*1)+1;

            var form = inputfld.form;
            var formlen = form.length;

            for(i = inputfldindx; i < formlen; i++) {
                if ((form[i].type == "text") ||
                    (form[i].type == "textarea") ||
                    (form[i].type.toString().charAt(0) == "s")) {

                    if (!form[i].disabled) {
                        form[i].focus();
                        break;
                    }
                }
            }
            return true;
        }
    }

    return false;
}

ll.util.roundDecimal = function(val, maxNbrDecimals) {
    var roundFactor = 1 * Math.pow(10.0, maxNbrDecimals);
    val = (Math.round(val * roundFactor + 0.0000000001) / roundFactor);
    return val;
}

/**
  * Takes a decimal value and applies rules to round the number and create the appropriate number of decimals
  *  Note: this should NOT be used to convert a value for output, as it needs to also be run through the number formatting
  */
ll.util.formatDecimal = function(val, minNbrDecimals, maxNbrDecimals) {
    maxNbrDecimals = Math.max(minNbrDecimals, maxNbrDecimals);

    //First round to get rid of extra decimals
    var s = ll.util.roundDecimal(val, maxNbrDecimals) + "";

    var decimalIdx = s.indexOf('.');
    if (decimalIdx < 0 && minNbrDecimals > 0) {
        s += ".";
        decimalIdx = s.indexOf('.');
    }

    var currentNbrDecimals = (decimalIdx != -1) ? s.length - decimalIdx - 1 : 0;
    //Make sure we have the minimum # of decimals
    if (currentNbrDecimals < minNbrDecimals) {
        for (var i = currentNbrDecimals; i < minNbrDecimals; i++) {
            s += "0";
        }
        currentNbrDecimals = s.length - decimalIdx - 1;
    //Make sure we have no more than the maximum # of decimals
    } else if (currentNbrDecimals > maxNbrDecimals && decimalIdx > 0) {
        s = s.substring(0, decimalIdx + maxNbrDecimals);
        currentNbrDecimals = s.length - decimalIdx - 1;
    }

    //Make sure we have no "0" values between min and max
    if (minNbrDecimals != maxNbrDecimals && currentNbrDecimals > minNbrDecimals) {
        for (var i = s.length - 1; i > (decimalIdx + minNbrDecimals); i--) {
            if (s.charAt(i) == '0') {
                s = s.substring(0, i);
            } else {
                break;
            }
        }
    }

    return s;
}

/**
 *   Format Price is used for converting a JS number value into a string representation of that value, with currency codes appended as designated
 *   The output of this function can not be used for mathmatical uses
 */
ll.util.formatPrice = function(priceVal, currencyCode, minNbrDecimals, maxNbrDecimals, showCurrencyCode, useParensForNegatives, currSpace, useGrouping) {
    if (arguments.length < 2) {
        currencyCode = '???'; //Make sure that a currencyCode is specified
    }
    if (arguments.length < 3) {
        minNbrDecimals = 2;
    }
    if (arguments.length < 4) {
        maxNbrDecimals = 2;
    }
    if (arguments.length < 5) {
        showCurrencyCode = true;
    }
    if (arguments.length < 6) {
        useParensForNegatives = true;
    }
    if (arguments.length < 7) {
        currSpace = '&nbsp;';
    }
    if(arguments.length < 8) {
        useGrouping = false;
    }
    if (priceVal == null) {
        priceVal = 0.0;
    }
    var s = ll.util.convertNumberToString(priceVal, minNbrDecimals, maxNbrDecimals, useParensForNegatives, useGrouping);
    if (showCurrencyCode) {
        s += currSpace + currencyCode;
    }
    return s;
}

ll.util.isEmptyNumber = function(s) {
    return (isEmpty(s) || ll.util.convertStringToNumber(s) == 0);
}
ll.util.isEmptyIdNumber = function(s) { // specifically for checking ID values, which are never formatted
    return (isEmpty(s) || s*1 == 0);
}

ll.util.isInteger = function(stringValue, emptyOK) {
    if (emptyOK == null) {
        emptyOK = defaultEmptyOK;
    }
    if (isEmpty(stringValue)) {
        return emptyOK;
    }
    for (var i=0; i < stringValue.length; i++) {
        var c = stringValue.charAt(i);
        if (!isDigit(c)) {
            return false;
        }
    }
    return true;
}

ll.util.isSignedInteger = function(stringValue, emptyOK) {
    if (emptyOK == null) {
        emptyOK = defaultEmptyOK;
    }
    if (isEmpty(stringValue)) {
        return emptyOK;
    }
    var startPos = 0;
    if (stringValue.charAt(0) == "-") {
       startPos = 1;
    }
    return ll.util.isInteger(stringValue.substr(startPos), emptyOK);
}

ll.util.isPositiveInteger = function(stringValue, emptyOK) {
    if (emptyOK == null) {
        emptyOK = defaultEmptyOK;
    }
    return (ll.util.isSignedInteger(stringValue, emptyOK) && (isEmpty(stringValue) || parseInt(stringValue) > 0));
}

ll.util.isNonnegativeInteger = function(stringValue, emptyOK) {
    if (emptyOK == null) {
        emptyOK = defaultEmptyOK;
    }
    return (ll.util.isSignedInteger(stringValue, emptyOK) && (isEmpty(stringValue) || parseInt(stringValue) >= 0));
}

ll.util.isNegativeInteger = function(stringValue, emptyOK) {
    if (emptyOK == null) {
        emptyOK = defaultEmptyOK;
    }
    return (ll.util.isSignedInteger(stringValue, emptyOK) && (isEmpty(stringValue) || parseInt(stringValue) < 0));
}

ll.util.isNonpositiveInteger = function(stringValue, emptyOK) {
    if (emptyOK == null) {
        emptyOK = defaultEmptyOK;
    }
    return (ll.util.isSignedInteger(stringValue, emptyOK) && (isEmpty(stringValue) || parseInt(stringValue) <= 0));
}

ll.util.isIntegerInRange = function(stringValue, a, b, emptyOK) {
    if (emptyOK == null) {
        emptyOK = defaultEmptyOK;
    }
    if (isEmpty(stringValue)) {
        return emptyOK;
    }
    if (!ll.util.isInteger(stringValue, false)) {
        return false;
    }
    var num = ll.util.convertStringToNumber(stringValue);
    return ((num >= a) && (num <= b));
}

ll.util.isFloatInRange = function(stringValue, a, b, emptyOK) {
    if (emptyOK == null) {
        emptyOK = defaultEmptyOK;
    }
    if (isEmpty(stringValue)) {
        return emptyOK;
    }
    if (!ll.util.isFloat(stringValue, false)) {
        return false;
    }
    var num = ll.util.convertStringToNumber(stringValue);
    return ((num >= a) && (num <= b));
}

ll.util.checkNumber = function (field, emptyOK) {
    if (emptyOK == null) {
        emptyOK = defaultEmptyOK;
    }
    if (emptyOK && isEmpty(field.value)) {
        return true;
    } else if (!ll.util.isSignedFloat(field.value, false)) {
        return warnInvalid (field, iNumber);
    }
    return true;
}

ll.util.checkInteger = function (field, emptyOK) {
    if (emptyOK == null) {
        emptyOK = defaultEmptyOK;
    }
    if (emptyOK && isEmpty(field.value)) {
        return true;
    } else if (!ll.util.isSignedInteger(field.value, false)) {
        return warnInvalid (field, iInteger);
    }
    return true;
}

ll.util.checkPositiveInteger = function (field, emptyOK) {
    if (emptyOK == null) {
        emptyOK = defaultEmptyOK;
    }
    if (emptyOK && isEmpty(field.value)) {
        return true;
    }
    if (!ll.util.isPositiveInteger(field.value, false)) {
        return warnInvalid (field, iPositiveInteger);
    }
    return true;
}

ll.util.checkNonnegativeInteger = function (field, emptyOK) {
    if (emptyOK == null) {
        emptyOK = defaultEmptyOK;
    }
    if (emptyOK && (isEmpty(field.value))) {
        return true;
    }
    if (!ll.util.isNonnegativeInteger(field.value, false)) {
        return warnInvalid (field, iPositiveInteger);
    }
    return true;
}

ll.util.checkFloat = function (field, emptyOK) {
    if (emptyOK == null) {
        emptyOK = defaultEmptyOK;
    }
    if (emptyOK && (isEmpty(field.value))) {
        return true;
    } else if (!ll.util.isFloat(field.value, false)) {
        return warnInvalid (field, iFloat);
    }
    return true;
}

ll.util.checkNonnegativeFloat = function (field, emptyOK) {
    if (emptyOK == null) {
        emptyOK = defaultEmptyOK;
    }
    if (emptyOK && isEmpty(field.value)) {
        return true;
    } else if (!ll.util.isNonNegativeFloat(field.value, false)) {
        return warnInvalid (field, iFloat);
    }
    return true;
}
