function AbstractValidator()
{
	this.message = "";
	this.params = new Array();
	this.form = null;
	this.formName = null;


	this.buildMessage = function()
	{
		return replaceTokens(this.message, this.params, this.form);
	}
	
}

//*************************************
// DoubleSelectValidator
//*************************************

function DoubleSelectValidator()
{
	this.inheritFrom = AbstractValidator;
	this.inheritFrom();

	this.isValid = function(field)
	{
	
		var number = field.inputs.right.options.length;
		var min = new Number(this.params['min']);
		if (!isNaN(min) && (number < min))
		{
			return false;
		}
	
		var max = new Number(this.params['max']);
		if (!isNaN(max) && (number > max))
		{
			return false;
		}
		
		return true;
	}
}


//*************************************
// ExpressionValidator
//*************************************

function FunctionValidator()
{
	this.inheritFrom = AbstractValidator;
	this.inheritFrom();

	this.isValid = function(field)
	{
		alert('depreciated');
		return true;
	
	/*
		var result= false;
		
		eval("result = " + this.params['functionName'] + "(field)");
	
	//	try
	//	{
			var expression = new Function("field", this.params['expression']) 
			result = expression(field);
	//	}
	//	catch (err)
	//	{
	//		alert("error in expression:\n\n" + this.params['expression']);
	//	}
		return result;
	*/
	}
}

//*************************************
// IntRangeValidator
//*************************************

function IntRangeValidator()
{
	this.inheritFrom = AbstractValidator;
	this.inheritFrom();


	this.isValid = function(field)
	{
		var value = field.getValue();
		
		if (value.length == 0)
			return true;
	
		var number = new Number(value);
		if (isNaN(number))
		{
			return false;
		}
	
		var min = new Number(this.params['min']);
		if (!isNaN(min) && (number < min))
		{
			return false;
		}
	
		var max = new Number(this.params['max']);
		if (!isNaN(max) && (number > max))
		{
			return false;
		}
		
		return true;
	}
}

//*************************************
// EmailValidator
//*************************************

function EmailValidator()
{
	this.inheritFrom = AbstractValidator;
	this.inheritFrom();

	this.isValid = function(field)
	{
		return validEmail(field.getValue());
	}

}
function validEmail(input)
{
	// we are not checking if this is supplied or not - just valid
	if (input.length == 0)
		return true;
	else
		return emailCheck (input)
}

/* 
http://javascript.internet.com/forms/email-address-validation.html
(Refer to email-validation.js.txt for a copy of the fully commented original script)
*/
function emailCheck (emailStr) {

    var checkTLD=1;
    var knownDomsPat=/^(com|net|org|edu|int|mil|gov|arpa|biz|aero|name|coop|info|pro|museum)$/;
    var emailPat=/^(.+)@(.+)$/;
    var specialChars="\\(\\)><@,;:\\\\\\\"\\.\\[\\]";
    var validChars="\[^\\s" + specialChars + "\]";
    var quotedUser="(\"[^\"]*\")";
    var ipDomainPat=/^\[(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})\]$/;
    var atom=validChars + '+';
    var word="(" + atom + "|" + quotedUser + ")";
    var userPat=new RegExp("^" + word + "(\\." + word + ")*$");
    var domainPat=new RegExp("^" + atom + "(\\." + atom +")*$");
    var matchArray=emailStr.match(emailPat);
    
    if (matchArray==null) {
        return "The email address seems incorrect (check @ and .'s)";
    }

    var user=matchArray[1];
    var domain=matchArray[2];

    for (i=0; i<user.length; i++) {
        if (user.charCodeAt(i)>127) {
            return "Ths email address's username contains invalid characters.";
        }
    }

    for (i=0; i<domain.length; i++) {
        if (domain.charCodeAt(i)>127) {
            return "Ths email address's domain name contains invalid characters.";
        }
    }

    if (user.match(userPat)==null) {
        return "The email address's username doesn't seem to be valid.";
    }

    var IPArray=domain.match(ipDomainPat);

    if (IPArray!=null) {
        for (var i=1;i<=4;i++) {
            if (IPArray[i]>255) {
                return "The email address's destination IP address is invalid.";
            }
        }
        return true;
    }
		
    var atomPat=new RegExp("^" + atom + "$");
    var domArr=domain.split(".");
    var len=domArr.length;
	
    for (i=0;i<len;i++) {
        if (domArr[i].search(atomPat)==-1) {
            return "The email address's domain name does not seem to be valid.";
        }
    }

    if (checkTLD && domArr[domArr.length-1].length!=2 && 
    domArr[domArr.length-1].search(knownDomsPat)==-1) {
        return "The email address must end in a well-known domain or two letter country code.";
    }

    if (len<2) {
        return "The email address's domain name is missing a hostname.";
    }
	
	return true;
}

//*************************************
// RequiredStringValidator
//*************************************
function RequiredStringValidator()
{
	this.inheritFrom = AbstractValidator;
	this.inheritFrom();
	
	this.isValid = function(field)
	{
		if (field.getValue().length > 0)
		{
			return true;
		}
		return false;
	}
}

//*************************************
// TimeRangeValidator
//*************************************

function TimeRangeValidator()
{
	this.inheritFrom = AbstractValidator;
	this.inheritFrom();

	this.isValid = function(field)
	{
	
		var start = field.inputs.start.value;
		var end = field.inputs.end.value;
	
		if ( (this.params["RequiredStart"] == "true") && (start.length == 0))
		{
			return false;
		}
		if( (this.params["RequiredEnd"] == "true") && (end.length == 0))
		{
			return false;
		}
		return true;
	}
}

//*************************************
// MonthYearValidator
//*************************************

function MonthYearValidator()
{
	this.inheritFrom = AbstractValidator;
	this.inheritFrom();

	this.isValid = function(field)
	{
	
	//	alert( typeof field.inputs.month );
	
		var selectedMonth = field.inputs.month.value;
		var selectedYear = field.inputs.year.value;
	
	//	alert( selectedMonth + ':' + typeof selectedMonth );
	
		if ( (this.params["RequiredMonth"] == "true") && (selectedMonth.length == 0))
		{
			return false;
		}
		if( (this.params["RequiredYear"] == "true") && (selectedYear.length == 0))
		{
			return false;
		}
		return true;
	}
}

//*************************************
// CCNumValidator
//*************************************

function CCNumValidator()
{
	this.inheritFrom = AbstractValidator;
	this.inheritFrom();

	this.isValid = function(field)
	{
		var original = field.getValue();
		if (original.length > 0)
		{
			for(var i = 0 ; i< original.length ; i++)
			{
				var c = original.charAt(i);
				if(!isDigit(c))
				{
					return false;
				}
			}
			if(this.params["MinLength"] == null || original.length >= Number(this.params["MinLength"]))
			{
				return true;
			}
			else
			{
				return false;
			}
		}
		else
		{
			return true;
		}
	}
}

//*************************************
// Misc Validator Support Functions
//*************************************

function replaceTokens( expression, mapParams, formSource )
{
	while (true)
	{
    	var x = expression.indexOf("${");
    	var y = expression.indexOf("}", x);
	
    
    	if ((x != -1) && (y != -1))
    	{
        	var paramName = expression.substring(x + 2, y);
   	

    		// resolve from the params
		    var paramValue = mapParams[paramName];

			if (paramValue == null)
			{
				// resolve from the form
				paramValue = findFieldValue(formSource, paramName);
			}
			
    		if (paramValue != null)
    		{
    			expression = expression.substring(0, x) + paramValue + expression.substring(y + 1);
    		}
    		else
    		{
    			// the variable doesn't exist, so don't display anything
    			expression = expression.substring(0, x) + expression.substring(y + 1);
    		}
        }
        else
        {
    	    break;
    	}
   	}
    return expression;
}

function findFormField(form, fieldName)
{
	for (var i=0; i < form.elements.length; i++)
	{
		var input = form.elements[i];

		if (input.name == fieldName)
		{
			return input;
		}
	}
	return null;
}

function findFieldValue( form, fieldName  )
{
	var field = findFormField(form, fieldName );
	
	if (field != null)
	{
		return findFieldValue(field);
	}

	return null;
}

function findFieldValue( field )
{
	if (typeof field == "undefined")
		return null;

	switch (field.type)
	{
				
		case "text":
		case "textarea":
		case "hidden":
						
			return field.value;
			break;
										
		case "select-one":
			if (field.selectedIndex > -1)
				return field[field.selectedIndex].value;
			else
				return "";
			break;
						
		case "radio":
			for (var i = 0; i < field.length; i++)
			{
				if (field[i].selected)
				{
					return field[i].value;
				}
			}
			break;
	}

	return null;
}

var ZERO_CHARCODE = "0".charCodeAt(0);
var NINE_CHARCODE = "9".charCodeAt(0);
function isDigit( c )
{
	return c.length == 1 && ( c.charCodeAt(0) >= ZERO_CHARCODE || c.charCodeAt(0) <= NINE_CHARCODE );
}


//*************************************
// StringLengthValidator
//*************************************

function StringLengthValidator()
{
	this.inheritFrom = AbstractValidator;
	this.inheritFrom();

	this.isValid = function(field)
	{
		var value = field.getValue();
		
		var min = new Number(this.params['minLength']);
		if (!isNaN(min) && (value.length < min))
		{
			return false;
		}
	
		var max = new Number(this.params['maxLength']);
		if (!isNaN(max) && (value.length > max))
		{
			return false;
		}
		return true;
	}
}

//*************************************
// RequiredMoneyValidator
//*************************************
function RequiredMoneyValidator()
{
	this.inheritFrom = AbstractValidator;
	this.inheritFrom();
	
	this.isValid = function(field)
	{
		if (field.getCentsValue() == "")
		{
			return false;
		}
		return true;
	}
}
