/**
 * Form validation library.
 *
 * @author Richard J. Turner <rjt@zygous.co.uk>
 * @copyright 2008 Richard J. Turner. All rights reserved.
 */

// Set-up name-spaces
var Zygous = Zygous || {};
Zygous.Validate      = {};
Zygous.FormValidator = {};

/**
 * Email address validator constructor.
 */
Zygous.Validate.EmailAddress = function () {};

/**
 * Is the specified email address valid?
 * This function actually just does a simple check using a regular expression.
 * There are far more checks that need to be done, but we can't easily do them
 * using JavaScript (e.g. validate MX records).
 * 
 * @param string sEmailAddress The email address to validate.
 * @return bool Whether the email address is valid.
 */
Zygous.Validate.EmailAddress.prototype.isValid = function (sEmailAddress) {
    $bValid = /^((\"[^\"\f\n\r\t\v\b]+\")|([\w\!\#\$\%\&\'\*\+\-\~\/\^\`\|\{\}]+(\.[\w\!\#\$\%\&\'\*\+\-\~\/\^\`\|\{\}]+)*))@((\[(((25[0-5])|(2[0-4][0-9])|([0-1]?[0-9]?[0-9]))\.((25[0-5])|(2[0-4][0-9])|([0-1]?[0-9]?[0-9]))\.((25[0-5])|(2[0-4][0-9])|([0-1]?[0-9]?[0-9]))\.((25[0-5])|(2[0-4][0-9])|([0-1]?[0-9]?[0-9])))\])|(((25[0-5])|(2[0-4][0-9])|([0-1]?[0-9]?[0-9]))\.((25[0-5])|(2[0-4][0-9])|([0-1]?[0-9]?[0-9]))\.((25[0-5])|(2[0-4][0-9])|([0-1]?[0-9]?[0-9]))\.((25[0-5])|(2[0-4][0-9])|([0-1]?[0-9]?[0-9])))|((([A-Za-z0-9\-])+\.)+[A-Za-z\-]+))$/.test(sEmailAddress);
    
    if (!$bValid) {
        this.error = "Please enter a properly formatted email address";
    }
    
    return $bValid;
};

/**
 * Constructor for the Validator.
 * @param string sFormId The ID of the form element to validate
 * @param array aValidators An array to configure the validator. 
 */
Zygous.FormValidator.Validator = function (sFormId, aValidators) {
    var oForm = YAHOO.util.Dom.get(sFormId);
    if (undefined == oForm) {
        throw "'" + sFormId + "' is not a DOM element ID.";
    }
    
    this.form       = oForm;
    this.validators = aValidators;
    
    this.listenForFormSubmission();
};

Zygous.FormValidator.Validator.prototype.listenForFormSubmission = function () {
    YAHOO.util.Event.addListener(
        this.form,
        'submit',
        this.interceptSubmission,
        this,
        true
    );
};

Zygous.FormValidator.Validator.prototype.interceptSubmission = function (oEvent) {
    this.resetErrors();
    if (!this.isValid()) {
        YAHOO.util.Event.stopEvent(oEvent);
        this.handleErrors();
        return;
    }
};

Zygous.FormValidator.Validator.prototype.isValid = function () {
    var sValue  = null;
    var aErrors = {length: 0};
    
    for (var sField in this.validators) {
        sValue = this.form.elements[sField].value;
        
        // Deal with fields that have no value at all.
        if (undefined == sValue && this.validators[sField].presence == 'required') {
            aErrors[sField] = aErrors[sField] || [];
            aErrors[sField].push("A value is required for field '" + sField + "'");
            aErrors.length++;
            continue;
        }
        
        // In a form, all values a strings, so we can safely trim them
        sValue = YAHOO.lang.trim(sValue);
        
        // Deal with fields that have an empty value, e.g. an empty string ''.
        if ('' === sValue && this.validators[sField].allowEmpty !== true) {
            aErrors[sField] = aErrors[sField] || [];
            aErrors[sField].push("The value for field '" + sField + "' must not be empty.");
            aErrors.length++;
            continue;
        }
        
        // Now apply the real test
        if (undefined !== this.validators[sField].validator &&
            !this.validators[sField].validator.isValid(sValue)) {
            aErrors[sField] = aErrors[sField] || [];
            aErrors[sField].push(this.validators[sField].validator.error);
            aErrors.length++;
        }
    }
    
    if (aErrors.length < 1) {
        return true;
    }
    
    this.errors = aErrors;
    return false;
};

Zygous.FormValidator.Validator.prototype.handleError = function (sField, sError) {
    // Override me.
    YAHOO.log(sError);
}

Zygous.FormValidator.Validator.prototype.resetError = function (sField, sError) {
    // Override me.
}

Zygous.FormValidator.Validator.prototype.handleErrors = function () {
    for (var sField in this.errors) {
        for (var i = 0, j = this.errors[sField].length; i < j; i++) {
            this.handleError(sField, this.errors[sField][i]);
        }
    }
};

Zygous.FormValidator.Validator.prototype.resetErrors = function () {
    for (var sField in this.errors) {
        this.resetError(sField);
    }
    this.errors = {};
};