/* Simple & extensible field validation
 * http://www.rich-waters.com/blog/
 * version: 0.9
 * updated: 12/5/06
 *
 * RegEx's from http://www.regexlib.com
 *
 * Copyright (c) 2006 Rich Waters
 * http://www.opensource.org/licenses/mit-license.php
 *
 */

var Validation = Class.create();
Validation.prototype = {
    initialize: function(form) {
        this.form = document.forms[form];
		// if form is not defined, forget the rest
        if (typeof this.form == 'undefined') {
            return false;
        }
        this.elems = document.getElementsByClassName("validate", form);
        this.configRules = [];
        this.keys = [];

		// Create the default validator objects
        this.registerValidator(new Validator("numeric", /^(\d|-)?(\d|,)*\.?\d*$/, "Vennligst skriv inn et tall (bare tall 0-9)"));
        this.registerValidator(new Validator("date",
                /(((0[13578]|10|12)([-.\/])(0[1-9]|[12][0-9]|3[01])([-.\/])(\d{4}))|((0[469]|11)([-.\/])([0][1-9]|[12][0-9]|30)([-.\/])(\d{4}))|((2)([-.\/])(0[1-9]|1[0-9]|2[0-8])([-.\/])(\d{4}))|((2)(\.|-|\/)(29)([-.\/])([02468][048]00))|((2)([-.\/])(29)([-.\/])([13579][26]00))|((2)([-.\/])(29)([-.\/])([0-9][0-9][0][48]))|((2)([-.\/])(29)([-.\/])([0-9][0-9][2468][048]))|((2)([-.\/])(29)([-.\/])([0-9][0-9][13579][26])))/,
                "Vennligst skriv inn en gyldig dato"));
        this.registerValidator(new Validator("email", /^[a-zA-Z0-9._-]+@([a-zA-Z0-9][a-zA-Z0-9.-]*\.)+[a-zA-Z0-9.-]{2,4}$/, "Vennligst skriv en gyldig email."));
        this.registerValidator(new Validator("authorEmail", /^[a-zA-Z0-9._-]+@([a-zA-Z0-9][a-zA-Z0-9.-]*\.)+[a-zA-Z0-9.-]{2,4}$/, "Vennligst skriv en gyldig email."));
        this.registerValidator(new Validator("phone", /^(\d{8})$/, "Vennligst skriv et gyldig telefonnummer(xxxxxxxx)"));
        this.registerValidator(new Validator("zip", /(^(?!0{5})(\d{5})(?!-?0{4})(-?\d{4})?$)/, "Vennligst skriv inn et gyldig postnummer"));
        this.registerValidator(new Validator("password", /^[a-zA-Z]\w{3,14}$/, "Passord må inneholde bokstaver og tall samt være 3-14 karakterer"));
        this.registerValidator(new Validator("name", /^([a-zA-zøæåØÆÅ\s]{2,32})$/, "Navn må inneholde vanlige bokstaver og være 2-32 karakterer"));
        this.registerValidator(new Validator("content", /^([a-zA-zøæåØÆÅ\s]{3,1000})$/, "Meldingen må inneholde vanlige bokstaver og være 3-1000 karakterer"));
        this.registerValidator(new Validator("message", /^[^<>()&:;#%\/\$]*$/,
                "Feltet kan ikke innholde disse tegnene: < > ( ) & : ; % # / $ og kan ikke inneholde HTML-kode eller lenker til nettsteder"));
        this.registerValidator(new RequiredValidator());

        for (var i = 0; i < this.elems.length; i++) {
            Event.observe(this.elems[i], "blur", this.attach.bindAsEventListener(this));
        }

		// Add event listeners to the onsubmit and onreset events
        Event.observe(this.form, "submit", this.validate.bindAsEventListener(this));
        Event.observe(this.form, "reset", this.reset.bindAsEventListener(this));
    },

    /* Quick method to add a Validator object to this Validation object
       * We push the actual object into the array 'configRules'
       * then add the name into keys for easy access
       */
    registerValidator: function(validator) {
        if (typeof this.form == 'undefined') {
            return false;
        }
        this.configRules.push(validator);
        this.keys.push(validator.toString());

    },

    /* Base method that we attach to all onchange events on the fields */
    attach: function(e) {
        var target = Event.element(e);
        var sRules = Element.classNames(target).toArray(); // Grab all the class names from the element

        for (var i = 0; i < sRules.length; i++) { // Loop through the class names
            var key = this.keys.indexOf(sRules[i]);
            if (key != -1) { // See if the class name has a Validator defined
                this.configRules[key].handleValid(target); // It has a validator object, call that Validator's handleVald to do the checking
            }
        }
    },

    /* validate method - gets called onsubmit */
    validate: function(e) {
        Event.stop(e); // Stop submit from occuring
        var target = Event.element(e); // Get ahold of the form trying to be submitted
        var errors = 0;
        var sRules;

        for (var i = 0; i < this.elems.length; i++) { // Loop through the elements Validator is watching
            sRules = Element.classNames(this.elems[i]).toArray(); // Grab all the class names from the element
            for (var k = 0; k < sRules.length; k++) { // Loop through the class names
                var key = this.keys.indexOf(sRules[k]);
                if (key != -1) { // See if the class name has a Validator defined
                    if (!this.configRules[key].isValid(this.elems[i])) { // Check to see if its invalid
                        errors++; // Increment error count
                        this.configRules[key].handleValid(this.elems[i]); // Call that Validators invalid handler
                    }
                }
            }
        }
        if (errors == 0) { // If we didn't get an error, continue the sumbit
            target.submit();
        }
    },

    /* reset method - called when the reset button is clicked (clears any invalid messages displayed) */
    reset: function(e) {
        var sRules;
        for (var i = 0; i < this.elems.length; i++) { // Loop through the elements
            if (this.elems[i].error) {    // if the element has error set
                sRules = Element.classNames(this.elems[i]).toArray(); // grab its class names
                for (var k = 0; k < sRules.length; k++) { // loop through its classes
                    var key = this.keys.indexOf(sRules[k]); // check the class to see if theres a rule (validator object) for it
                    if (key != -1) { // if we found a rule
                        this.configRules[key].clear(this.elems[i]); // call the clear method of that validator
                    }
                }
            }
        }
    }
};

/* Validator
  * base object to inherit validator objects from to handle specific cases of form validation
  * default isValid method expects the object to have been initialized with a regular expression
  * for any other validation override the isValid method with one that returns a boolean value
  * NOTE: make sure to include an empty initialize function in the new method otherwise this one
  * will get called twice, once when you create your object and once when that object extends
  * this one.
  */
var Validator = Class.create();
Validator.prototype = {
    initialize: function(key, reg, msg) {
        this.key = key;
        this.regex = reg;
        this.msg = msg;
    },

    isValid: function(field) {
        if (this.regex != "" && this.regex.test(field.value) || field.value == "") {
            return true;
        } else {
            return false;
        }
    },

    handleValid: function(field) {
        if (this.isValid(field)) {
            this.validHandler(field);
        } else {
            this.invalidHandler(field);
        }
    },

    validHandler: function(field) {
        // Pulled the code out of here so that reset wasn't calling valid handler in case we want some sort of valid response but don't want it to happen on reset
        this.clear(field);
    },

    invalidHandler: function(field) {
        if (!field.error) {

            field.saveBackground = Element.getStyle(field, 'background-color');
            Element.setStyle(field, { backgroundColor: "#FFDBDB" });
            
            if (typeof Effect == 'undefined') {
                new Insertion.After(field, "<br><span id=\"" + field.name + "-invalid\" class=\"invalid\" style=\"color:red;padding-left:10px\">" + this.msg + "</span>");
            } else {
                var invalid = new Insertion.After(field, "<br><span id=\"" + field.name + "-invalid\" class=\"invalid\" style=\"color:red;padding-left:10px;display:none\">" + this.msg + "</span>");
                new Effect.Opacity(invalid.element.nextSibling, {from: 0.0, to: 1.0, beforeSetup: function(effect) {
                    effect.element.show();
                } });
            }
            field.error = true;
        }
    },

    clear: function(field) {
        if (field.error) {
            Element.setStyle(field, { "background-color": field.saveBackground });

            Element.setStyle(field, "");
            var elem = $(field.name + "-invalid");
            
            if (typeof Effect == 'undefined') {
                Element.remove(elem);
            } else {
                new Effect.Fade(elem, {afterFinish: function(effect) {
                    Element.remove(effect.element)
                }});
            }
            field.error = false;
        }
    },             

    toString: function() {
        return this.key;
    }
};


// Create a custom object extending the Validator Class because we don't want to bother with regex for required
var RequiredValidator = Class.create();
RequiredValidator.prototype = Object.extend(new Validator("required", "", "Dette feltet må ha en verdi"), {
    initialize: function() {
    }, // MUST OVERRIDE initialize otherwise the base class one gets called twice!
    // Override isValid with one that checks to see if theres anything in the field
    isValid: function(field) {
        if (!Field.present(field)) {
            return false;
        } else {
            return true;
        }
    }
});

