var OZ_DEFAULT_MESSAGE_ELEMENT_ID = "jsMessages"; 

// Match M/d/yyyy (1-2 char mo and day with reasonable values, 4 char year)
var DATE_FORMAT_REGEX = /(0?[0-9]|10|11|12)\/([012]?[0-9]|30|31)\/\d{4}/;

/**
 *  Return a Javascript date object, but only if it matches our date format.
 *  This catches cases where JS is a bit too permissive, such as dates like
 *  33/33/205
 */
function validatedDateObject(str) {
    // intentionally default to same as return from new Date() with bad inputs.
    var result = "Invalid Date"; 
    if (str && str.match(DATE_FORMAT_REGEX)) {
        result = new Date(str);
    }
    return result;
}

function formatNumber (num, decplaces) {
    // convert in case it arrives as a string value
    num = parseFloat(stripNonDigits(num));
    // make sure it passes conversion
    if (!isNaN(num)) {
        // multiply value by 10 to the decplaces power;
        // round the result to the nearest integer;
        // convert the result to a string
        var str = "" + Math.round (eval(num) * Math.pow(10,decplaces));
        // exponent means value is too big or small for this routine
        if (str.indexOf("e") != -1) {
            return "Out of Range";
        }
        // if needed for small values, pad zeros
        // to the left of the number
        while (str.length <= decplaces) {
            str = "0" + str;
        }
        // calculate decimal point position
        var decpoint = str.length - decplaces;
        // assemble final result from: (a) the string up to the position of
        // the decimal point; (b) the decimal point; and (c) the balance
        // of the string. Return finished product.
        var result = formatCommas(str.substring(0,decpoint));
        if (decplaces > 0)
        {
            result += "." + str.substring(decpoint,str.length);
        }
        return result;

    } else {
        return "NaN";
    }
}


function stripNonDigits(text) {    
    if (text && text.replace) {        
        var re = /[^.\d]/;        
        text = text.replace(re,"");   
        text = text.replace(/,/,""); 
    } else if (text) {
        warn(text + " is not text, but " + typeof text);
    }
    return text; 
}

function formatCurrency(value,suppressDollarSign) {
    var orig = value;
    value += "";
    value = stripNonDigits(value);   
    if (value) {
        value = parseFloat(stripNonDigits(value));
        if (isNaN(value)) {
            alert("Invalid currency value: " + orig);
            return null;
        }
        value = formatNumber(value, 2);
        if (!suppressDollarSign) { value = "$" + value; }
        return value;
    }        
    return null;

}

function formatCommas(numString) {
    var re = /(-?\d+)(\d{3})/;
    while (re.test(numString)) {
        numString = numString.replace(re, "$1,$2");
    }
    return numString;
}

function stripCommas(numString) {
    var re = /,/g;
    return numString.replace(re,"");
}

/*
 * For each string in 'arg', create a div of the given 'styleClass'
 * and add it to the element whose ID is 'elemId'.
 * if elemId is not provided, use OZ_DEFAULT_MESSAGE_ELEMENT_ID.
 * NOTE: this does not clear existing messages; use clearMessages(elemId)
 * if you need to.
 */
function displayMessages(arg, styleClass, elemId) {
    if (!elemId) elemId = OZ_DEFAULT_MESSAGE_ELEMENT_ID;
    var msgs = arg;
    if (typeof arg != 'Array') { 
        msgs = [arg];
    }
    var theDiv = $(elemId);
    if (msgs.length > 0 && theDiv) {
        window.location = "#" + elemId;
        theDiv.style.display="block";
        theDiv.style.visibility="visible";
        for (var i = 0; i < msgs.length; i++) {
            theDiv.appendChild(createDiv(styleClass, msgs[i]));
        }
        Fat.fade_element(elemId, 60, 3000, "#b0bdad", "#FFFFFF"); 
    }

    
}

/*
 * Remove all child nodes from the element whose ID is 'elemId'.
 * if elemId is not provided, use OZ_DEFAULT_MESSAGE_ELEMENT_ID.
 */
function clearMessages(elemId) {
    if (!elemId) elemId = OZ_DEFAULT_MESSAGE_ELEMENT_ID;
    removeAllChildren($(elemId));
}

function removeAllChildren(elem) {
    if (elem) {
        while (elem.childNodes.length > 0) {
            elem.removeChild(elem.firstChild);
        }
    } else {
        warn("removeAllChildren called with null element");    
    }
}


function createDiv(className, text) {
    var elem = document.createElement("div");
    //elem.appendChild(document.createTextNode(text));
    elem.innerHTML = text;
    elem.className = className;
    return elem;
}


/* ----------------------------------------------------------------------------------
 * A fistful of utility methods meant for making it easier to deal with form elements.
 * ---------------------------------------------------------------------------------- */

function getSimpleValue(field) {
    if (field) return field.value;
    return null;
}

function getSingleSelectValue(field) {
    if (!field) return null;
    var type = getElemType(field);
    if (!(field.length)) {
        field = [field];
    }
    for (var i = 0; i < field.length; i++) {
        if (checkedOrSelected(type, field[i])) return field[i].value;   
    }
    return null;
}

function selectValue(field, value) {
    if (!field) return null;
    var type = getElemType(field);
    if (!(field.length)) {
        field = [field];
    }
    for (var i = 0; i < field.length; i++) {
        if (field[i].value == value) {
            if (type == 'checkbox' || type == 'radio') 
                field[i].checked = true;
            if (type == 'select-one' || type == 'select-multiple') 
                field[i].selected = true;
            break;
        }
    }
}    

function getMultiSelectValue(field) { 
    if (!field) return null;
    var results = new Array();
    var type = getElemType(field); 
    if (!field.length) {
        field = [field];
    }
    for (var i = 0; i < field.length; i++) {
        if (checkedOrSelected(type, field)) results.push(field.value);
    }
    return results;
}

function checkedOrSelected(type, item) {
    if (type == 'checkbox' || type == 'radio') return item.checked;
    if (type == 'select-one' || type == 'select-multiple') return item.selected;
    alert("unrecognized type: " + type);
    return false;
}

var GET_VALUE_CALLBACKS = {
    'hidden' : getSimpleValue,
    'text' : getSimpleValue,
    'password' : getSimpleValue,
    'textarea' : getSimpleValue,
    'file' : getSimpleValue,
    'radio' : getSingleSelectValue,
    'select-one' : getSingleSelectValue,
    'checkbox' : getMultiSelectValue,
    'select-multiple' : getMultiSelectValue
};

function getSelectedField(field) {
    if (!field) return null;
    var type = getElemType(field);
    if (!(field.length)) {
        field = [field];
    }
    for (var i = 0; i < field.length; i++) {
        if (checkedOrSelected(type, field[i])) return field[i];   
    }
    return null;
}

function getFieldValue(form, fieldName) {
    var elem = form[fieldName];
    if (elem) {
        return getElemValue(elem);
    }
    alert("Couldn't find " + fieldName + " in form " + form.name);
    return null;
}

function getElemType(elem) {
    // deal with HTML element types when you are sometimes handling a list 
    // of checkboxes or radio buttons or whatever
    if (elem.type) return elem.type;
    return elem[0].type;
}

function getElemValue(elem) {
    if (elem) {
        var type = getElemType(elem); 
        var _getValue = GET_VALUE_CALLBACKS[type];
        if (typeof _getValue == 'function') {
            return _getValue(elem);
        } else {
            alert("unrecognized element type: " + type + " for " + elem.name + "[" + elem + "]");
        }
    }
    alert("Empty element");
    return null;
}

// Trim whitespace from left and right sides of s.
function trim(s) {
    return s.replace( /^\s*/, "" ).replace( /\s*$/, "" );
}


function submitFormById(formId, validationFunction) {
    var form = getRawObject(formId); // depends on DHTMLAPI.js for 'getRawObject'
    if (form) {
        var valid = true;
        //TODO: consider eval'ing for a validate method, or receiving one as an arg.
        if (validationFunction) {
            // validation function is responsible for displaying alerts
            valid = validationFunction(form);
        }
        if (valid) form.submit();
    } else {
        error("No form " + formId);
    }
    return false;
}

function validateRequiredField(elem, msgs, errMsg) {
    if (!elem) {
        msgs.push(errMsg);
        return false;
    }

    var value = getElemValue(elem);
    if (!(value && trim(value).length > 0)) {
        msgs.push(errMsg);
        return false;
    }
    return true;
}

function validatePositiveInteger(elem, msgs, errMsg) {
    var errct = msgs.length;
    if (elem) {
        var value = getElemValue(elem);
        var number = parseInt(value);
        if (isNaN(number) || number <= 0) { msgs.push(errMsg); return; }
        elem.value = number; // just in case we stripped any junk chars but validated.
    }
    return errct == msgs.length;
}


function validatePositiveFloat(elem, msgs, errMsg) {
    var errct = msgs.length;
    if (elem) {
        var value = getElemValue(elem);
        var number = parseFloat(stripNonDigits(value));
        if (isNaN(number) || number <= 0) { msgs.push(errMsg); return; }
        elem.value = number; // just in case we stripped any junk chars but validated.
    }
    return errct == msgs.length;
}

function domCollectionToArray(collection) {
	var array = new Array(collection.length);
	for (var i = 0; i < collection.length; i++) {
		array[i] = collection[i];
	}
	return array;
}

function togglePriceCoding() {
    toggleCookie('encpricemode');
    adjustEncodedPriceModeDisplay();
    return false;
}

function inEncodedMode() {
    return (getCookie('encpricemode') == 'true') || (getCookie('encpricemode') == null);
}

function adjustEncodedPriceModeDisplay() {
    var encodedPriceModeShowDisplay = (inEncodedMode()) ? 'block' : 'none';
    var encodedPriceModeHideDisplay = (!inEncodedMode()) ? 'block' : 'none';
    var showInEncoded = dojo.html.getElementsByClass('encodedPriceModeShow');
    for (var i = 0; i < showInEncoded.length; i++) {
        showInEncoded[i].style.display = encodedPriceModeShowDisplay;
    }
    var hideInEncoded = dojo.html.getElementsByClass('encodedPriceModeHide');
    for (var i = 0; i < hideInEncoded.length; i++) {
        hideInEncoded[i].style.display = encodedPriceModeHideDisplay;
    }
}

function toggleCookie(name) {
    var cookie = getCookie(name);
    var curVal = (cookie == 'true');
    var newVal = !curVal;
    setCookie(name, newVal, null, "/ozone");
}



/*
fvlogger seems to have an annoying way of suppressing Javascript "compilation" errors.  Until we can figure that out, it is sometimes convenient to turn it off.  By providing these base implementations, we prevent JS from failing if fvlogger gets turned off.

This means that the fvlogger/logger.js must be inlined AFTER this JS file.
*/

        function debug() { }
        function info() { }
        function warn() { }
        function error() { }
        function fatal() { }

