/* © Zooven, Inc 2006-2007 - ALL RIGHTS RESERVED */

/**
 * FieldValidator - a base class for javascript classes that can be used to validate a field.
 */
zooven.validation.FieldValidator = Class.create();
zooven.validation.FieldValidator.prototype = {
/**
 * construct a FieldValidator.
 * field        : the DOM object for the field to validate
 * message      : the pattern for the message to return when the field is invalid (@value@ will be replaced with the
 *                invalid value)
 */
    initialize : function(field, message) {
        this.field = field;
        this.message = message;
    },

/**
 * isValid - this method should return true if the field is valid, false otherwise.
 *
 * this method always returns true - subclasses should override this to implement validation logic
 */
    isValid : function() {
        return true;
    },

/**
 * validate - check the field for a valid value, return null if valid, or the error message if invalid.
 */
    validate : function() {
        return this.isValid() ?
               null :
               this.message.replace(/\@value\@/g, this.field.value);
    }
};

/**
 * RequiredFieldValidator - an implementation of FieldValidator that checks whether the field has been filled out.
 */
zooven.validation.RequiredFieldValidator = Class.create();
zooven.validation.RequiredFieldValidator.prototype = Object.extend(new zooven.validation.FieldValidator(), {
    initialize : function(field, message) {
        zooven.validation.FieldValidator.prototype.initialize.call(this,
                field,
                message ? message : '* required');
    },

    isValid : function() {
        return this.field && this.field.value && this.field.value != "";
    }
});

/**
 * RequireOneFieldValidator - an implementation of FieldValidator that requires at least one of the given fields.
 */
zooven.validation.RequireOneFieldValidator = Class.create();
zooven.validation.RequireOneFieldValidator.prototype = Object.extend(new zooven.validation.FieldValidator(), {
    initialize : function(
            fields,
            message) {
        zooven.validation.FieldValidator.prototype.initialize.call(this, fields[0], message);
        this.fields = fields;
    },

    isValid : function() {
        var valid = false;
        this.fields.each(function(field) {
            if (field && field.value && field.value != "") {
                valid = true;
            }
        });
        return valid;
    }
});

/**
 * RegexFieldValidator - an implementation of FieldValidator that compares the field against the given regex.
 */
zooven.validation.RegexFieldValidator = Class.create();
zooven.validation.RegexFieldValidator.prototype = Object.extend(new zooven.validation.FieldValidator(), {
    initialize : function(field, message, regex) {
        zooven.validation.FieldValidator.prototype.initialize.call(this, field, message);
        this.regex = regex;
    },

    isValid : function() {
        return this.field.value == "" ||
               this.field.value == this.field.value.match(this.regex);
    }
});

/**
 * EmailFieldValidator - an implementation of FieldValidator that checks whethern the field is a valid email address.
 */
zooven.validation.EmailFieldValidator = Class.create();
zooven.validation.EmailFieldValidator.prototype = Object.extend(new zooven.validation.RegexFieldValidator(), {
    initialize : function(field, message) {
        zooven.validation.RegexFieldValidator.prototype.initialize.call(this,
                field,
                message ? message : '@value@ is not a valid email.',
                /[a-zA-Z0-9_\.]+\@([a-zA-Z0-9_]+\.)+[a-zA-Z0-9_]+/g);
    }
});

/**
 * FieldValidatorChain - a FieldValidator that tries each of a chain of validators, in turn, and returns the error
 *                       message of the first failure, or null on success.
 */
zooven.validation.FieldValidatorChain = Class.create();
zooven.validation.FieldValidatorChain.prototype = {
    initialize : function(
            fieldValidators,
            messageField) {
        // set the member variable for the field validators
        this.fieldValidators = fieldValidators;
        // if there was an explicit message field, set that - otherwise set it to the field of the first validator
        this.field = messageField ?
                     messageField :
                     this.fieldValidators[0].field;
    },

    isValid : function() {
        var valid = true;
        this.fieldValidators.each(function(fieldValidator) {
            valid = valid && fieldValidator.isValid();
        });
        return valid;
    },

    validate : function() {
        // initialize the return value to null
        var retVal = null;

        // validation is a closure on the FieldValidatorChain and the return value.
        var chain = this;
        this.fieldValidators.each(function(fieldValidator) {
            // if there wasn't already a validation error, try this field and set the return value
            retVal = (retVal == null) ?
                     fieldValidator.validate() :
                     retVal;
        });
        return retVal;
    }
}