var generic = generic || {};

generic.errorStateClassName = 'error';

/**
 * This method displays error messages. It takes an array of error objects and a UL node
 * as parameters. If the UL is not spuulied, it will attempt to find a <UL class="error_messages">
 * in the DOM. It will then attempt to insert one directly after a <DIV id="header"> (If no header
 * is found, the method exits.) All the LI child nodes (previous messages) of the UL are hidden.
 * The text property of each error Hash is then displayed as an LI.
 * This method can also alter the style of the input elements that triggered the error.
 * The tags property in an error hash must be an array that contains a string starting with
 * "field." If the optional formNode parameter is supplied, this form node will be
 * searched for the field, and that field will be passed to the generic.showErrorState method. 
 * @example 
 * var errArray = [
 *      {
 *          "text": "Last Name Alternate must use Kana characters.",
 *          "display_locations": [],
 *          "severity": "MESSAGE",
 *          "tags": ["FORM", "address", "field.last_name_alternate"],
 *          "key": "unicode_script.last_name_alternate.address"
 *      },
 *      {
 *          "text": "First Name Alternate must use Kana characters.",
 *          "display_locations": [],
 *          "severity": "MESSAGE",
 *          "tags": ["FORM", "address", "field.first_name_alternate"],
 *          "key": "unicode_script.first_name_alternate.address"
 *      }
 *  ];
 * var listNode = $$("ul.error_messages")[0];
 * generic.showErrors(errArray, listNode);
 * @param {Array} errorObjectsArray Array of error hashes.
 * @param {DOM Node UL} errListNode UL element in which the error messages will be displayed.
 * @param {DOM Node} formNode Form element (or any container node) that contains the inputs
 * to be marked as being in an error state. 
 */
generic.showErrors = function(errorObjectsArray, errListNode, formNode) {
    var ulNode = errListNode || $$("ul.error_messages")[0];
    if (!ulNode) {
        ulNode = new Element("ul", {"class":"error_messages"});
        var header = $$("div#header")[0];
        if (!header) {
            return null;
        } else {
            header.insert({after:ulNode});
        }
    }
    var errListItemNodes = ulNode.select("li");
    errListItemNodes.each(function(li){
        li.hide();
    });
    ulNode.addClassName("errors-no-messages");
    if (errorObjectsArray.length > 0 && Object.isElement(formNode)){
        // hide all error states on fields
        var inputNodes = formNode.select("input");
        inputNodes = inputNodes.concat(formNode.select("select"));
        inputNodes = inputNodes.concat(formNode.select("label"));
        inputNodes.each(function(inputNode) {
            generic.hideErrorState(inputNode);
        });
    }
    errorObjectsArray.each(function(errObj){
        var errKey = errObj.key;
        var errListItemNode = null;
        if (errKey) {
            var regEx = new RegExp(errKey);
            // try to find LI whose ID matches the error key 
            errListItemNode = errListItemNodes.find(function(node) {
                return regEx.test(node.id);
            });
        }
        if (errListItemNode) {
            errListItemNode.show();
        } else {
            errListItemNode = new Element("li").insert(errObj.text);
            ulNode.insert(errListItemNode);
        }
        if (errObj.displayMode && errObj.displayMode === "message") {
            errListItemNode.addClassName("message");
        }
        if (errObj.tags && Object.isArray(errObj.tags) && formNode) {
            // search through error objects, show error state for any tagged with "field.[NAME]"
            var fieldPrefixRegEx = /^field\.(\w+)$/;
            errObj.tags.each( function(tag) {
                var reResults = tag.match(fieldPrefixRegEx);
                if(reResults && reResults[1]) {
                    var fieldName = reResults[1].toUpperCase();
                    var inputNode = formNode.select("input[name=" + fieldName + "]")[0] || formNode.select("select[name=" + fieldName + "]")[0];
                    if (inputNode) {
                        generic.showErrorState(inputNode);
                        var labelNode = formNode.select("label[for=" + inputNode.id + "]")[0];
                        generic.showErrorState(labelNode);                      
                    }
                }
            });
        }

    });
    ulNode.show();
    if (errorObjectsArray.length > 0){
        ulNode.removeClassName("errors-no-messages");
    }
};
generic.showErrorState = function(inputNode) {
    if (!inputNode || !Object.isElement(inputNode)) {
        return null;
    }
    inputNode.addClassName(generic.errorStateClassName);
}

generic.hideErrorState = function(inputNode) {
    if (!inputNode || !Object.isElement(inputNode)) {
        return null;
    }
    inputNode.removeClassName(generic.errorStateClassName); 
}

