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();
    })
	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();
};
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);	
}

