var traceStr ="";
function trace(str) {
	traceStr=traceStr+'<br>'+str;
}

//Initialize form when document is created but before all images are fetched
document.observe('dom:loaded', function(event){
    traceStr="";
    trace(":on domready forms=" + document.forms.length);
    dev_mode=false;
    try {
        //loop through forms in document.
        //if it finds a match in the form list (specified in the bottom of this document)  it will run initForm and set the variable mainForm to the form object
        //before you add a new form to the list, make sure to include translation bundle in the jsp.
        var allForms = document.forms;
        for (i=0;i<allForms.length;i++) {
            var thisForm = $(allForms[i]);
            trace(i+":"+thisForm.name);
            var thisFormId = thisForm.readAttribute('id');
            if(thisFormId) {
                trace("about to check id:"+thisFormId);
                var cvArray = hasClientValidation(thisFormId);
                if (cvArray[0]) {
                    trace("has client framework");
                    //the form has client validation, load it and start it
                    trace("we should load: " + cvArray[1]);
                    trace("beforeloadjs");
                    mainForm=thisForm;
                    loadJS(cvArray[1],"global");
                }
            } else {
                trace("form without id");
            }
            irwSetupClientSideValidation(thisForm);
        }
    } catch (e) {
        trace("Exception setting up validation: " + e);
        dev_domready=e;
    }
});

//Try initialize form again when document is created and all images are fetched
Event.observe(window, "load", function(){
    trace(":window loaded, forms=" + document.forms.length);
    for (var i=0;i<document.forms.length;i++) {
        irwSetupClientSideValidation(document.forms[i]);
    }
});

// Initialize client side validation
function irwSetupClientSideValidation(thisForm) {
    var traceRow = "";
    var isValidationInitiated = false;
    try {
        isValidationInitiated = eval(thisForm.name + 'ValidationInitiated;');
    } catch (e) {
        // Not a client side validation form
        return;
    }
    if (isValidationInitiated) {
        // Validation already done!
        return;
    }
    try {
        eval(thisForm.name + '_setupValidation();');
        traceRow += "client side validation!";
    } catch (e) {
        traceRow += "failed client side validation: " + e;
    }
    if (traceRow.length > 0) {
        trace(thisForm.name + ": " + traceRow);
    }
}

//validate wrapper, catch erros and submits the form for server side validation only.
function validateFormWrapper(form){
	trace("validateForm");
	try {
		var formName= form.name;
		return validateForm(form);
	} catch (e) {
		if(dev_mode) {
			dev_validateForm=e;
			return false;
		} else {
				trace("catch validate form",e);
				trace("return true");
				return false;
			return true;
		}
	}
}

//this method returns true if the given form is in a list of form ids.  When your client validation for a form is ready. add the form id to this list
function hasClientValidation(formID) {
	//trace("hejsan");
	var hasClientValidationStatus = new Array();
	hasClientValidationStatus[0]=false;
	trace("check if the form has validation framework");
	trace("the id we want to check is:"+formID);
	//comma separated list of which form ID's that has client framework. Each form that has validation framework should be in the list and with the name of the actual javascript file at the same position, divided by an pipe ( FORMID | JAVASCRIPTFILE )
	var readyForms="createUser|createUser";
	readyForms.split(",").each(function(item){
		trace("checking formid "+item.split("|")[0]);
		if(item.split("|")[0]==formID) {
			trace("the form was found, returning");
			hasClientValidationStatus[0] = true;
			trace("the name of the javascript file for the form is: " +  item.split("|")[1]);
			hasClientValidationStatus[1] = item.split("|")[1];		
		}
	});
	return hasClientValidationStatus;
}

//translation bundle
var TranslationBundle = Class.create({
  initialize: function(bundleArray) {
	trace("init TranslationBundle");
	this.bundle = bundleArray;
  },
  get: function(key) {
	trace("TranslationBundle get");
	var keyValue="not found";
	try {
		keyValue = eval("this.bundle[\""+key+"\"]");
	} catch(e) {
	}
	return  keyValue;
  }
});

//load external javascript file
function loadJS(name,mode) {
	trace("loading js");
	try {
		var msString="/ms/js/forms/"
		if(mode!="global") {
			trace("get locale");
			//get the local css, it has the locale in the src
			var locale = $$("#localCSS")[0].readAttribute("href").substring(4,9);
			msString = "/ms/"+locale+"/js/forms/";
			trace(msString);
		}
		var formFunctions = new Element("script", {type: "text/javascript", language: "Javascript", src: msString+name+".js"});
		$$("head")[0].appendChild(formFunctions);
	} catch (e) {
		dev_loadJS=e;
	}
}

/************************************************************************************/

var irwPreventFieldValidation = false;

var irwTraceStr ="";
function irwTrace(str) {
    irwTraceStr=irwTraceStr+'<br>'+str;
}

// Method to setup client side form validation. Called from the Jsp-pages tag IrwJavascriptValidatorTag.
function irwSetupForm(formName, errorheadline) {
    //irwTrace("irwSetupForm " + formName);
    var form = document.forms[formName];
    if (!form) {
        irwTrace("Could not find form with the name='" + formName + "'!");
        return;
    }

    if (errorheadline && errorheadline.length > 0) {
        var formErrorsDiv = irwCreateFormErrorsDiv(form, errorheadline);
        Element.insert(form, {'before': formErrorsDiv});
    }

	// Prevent field validation when a submit button is pressed down in the form
	var node_list = Form.getInputs(form, 'submit');
	for (var i = 0; i < node_list.length; i++) {
    	var node = node_list[i];
		Event.observe(node, 'mousedown', function(event) {
			//irwTrace("submit button pressed down");
			irwPreventFieldValidation = true;
		});
	}

    irwTrace("observe submit " + formName);
    Event.observe(form, 'submit', function(event) {
        var formValid = true;
        try {
            var form = Event.element(event);
            var funcName = form.name + '_validateForm' + '(formName);';
            irwTrace("submit " + funcName);
            formValid = eval(funcName);
        } catch (e) {
            irwTrace("Error validation form at submit " + funcName + ": " + e);
        }
        if (!formValid) event.stop();
    });
}

// Setup field validation listeners and the rules error management.
function irwSetupRules(ruleArray) {
    //irwTrace("irwSetupRules");
    var fieldIdOld;
    for (var i=0; i<ruleArray.length; i += 3) {
        var fieldId = ruleArray[i];
        var rule = ruleArray[i+1];
        var errorText = ruleArray[i+2];
        if (fieldId != fieldIdOld) {
            irwSetupFieldValidation(fieldId);
            fieldIdOld = fieldId;
        }
        irwSetupRule(fieldId, rule, errorText);
    }
}

// Setup field validation listeners.
function irwSetupFieldValidation(fieldId) {
    //irwTrace("irwSetupFieldValidation " + fieldId);
    // get input field element
    var field = $(fieldId);
    if (!field) {
        irwTrace("Could not find element for field id='" + fieldId + "'!");
        return;
    }

    // When field is focused, make sure the field will be validated on blur
    Event.observe(field, 'focus', function(event) {
        irwPreventFieldValidation = false;
    });

    // observe
    if (field.type && ("radio" == field.type || "checkbox" == field.type)) {
        // Handle radio buttons
        irwTrace("observe " + field.type + " " + fieldId);
        var elements = field.form.getInputs(field.type, field.name);
        for (var i=0; i<elements.length; i++) {
            var elem = elements[i];
            irwTrace("observe " + elem.type + " " + i);
            Event.observe(elem, 'click', irwDoFieldValidation);
            if (i > 0) {
                Event.observe(elem, 'blur', irwDoFieldValidation);
            }
        }
    }
    else if (field.tagName && "SELECT" == field.tagName) {
        // Handle combobox, select
        irwTrace("observe SELECT " + fieldId);
        Event.observe(field, 'change', irwDoFieldValidation);
    }
    irwTrace("observe blur " + fieldId);
    Event.observe(field, 'blur', irwDoFieldValidation);
}

// Perform the actual field by field validation
function irwDoFieldValidation(event) {
    var field = Event.element(event);
    var fieldId = field.id;
    var funcPrefix = irwGetUnIndexedId(fieldId);
    if (irwPreventFieldValidation) {
        //irwTrace("validation stopped " + fieldId);
        return;
    }
    try {
        // Call validation rule
        var validateFuncName = funcPrefix + "Validate(fieldId);";
        irwTrace(validateFuncName);
        //irwTrace("validate " + fieldId + " " + event);
        var ruleResults = eval(validateFuncName);
    } catch (e) {
        trace("Error validation field " + fieldId + ": " + e);
    }
    //irwTrace("validation " + fieldId + " done!");
}

// Setup field validation rule error management.
function irwSetupRule(fieldId, rule, errorText) {
    //irwTrace("irwSetupRule " + fieldId + ", " + rule + ", " + errorText);

    // get input field element
    var field = $(fieldId);
    if (!field) {
        irwTrace("Could not find form field for field id='" + fieldId + "'!");
        return;
    }

    // Setup error div
    var formFieldDiv = irwGetParentFormField(field);
    if (!formFieldDiv) {
        irwTrace("Could not find form field div for field id='" + fieldId + "'!");
        return;
    }

    var lastElem = irwGetLastRowElem(formFieldDiv);
    if (!lastElem) {
        irwTrace("Could not find last element on row for field id='" + fieldId + "'!");
        return;
    }
    var fieldErrorDiv = irwCreateFieldErrorDiv(fieldId, rule, errorText);
    if (!fieldErrorDiv) {
        irwTrace("Could not create field error element for field id='" + fieldId + "'!");
        return;
    }
    
    var nextElem = lastElem.next();
    while (nextElem && nextElem.hasClassName("clientErrorText")) {
    	lastElem = nextElem;
    	nextElem = lastElem.next();
    }
	Element.insert(lastElem, {'after': fieldErrorDiv});

    var formErrorsDiv = $(field.form.name + "FormErrors");
    if (formErrorsDiv) {
        var formErrorDiv = irwCreateFormErrorDiv(fieldId, rule, errorText);
        if (fieldErrorDiv) formErrorsDiv.appendChild( formErrorDiv );
    }
}

// Call the correct field validation function and update the field formatting and error message visibility.
// Returns a Hash<String,boolean> with rule name as key and the rule result as value.
function irwPerformFieldValidation(fieldId, params, rules) {
    //irwTrace("irwPerformFieldValidation " + fieldId);
    var ruleResults=new Hash();
    try {
        for (var i=0; i<rules.length; i++) {
            var rule = rules[i];
            var field = $(fieldId);
            var validateRuleName = 'validate' + irwFirstCharUpper(rule) + 'Field(field,params);';
            var ruleValid = true;
            try {
                // Call validation rule in irwValidationRules.js
                ruleValid = eval(validateRuleName);
            } catch (e) {
                irwTrace("Field validation function '" + validateRuleName + "' failed: " + e);
            }
            ruleResults.set(rule, ruleValid);
        }
    } catch (e) {
        irwTrace("Field validation of '" + fieldId + "' failed: " + e);
    }

    return irwUpdateFieldValidation(fieldId,ruleResults);
}

// Update the field formatting and error message visibility.
// Returns a Hash<String,boolean> with rule name as key and the rule result as value.
function irwUpdateFieldValidation(fieldId, ruleResults) {
    //irwTrace("irwUpdateFieldValidation " + fieldId);
    // Update the validation result
    var errorPrefix = irwGetUnIndexedId(fieldId);
    var isValid = true;
    try {
        ruleResults.each (
            function(pair) {
                var rule = pair.key;
                var ruleValid = pair.value;
                isValid = isValid && ruleValid;
                var fieldErrorDiv = $(irwGetFieldErrorId(errorPrefix,rule));
                if (fieldErrorDiv) {
                    if (ruleValid) {
                        fieldErrorDiv.hide();
                    }
                    else {
                        fieldErrorDiv.show();
                    }
                }
                else {
                    //irwTrace("Could not find error div '" + irwGetFieldErrorId(errorPrefix,rule) + "'");
                }
                var formErrorDiv = $(irwGetFormErrorId(errorPrefix,rule));
                if (formErrorDiv) {
                    if (ruleValid) {
                        if (!formErrorDiv.hasClassName("clientErrorTextCorrected")) {
                            formErrorDiv.addClassName("clientErrorTextCorrected");
                        }
                    }
                    else {
                        if (formErrorDiv.hasClassName("clientErrorTextCorrected")) {
                            formErrorDiv.removeClassName("clientErrorTextCorrected");
                        }
                    }
                }
                else {
                    //irwTrace("Could not find FORM error div '" + irwGetFormErrorId(errorPrefix,rule) + "'");
                }
            }
        )
        var field = $(fieldId);
        if (field) {
            if (isValid) {
                field.removeClassName("if-field-input-error");
                field.addClassName("if-field-input");
            } else {
                field.removeClassName("if-field-input");
                field.addClassName("if-field-input-error");
            }
        }
        else {
            irwTrace("Could not find form field for field id='" + fieldId + "'!");
        }
    } catch (e) {
        irwTrace("Update of field validation '" + fieldId + "' failed: " + e);
    }
    //irwTrace("irwUpdateFieldValidation " + fieldId + "=" + isValid);
    return ruleResults;
}

// Update the field formatting and error message visibility at form validation (submit).
// Returns the first input/select field failing validation in order to focus on the correct field.
function irwPerformFormValidation(fieldId, fieldToFocus) {
    //irwTrace("irwPerformFormValidation " + fieldId + " " + fieldToFocus);
    var fieldValid = true;
    try {
        var field = $(fieldId);
        if (!field) {
            irwTrace("Could not find field with field id='" + fieldId + "'!");
            return fieldToFocus;
        }

        // Call the field validation rule
        var ruleResults = eval(fieldId + 'Validate(fieldId);');

        if (!ruleResults) {
            irwTrace("Could not perform client validation function for field id='" + fieldId + "'!");
            return fieldToFocus;
        }
        ruleResults.each (
            function(pair) {
                var rule = pair.key;
                var ruleValid = pair.value;
                fieldValid = fieldValid && ruleValid;
                var formRuleErrorDiv = $(irwGetFormErrorId(fieldId, rule));
                if (formRuleErrorDiv) {
                    if (ruleValid) {
                    	formRuleErrorDiv.hide();
                    }
                    else {
                    	formRuleErrorDiv.show();
                    }
                }
            }
        )
        if (!fieldToFocus && !fieldValid) {
            // first invalid field
            fieldToFocus = field;
        }
    } catch (e) {
        irwTrace('Client validation function call failed: ' + e);
        return fieldToFocus;
    }
    //irwTrace("irwPerformFormValidation " + fieldId + "=" + fieldValid);
    return fieldToFocus;
}

// Update form validation errors visibility
function irwUpdateFormValidationResult(formName, fieldToFocus) {
    var formValid = !fieldToFocus;
    try {
        var formErrors = $(formName + "FormErrors");
        if (formErrors) {
            formErrors.setStyle(formValid? "display:none": "display:block");
            if (formErrors)
                if (!formValid && !irwElementInViewport(formErrors)) Element.scrollTo(formErrors);
        }

        var formErrorsServer = $(formName + "FormErrorsServer");
        if (formErrorsServer) {
       		formErrorsServer.hide();
        }

        if (fieldToFocus) fieldToFocus.focus();
    } catch (e) {
        irwTrace('Failed updating form ' + formName + ' validation result: ' + e);
    }
    return formValid;
}

// When an error div should be inserted below an input field we need to find the parent "form field" div.
// Every??? input field is wrapped in av div with class "formField".
function irwGetParentFormField(field) {
    var parentFormField = field.up();
    if (parentFormField.tagName == "FORM") return field;
    while (parentFormField && parentFormField.hasClassName && !parentFormField.hasClassName("formField")){
        if (parentFormField.up().tagName == "FORM") break;
        parentFormField = parentFormField.up();
    }
    return parentFormField;
}

// Create an error div for each field validation rule performed field by field.
// Will be turned on and off according to validation result.
// Returns the created element
function irwCreateFieldErrorDiv(fieldId, rule, errorText) {
    return new Element('div', {'style':'display:none;','class':'clientErrorText','id': irwGetFieldErrorId(fieldId,rule)}).update(errorText);
}

// Create an error div for each field validation rule performed at form submit.
// Will be turned on and off according to validation result.
// Returns the created element
function irwCreateFormErrorDiv(fieldId, rule, errorText) {
    return new Element('div', {'style':'display:none;','class':'clientErrorText','id': irwGetFormErrorId(fieldId, rule)}).update(errorText);
}

// Create an error div acting as a container for field errors performed at form submit.
// Returns the created element
function irwCreateFormErrorsDiv(form, errorheadline) {
    var errorDiv = new Element('div', {'style':'display:none;','class':'ErrorText','id': form.name + 'FormErrors'});
    var h2 = new Element('h2', {'escapeXml':'false'}).update(errorheadline);
    errorDiv.appendChild(h2);
    return errorDiv;
}

// ------- Utility functions ------------

// Find the last input element on the same row (same Y position)
function irwGetLastRowElem(parentDiv) {
    var parentY = irwGetElementY(parentDiv);
    var elemList = parentDiv.nextSiblings();
    var last = parentDiv;
    if (!elemList) {
        return last;
    }
    for (var i=0; i<elemList.length; i++) {
        var formFieldY = irwGetElementY(elemList[i]);
        var diffY = Math.abs(parentY - formFieldY);
        // Compensate for diffrences in browsers opinion of heights
        if (diffY > 3) {
            break;
        }
        last = elemList[i];
    }
    return last;
}

// Find a elements Y position
function irwGetElementY( element ) {
    return element.cumulativeOffset()[1];
}

// Returns the id of the field error element
function irwGetFieldErrorId(fieldId, rule) {
    return fieldId + "_" + rule + "_FieldError";
}

// Returns the id of the form error element
function irwGetFormErrorId(fieldId, rule) {
    return fieldId + "_" + rule + "_FormError";
}

function irwFirstCharUpper(str) {
    if (str) return str.substring(0,1).toUpperCase() + str.substring(1);
    return "";
}

// Returns true if element is visible in the viewport otherwise false
function irwElementInViewport(el) {
	var inViewPort = false;
	try {
		var top = el.offsetTop;
		var left = el.offsetLeft;
		var width = el.offsetWidth;
		var height = el.offsetHeight;
		while(el.offsetParent) {
			el = el.offsetParent;
			top += el.offsetTop;
			left += el.offsetLeft;
		}
		inViewPort = (top >= window.pageYOffset &&
	              left >= window.pageXOffset &&
	              (top + height) <= (window.pageYOffset + window.innerHeight) &&
	              (left + width) <= (window.pageXOffset + window.innerWidth)  );
	} catch (e) {
        irwTrace('Failed check if in viewport ' + el.name + ' :' + e);
	}
	return inViewPort;
}

// Returns the fields id without the index suffix for radio and checkbuttons
function irwGetUnIndexedId(fieldId) {
    var unIndexedId = fieldId;
    var field = $(fieldId);
    if (field && unIndexedId && field.type && ("radio" == field.type || "checkbox" == field.type)) {
        var pos = unIndexedId.lastIndexOf("_-");
        if (pos > 0) {
            unIndexedId = unIndexedId.substring(0,pos);
            irwTrace("unIndexedId = " + unIndexedId);
        }
    }
    return unIndexedId;
}