/* Trim method for string */
String.prototype.trim = function() {
	return this.replace(/^\s+|\s+$/g, ""); 
};

/* Wrapper for use with prototype event handling
 * Example of checking a field with an id of 'login' when losing it's focus:
 * Event.observe($('login'), 'blur', checkFieldByEvent.bindAsEventListener());
 */
function checkFieldByEvent(e) {
    return checkField(Event.element(e));
}

function checkField(element)
{
    /* Look for validation data */
    var alt = element.getAttribute('alt')
    if((alt == null) || (alt == undefined) || (alt == '')) {
        return true;
    }
    
    /* Try to unserialize validation data */
    /* Exception should be handled by the caller */
    eval("var responseObj = " + alt); 
    
    /* Trim whitespace */
    element.value = element.value.trim();
    var elementError = false;
    var errorMessage = "";
    
    /* Look for required field and required field error message */
    var required = false;
    if(responseObj['required'] != undefined) {
        required = responseObj['required'];
    }
    if(required) {
        var requiredMessage = 'Required field';
        if(responseObj['required_message'] != undefined) {
            requiredMessage = responseObj['required_message'];
        }
        
        if(element.value.length == 0) {
            elementError = true;
            errorMessage = requiredMessage;
        }
    }
    
    /* Look for validators */
    if((!elementError) && (element.value.length > 0)) {
        for(var vCounter=0; vCounter<responseObj['validators'].length; vCounter++) {
            if(responseObj['validators'][vCounter]['class'] != undefined) {
                var className = responseObj['validators'][vCounter]['class'];
                /* try to create a validator object */
                /* Exception should be handled by the caller */
                try {
                    eval('var validator = new '+className+'()');
                } catch(e) {
                    break;
                }
                
                /* Attache a standard initialization method */
                validator.initialize=function(parameters) {
                    try {
                        for(var parameter in parameters) {
                            this[parameter] = parameters[parameter];
                        }
                        this['field_id'] = element.getAttribute('id');
                    } catch(e) {}
                }
                    /* Initialize parameters */
                validator.initialize(responseObj['validators'][vCounter]['parameters']);
                
                /* Validate */
                errorMessage = validator.execute(element.value);
                if(errorMessage) {
                    elementError = true;
                    break;
                }
            }
        }
    }
    
    setAlert(element, elementError != null, (errorMessage ? errorMessage : null));
    return !elementError;
}

/* Show/Hide alerts */
function setAlert(element, visible, errorMessage) {
    var alertImg = document.getElementById(element.id+"Error");
    if(visible) {
        try {
            my_field_error(element, errorMessage);
        } catch (e) {
            alertImg.alt = errorMessage;
            alertImg.title = errorMessage;
            alertImg.style.display = 'block';
        }
    } else {
        try {
            my_field_error(element, null);
        } catch (e) {
            alertImg.style.display = 'none';
        }
    }
}

function submitByEvent(e) {
    if(validate(Event.element(e).form) == true) {
        Event.element(e).form.submit();
    }
}

function validate(form) {
    var valid = true;

    // get values from tinyMCE
    try {
        tinyMCE.triggerSave();
    } catch (e) {}

    /* Iterate through the form fields */
    var elements = form.elements;
    for(var eCounter = 0; eCounter < elements.length; eCounter++) {
        try {
            valid = valid && checkField(elements[eCounter]);
        } catch (e) {}
    }
    
    return valid;
}

/* Validators */

/**
 * sfStringValidator allows you to apply string-related constraints to a
 * parameter.
 *
 * Optional parameters:
 *
 * # insensitive  - [false]              - Whether or not the value check
 *                                                against the array of values is
 *                                                case-insensitive. Note:
 *                                                When using this option, values
 *                                                in the values array must be
 *                                                entered in lower-case.
 * # max          - [none]               - Maximum string length.
 * # max_error    - [Input is too long]  - An error message to use when
 *                                                input is too long.
 * # min          - [none]               - Minimum string length.
 * # min_error    - [Input is too short] - An error message to use when
 *                                                input is too short.
 * # values       - [none]               - An array of values the input
 *                                                is allowed to match.
 * # values_error - [Invalid selection]  - An error message to use when
 *                                                input does not match a value
 *                                                listed in the values array.
 */

/* Constructor */
var sfStringValidator=function() {
    this.insensitive = false;
    this.max = null;
    this.max_error = "Input is too long";
    this.min = null;
    this.min_error = "Input is too short";
    this.values = null;
    this.values_error = "Invalid selection";
}

/* Validation method */
sfStringValidator.prototype.execute=function(value) {
    if ((this.min != null) && (value.length < this.min)) {
        // too short
        return this.min_error;
    }

    if ((this.max != null) && (value.length > this.max)) {
        // too long
        return this.max_error;
    }
    
    if(this.values != null) {
        for(i = 0; i < this.values.length; i++) {
            if((this.insensitive?(this.values[i].toLowerCase()):(this.values[i])) == (this.insensitive?(value.toLowerCase()):(value))) {
                return false;
            }
        }
        
        return this.values_error;
    }

    return false;
}

/**
 * sfNumberValidator verifies a parameter is a number and allows you to apply
 * size constraints.
 *
 * Optional parameters:
 *
 * # max        - [none]                  - Maximum number size.
 * # max_error  - [Input is too large]    - An error message to use when
 *                                                 input is too large.
 * # min        - [none]                  - Minimum number size.
 * # min_error  - [Input is too small]    - An error message to use when
 *                                                 input is too small.
 * # nan_error  - [Input is not a number] - Default error message when
 *                                                 input is not a number.
 * # type       - [Any]                   - Type of number (Any, Float).
 * # type_error - [Wrong input] - An error message to use when
 *                                                 input is not a number.
 */

/* Constructor */
var sfNumberValidator=function() {
    this.max = null;
    this.max_error = "Input is too large";
    this.min = null;
    this.min_error = "Input is too small";
    this.nan_error = "Input is not a number";
    this.type = "any"; // 'any', 'decimal', 'float', 'int', 'integer'
    this.type_error = "Wrong input";
}

/* Validation method */
sfNumberValidator.prototype.execute=function(value) {
    if(isNaN(value)) {
        return this.nan_error;
    }
    
    iValue = parseInt(value, 10);
    fValue = parseFloat(value);
    
    if((this.type == 'int') || (this.type == 'integer')) {
        if(fValue != iValue) {
            return this.type_error;
        }
        pValue = iValue;
    } else {
        pValue = fValue;
    }
    
    if((this.min != null) && (pValue < this.min)) {
        return this.min_error;
    }
    
    if((this.max != null) && (pValue > this.max)) {
        return this.max_error;
    }
    
    return false;
}

/**
 * sfRegexValidator allows you to match a value against a regular expression
 * pattern.
 *
 * Required parameters:
 *
 * # pattern - [none] - A PCRE, preg_match() style regular expression
 *                             pattern.
 *
 * Optional parameters:
 *
 * # match       - [true]          - Indicates that the pattern must be
 *                                          matched or must not match.
 * # match_error - [Invalid input] - An error message to use when the
 *                                          input does not meet the regex
 *                                          specifications.
 */

/* Constructor */
var sfRegexValidator=function() {
    this.match = true;
    this.match_error = "Invalid input";
    this.pattern = null;
}

/* Validation method */
sfRegexValidator.prototype.execute=function(value) {
    if(this.pattern != null) {
        match = Boolean(this.match);
        pos = 0;
        unescaped = "";
        while(pos < this.pattern.length) {
            c = this.pattern.charAt(pos);
            if (c == "\\") {
                pos++;
            }
            try {
                unescaped += this.pattern.charAt(pos);
            } catch(e) {}
            pos++;
        }

        try {        
            eval("regExp = "+unescaped);
            value = String(value);
            if((value.match(regExp) && match) || (!value.match(regExp) && !match)) {
                return false;
            } else {
                return this.match_error;
            }
        } catch(e) {
            return false;
        }
    } else {
        return false;
    }
}

/**
 * sfEmailValidator verifies a parameter contains a value that qualifies as an
 * email address.
 * 
 * Optional parameters:
 *
 * # email_error - [Invalid input] - An error message to use when the
 *                                          input is not an email address
 */

/* Constructor */
var sfEmailValidator=function() {
    this.email_error = "Invalid input";
}

sfEmailValidator.prototype.execute=function(value) {
    regExp  = /^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})$/;
    if (regExp.test(value)) {
        return false;
    } else {
        return this.email_error;
    }
}


/**
 * sfCompareValidator checks the equality of two different request parameters.
 *
 * Required parameters:
 *     check:          field2
 * 
 * Optional parameters:
 * # compare_error - [The values you entered do not match. Please try again.] - 
 *                           An error message to use when the fields do not match
 */

/* Constructor */
var sfCompareValidator=function() {
    this.check = null;
    this.compare_error = "The values you entered do not match. Please try again";
}

sfCompareValidator.prototype.execute=function(value) {
    if(this.check != null) {
        check_field = document.getElementById(this.check);
        if(check_field != null) {
            check_value = check_field.value;
            if(check_value != value) {
                return this.compare_error;
            }
        }
    }
    
    return false;
}
