/**
 * (c)2002-2004 E-Dialog.com
 */


/**
 This class (container class really) has functions for doing special validation.
 */
ValidationUtil = new Object();
ValidationUtil.REGEX_NON_ASCII = new RegExp("[^\\x00-\\x7F]");
ValidationUtil.REGEX_EMAIL     = new RegExp("^([^()<>@,;:\\\\\".\\s\\x00-\\x1F\\x7F\\[\\]]+|\"([^\\\\\"\\x0D]|\\\\.)*\")(\\.([^()<>@,;:\\\\\".\\s\\x00-\\x1F\\x7F\\[\\]]+|\"([^\\\\\"\\x0D]|\\\\.)*\"))*@[^()<>@,;:\\\\\".\\s\\x00-\\x1F\\x7F\\[\\]]+(\\.[^()<>@,;:\\\\\".\\s\\x00-\\x1F\\x7F\\[\\]]+)*\\.([^()<>@,;:\\\\\".\\s\\x00-\\x1F\\x7F\\[\\]]{2,4}|museum)$");
ValidationUtil.REGEX_LTRIM     = new RegExp("^\\s*(.*)");
ValidationUtil.REGEX_RTRIM     = new RegExp("([^\\s]*)\\s*$");
ValidationUtil.REGEX_INTEGER   = new RegExp("^\\d+$");
ValidationUtil.REGEX_NUMERIC   = new RegExp("^\\d+(\\.\\d*)?$");
ValidationUtil.isEmail = function(param) {
    return !ValidationUtil.REGEX_NON_ASCII.test(param) && ValidationUtil.REGEX_EMAIL.test(param);
}
ValidationUtil.isDate = function(param) {
    return (Date.parse(param)) ? true : false;
}
ValidationUtil.isDateYMD = function(year, month, day) {
    return ValidationUtil.isDateMDY(month, day, year);
}
ValidationUtil.isDateMDY = function(month, day, year) { 
    if( ValidationUtil.REGEX_INTEGER.test(month) &&
        ValidationUtil.REGEX_INTEGER.test(day) &&
        ValidationUtil.REGEX_INTEGER.test(year)) {
        var d = new Date(year, --month, day);
        return (d && d.getFullYear()==year && d.getMonth()==month && d.getDate()==day);
    }
    return false;
}
ValidationUtil.isInteger = function(param) {
    return ValidationUtil.REGEX_INTEGER.test(param);
}
ValidationUtil.isNumeric = function(param) {
    return ValidationUtil.REGEX_NUMERIC.test(param);
}
ValidationUtil.hasValue = function(param) {
    if(!param || (typeof param!="string")) return false;
    param = param.replace(ValidationUtil.REGEX_LTRIM, "$1");
    param = param.replace(ValidationUtil.REGEX_RTRIM, "$1");
    return param != "";
}





/**
 * Adds methods from superObj into obj, a way of doing multiple inheritance.... 
 * The javascript 'prototype' thing is messed up.
 */
function setSuperClass(obj, superObj) {
    for(var x in superObj) {
        if(typeof superObj[x]=="function") {
            obj[x] = superObj[x];
        }
    }
}




/**
 * 'SuperClass' for all form beans.
 *
 * The fieldCollection parameter should be a collection (a Map/'Associative Array') 
 * with properties that match field names of the form to be validated.
 *
 * In client-side javascript, a FORM object should be passed through the
 * simplifyClientSideFormData() function to extracting values from fields 
 * appropriately before passing to this function.
 *
 * On the server-side there are functions on FormProcessor to do these mappings.
 */
function BaseFormBean(fieldCollection) {
    // private properties
    var myFieldCollection = fieldCollection;
    var errors = new Array();
    var baseErrorMessage = null;

    // private methods/inner classes
    /** puts together the 'Foo' part of 'getFoo/setFoo' */
    function buildBaseAccessorMethodName(propName) {
        if(!propName || (typeof propName!="string") || !/^[a-zA-Z][a-zA-Z0-9_]+$/.test(propName)) return null;
        return propName.charAt(0).toUpperCase()+propName.substring(1,propName.length);
    }
    /** supports getFoo/setFoo */
    function Accessor(fieldName) {
        var myFieldName = fieldName;
        this.getterMethod = function() {
            return myFieldCollection[myFieldName];
        }
        this.setterMethod = function(param) {
            myFieldCollection[myFieldName] = param;
        }
    }
    // add methods to instances of this object to get field properties. i.e. getFoo()
    for(var fieldName in fieldCollection) {
        var baseAccessorMethodName = buildBaseAccessorMethodName(fieldName);
        if(baseAccessorMethodName!=null) {
            var accessor = new Accessor(fieldName);
            this["get"+baseAccessorMethodName] = accessor.getterMethod;
            this["set"+baseAccessorMethodName] = accessor.setterMethod;
        }
    }

    /**
     * A method to return a property in the field collection by name
     */
    this.get = function(param) {
        var accessorName = buildBaseAccessorMethodName(param);
        if(!accessorName) return null;
        var accessorMethod = this["get"+accessorName];
        return (typeof accessorMethod == "function") ? eval("this.get"+accessorName+"()") : null;
    }
    /**
     * Returns this object's field collection
     */
    this.getFieldCollection = function() {
        return myFieldCollection;
    }

    /**
     * Sub-Classes should over-ride this method.
     */
    this.validate = function() {
        return;
    }

    /**
     * Runs the validate function, and returns true/false if there were errors.
     */
    this.isValid = function() {
        this.clearErrors();
        this.validate();
        return this.getNumErrors()==0;
    }

    /**
     * Clears any errors from the error list
     */
    this.clearErrors = function() {
        errorFields = new Array();
    }
    /**
     * Adds a new error to the error list.
     */
    this.addError = function(fieldName, fieldDescription) {
        var o = new Object();
        o.name = fieldName;
        o.description = fieldDescription;
        errors[errors.length] = o;
    }
    /**
     * Returns the number of errors in the error list
     */
    this.getNumErrors = function() {
        return errors.length;
    }
    /**
     * Returns an array of any errors that occured.
     */
    this.getErrors = function() {
        return errors;
    }
    /**
     * Sets the base error message to a new value.
     */
    this.setBaseErrorMessage = function(newErrorMessage) {
        baseErrorMessage = newErrorMessage;
    }
    /**
     * Gets the base error message for this form bean.
     */
    this.getBaseErrorMessage = function() {
        if(baseErrorMessage != null) {
            return baseErrorMessage;
        } else {
            var result = "The following fields are missing or invalid";
            if(this.get("profanityfiltered") == "true") 
                result += "\n(some fields may have been filtered for profanity)";
            return result+":";
	}
    }

    /**
     * Gets a full error message from this form bean using the base error 
     * message and the individual error fields.
     */
    this.getFullErrorMessage = function(beforeFirstError, betweenErrors, afterLastError) {
        if(typeof beforeFirstError == "undefined") beforeFirstError = " ";
        if(typeof betweenErrors    == "undefined") betweenErrors    = ", ";
        if(typeof afterLastError   == "undefined") afterLastError   = "";

        var fullErrorMessage = this.getBaseErrorMessage();
        fullErrorMessage += beforeFirstError;
        var errors = this.getErrors();
        for(var i=0; errors && i<errors.length; i++) {
            if(i!=0) fullErrorMessage += betweenErrors;
            fullErrorMessage += errors[i].description;
        }
        fullErrorMessage += afterLastError;
        return fullErrorMessage;
    }
}


/**
 * A function, used on a client-side HTML-DOM enabled browser to simplify
 * a FORM object's values so they can be passed into BaseFormBean.
 */
function simplifyClientSideFormData(formObject) {
    if(!formObject || !formObject.elements) return null;
    var result = new Object();
	
    for(var i=0; i<formObject.elements.length; i++) {
        var element = formObject[i];
        var name = element.name;
        if(name) {
            var value = simplifyClientSideElementValue(element);
            if(!result[name])
                result[name] = value;
            else if(value) 
                result[name] = result[name] + "," + value;
        }
    }
    return result;
}

/**
 * A function, called by simplifyCientSideFormData
 */
function simplifyClientSideElementValue(elementObject) {
    if(!elementObject) return null;

    var result = "";
    // handle a single checkbox/radio button
    if((typeof elementObject.type != "undefined") && elementObject.type!=null && (elementObject.type.toLowerCase()=="checkbox" || elementObject.type.toLowerCase()=="radio")) {
        if(elementObject.checked) {
            result = elementObject.value;
        }
    // handle text input fields and textareas
    } else if((typeof elementObject.value != "undefined") && elementObject.value!=null) {
        result = elementObject.value;
    // handle a select box
    } else if(elementObject.options && (typeof elementObject.options.length == "number") && (typeof elementObject.selectedIndex == "number")) {
        // note that this code does not support:   <option>xxx</option>
        // the value must be explicitly declared:  <option value="yyy">xxx</option>
        result = elementObject.options[elementObject.selectedIndex].value;
    }
    return result;
}


/**
 * Client side script called in onSubmit of form tag.
 *
 * The form name attribute should match the form's bean class.
 *
 */
function validateClientSideForm(formObject, formName) {
    if(!formObject) return true;
    if(!formName) formName = formObject.name;
    if(!formName) return true;

    var formData = simplifyClientSideFormData(formObject);
    var formBean = eval("new "+formName+"(formData)");

    if(!formBean.isValid()) {
        var errorMessage = formBean.getFullErrorMessage("\n    ", "\n    ", "");
        alert(errorMessage);
        return false;
    }
    return true;
}


//-----------------------


/**
 * Form validation for signupform
 */
function signupform(fieldCollection) {
	setSuperClass(this, new BaseFormBean(fieldCollection));
	
	/**
	 * This function performs the actual validation.
	 */
	this.validate = function () {
		this.clearErrors();
		
		if(!ValidationUtil.isEmail(this.get("email"))) 
			this.addError("email", "Email Address");
			
		if(this.get("email") != this.get("email2"))
			this.addError("email", "Email addresses must match"); 
		
		if(!ValidationUtil.hasValue(this.get("firstname")))
			this.addError("firstname", "First Name");
			
		if(!ValidationUtil.hasValue(this.get("lastname")))
			this.addError("lastname", "Last Name");
			
		if(!ValidationUtil.hasValue(this.get("country")))
			this.addError("country", "Country");
			
		if(!ValidationUtil.hasValue(this.get("postcode")))
			this.addError("postcode", "Postcode");
			
		if(this.get("postcode") != this.get("postcode2"))
			this.addError("postcode", "Postcodes must match");
			
		if(this.get("country") == "UK")
		{
			if((!ValidationUtil.hasValue(this.get("readership_1a"))) && (!ValidationUtil.hasValue(this.get("readership_1b"))) && (!ValidationUtil.hasValue(this.get("readership_1c"))) && (!ValidationUtil.hasValue(this.get("readership_1d"))) && (!ValidationUtil.hasValue(this.get("readership_1e"))) && (!ValidationUtil.hasValue(this.get("readership_1f"))) && (!ValidationUtil.hasValue(this.get("readership_1g"))) && (!ValidationUtil.hasValue(this.get("readership_1h"))))
				this.addError("readership_1a", "Readership Question");	
		}
		else
		{
			if(!ValidationUtil.hasValue(this.get("readership_2")))
				this.addError("readership_2", "Readership Question");
		}
		
	}

	/**
	 * This method returns a comma-delimited list of fields
	 * that should be profanity-filtered.
	 *
	 * (server-side only)
	 */
	this.getFieldsToRunThroughProfanityFilter = function() {
		return "firstname,country";
	}
	
	/**
	 * This method returns a comma-delimited list of fields
	 * that should be saved in user profile database.
	 */
	this.getProfileFields = function() {
		var myfields = "";
		if(ValidationUtil.hasValue(this.get("firstname")))
		{
			myfields = myfields + ",firstname";
		}
		if(ValidationUtil.hasValue(this.get("lastname")))
		{
			myfields = myfields + ",lastname";
		}
		if(ValidationUtil.hasValue(this.get("country")))
		{
			myfields = myfields + ",country";
		}
		if(ValidationUtil.hasValue(this.get("postcode")))
		{
			myfields = myfields + ",postcode";
		}
		return myfields;
	 }
	
	/**
	 * This method returns a comma-delimited list of optin list names
	 * that have been displayed on the form.
	 * User can be added/removed from these lists based on value of
	 * 'named_optin' form field.
	 */
	this.getAllNamedLists = function() {
		return "suppression";
	}

	/**
	 * Survey name to save survey data under. A default value may be 
	 * specified in application config.
	 */
	/*
	this.getSurveyName = function() {
		return "";
	}
	*/
	
	/**
	 * This method returns a comma-delimited list of fields
	 * that should be saved in short answer column of survey table.
	 */
	this.getShortSurveyFields = function() {
		return "";
	}
	
	/**
	 * This method returns a comma-delimited list of fields
	 * that should be saved in long answer column of survey table.
	 */
	this.getLongSurveyFields = function() {
		return "";
	}
	
	/**
	 * This method returns a comma-delimited list of fields
	 * who's values should be retreived from the from processor 
	 * after validation.
	 *
	 * This allows you to modify form variables in the validation script
	 * or set default values for fields that may not be present in the form.
	 *
	 * (server side only)
	 */
	this.getFieldsToReload = function() {
		return ""; // dob
	}

	
	
	/**
	 * This is an exmaple function to that pretties up the date fields.
	 */
	/*
	this.getDob = function () {
		var month = this.get("dob_month");
		var day   = this.get("dob_day");
		var year  = this.get("dob_year");
		if(month!="" && day!="" && year!="") {
			if(ValidationUtil.isDateMDY(month, day, year)) return month+"/"+day+"/"+year;
		}
		return null;
	}
	*/


	/**
	 * This method returns a basic error message that will be used
	 * to create the 'full' error messages that users will see.
	 *
	 * In most circumstances, this message will be followed by 
	 * field-specific messages if an error occurs.
	 */
	/*
	this.getBaseErrorMessage = function() {
		var result = "The following fields are missing or invalid";
		if(this.get("profanityfiltered") == "true") 
			result += "\n(some fields may have been filtered for profanity)";
		return result+":";
	}
	*/
}
