var doValidation = false;
var geoPageValidationEnabled = false;
var geoValidationClientVersion = 1;
var geoValidationServerVersion = -1;
var haveSummaries = false;

// dummy stubs
function old_Page_ClientValidate() {}
function old__doPostBack() {}

function Geo__doPostBack(eventTarget, eventArgument)
{
	if(typeof(old__doPostBack) == 'function')
		old__doPostBack(eventTarget, eventArgument);
}

function GeoPage_ClientValidate()
{
	doValidation = true;
}

//////////////////////////////////////
//	GeoValidator Object Functions	//
//////////////////////////////////////

function GeoCustomValidate()
{
	//
	// dataBall[0] = Custom Function
	// dataBall[1] = Text
	// dataBall[2] = ErrorMessage
	//
	
	if(!GeoIsValidatorEnabled(this.controltovalidateID, this.errorTagID))
		return null;
		
	var errorText = null;
	var errorMessage = null;
	if(!this.dataBall[0](this.controltovalidateID))
	{
		errorText = this.dataBall[1];
		errorMessage = this.dataBall[2];
	}
	
	var errorTag = document.getElementById(this.errorTagID);
	GeoSetErrorDisplay(errorTag, errorText);
		return errorMessage;
}

function GeoCompareValidate()
{
	//
	// dataBall[0] = Regular Expression
	// dataBall[1] = Is Required
	// dataBall[2] = Is Required Text
	// dataBall[3] = Is Required Error
	// dataBall[4] = Invalid Text
	// dataBall[5] = Invalid Error
	// dataBall[6] = Compare Text
	// dataBall[7] = Compare Error
	// dataBall[8] = Control To Compare
	// dataBall[9] = Compare Value
	// dataBall[10] = Compare Logic
	// dataBall[11] = Compare Type
	// dataBall[12] = Range
	// dataBall[13] = ExcludeRange
	//
	
	if(this.runBefore == null)
	{
		if(this.dataBall[8] != null && this.dataBall[8] != "")
		{
			var controlToCompare = document.getElementById( this.dataBall[8] );			
			Geo_AttachEvent(controlToCompare, "blur", new Function("GeoValidators[" + this.arrayIndex + "].evaluationfunction();"), false);
		}
		this.runBefore = true;
	}
	
	if(!GeoIsValidatorEnabled(this.controltovalidateID, this.errorTagID))
		return null;
		
	if(this.dataBall[8] != "" && !GeoIsValidatorEnabled(this.dataBall[8]))
		return null;
		
	var errorMessage = null;
	var errorText = null;
	var objSubject = document.getElementById(this.controltovalidateID);
	var controlValue = GeoGetValueRecursive(objSubject);	
	var compareValue = null;
	var errorTag = document.getElementById(this.errorTagID);
	var isRequired = this.dataBall[1].toString().toLowerCase() == "true";
	
	if(this.dataBall[8] != "")
		compareValue = GeoGetValueRecursive( document.getElementById(this.dataBall[8]) );
	else
		compareValue = this.dataBall[9];
		
	if(isRequired)	
	{
		if(!ValidateRequired(controlValue))
		{
			errorText = this.dataBall[2];
			errorMessage = this.dataBall[3];
		}
	}
	
	if(isRequired || controlValue != "" || (this.dataBall[8] != "" && compareValue != ""))
	{
		if(errorMessage == null && !RegularExpressionValidate(controlValue,this.dataBall[0]))
		{
			errorText = this.dataBall[4];
			errorMessage = this.dataBall[5];
		}

		if(errorMessage == null && this.dataBall[8] != "" && !RegularExpressionValidate(compareValue,this.dataBall[0]))
		{
			errorText = this.dataBall[4];
			errorMessage = this.dataBall[5];
		}
		
		if(errorMessage == null && !CompareValidate(controlValue,compareValue,this.dataBall[10],this.dataBall[11],this.dataBall[12],this.dataBall[13]))
		{
			errorText = this.dataBall[6];
			errorMessage = this.dataBall[7];
		}
	}
	
	GeoSetErrorDisplay(errorTag, errorText);
	return errorMessage;
}

function GeoRegularExpressionValidate()
{
	//
	// dataBall[0] = Regular Expression
	// dataBall[1] = Is Required
	// dataBall[2] = Is Required Text
	// dataBall[3] = Is Required Error
	// dataBall[4] = Invalid Text
	// dataBall[5] = Invalid Error
	//
	
    if(!GeoIsValidatorEnabled(this.controltovalidateID, this.errorTagID))
		return null;

	var errorMessage = null;
	var errorText = null;
	var objSubject = document.getElementById(this.controltovalidateID);
	var value = GeoGetValueRecursive(objSubject);	
	var errorTag = document.getElementById(this.errorTagID);

	if(this.dataBall[1].toString().toLowerCase() == "true" && !ValidateRequired(value))	
	{
		errorText = this.dataBall[2];
		errorMessage = this.dataBall[3];
	}

	if(errorMessage == null && !RegularExpressionValidate(value,this.dataBall[0]))
	{
		errorText = this.dataBall[4];
		errorMessage = this.dataBall[5];
	}
		    
	GeoSetErrorDisplay(errorTag,errorText);
	return errorMessage;
}

function GeoRequiredFieldValidate()
{	
	//
	// dataBall[0] = Required Text
	// dataBall[1] = Required Error
	//

	if(!GeoIsValidatorEnabled(this.controltovalidateID, this.errorTagID))
		return null;

	var objSubject = document.getElementById(this.controltovalidateID);
	var value = GeoGetValueRecursive(objSubject);
	var errorTag = document.getElementById(this.errorTagID);
	var errorMessage = null;
	var errorText = null;
	
	if(!ValidateRequired(value))
	{
		errorText = this.dataBall[0];
		errorMessage = this.dataBall[1];
	}

	GeoSetErrorDisplay(errorTag,errorText);
	return errorMessage;			
}

function geoCheckMaxLength()
{
	//
	// dataBall[0] = Max Length
	// dataBall[1] = Required Text
	// dataBall[2] = Required Error
	//

    if(!GeoIsValidatorEnabled(this.controltovalidateID, this.errorTagID))
		return null;
	
	var errorMessage = null;
	var errorText = null;
	var objSubject = document.getElementById(this.controltovalidateID);
	var value = GeoGetValueRecursive(objSubject);
	var errorTag = document.getElementById(this.errorTagID);
	
	var IsValid = value.length <= this.dataBall[0];	
	
	if(!IsValid)
	{
		errorMessage = replaceMaxLengthPlaceholders(this.dataBall[2], this.dataBall[0], value.length);
		errorText = replaceMaxLengthPlaceholders(this.dataBall[1], this.dataBall[0], value.length);
	}
	
	GeoSetErrorDisplay(errorTag, errorText);
	return errorMessage;	
}

//////////////////////////////
//	Validation Functions	//
//////////////////////////////

function CompareValidate(controlValue, compareValue, compareLogic, compareType, range, ExcludeRange)
{
	var returnValue = true;
	var minCompareValue = null;
	var maxCompareValue = null;
	
	if(range == null || range == "")
		range = 0;
	
	switch(compareType)
	{
		case "String":
			minCompareValue = compareValue;
			maxCompareValue = compareValue;
			break;
			
		case "Date":
			var badDate = Date.parse("");
			controlValue = Date.parse(controlValue.replace("-","/"));
			compareValue = Date.parse(compareValue.replace("-","/"));
			
			if(isNaN(controlValue) || isNaN(compareValue))
				return false;
			
			minCompareValue = new Date();
			minCompareValue.setTime(compareValue);			
			minCompareValue.setFullYear(minCompareValue.getFullYear() - parseInt(range/365),minCompareValue.getMonth(),minCompareValue.getDate() - (range%365));
			
			maxCompareValue = new Date();
			maxCompareValue.setTime(compareValue);			
			maxCompareValue.setFullYear(maxCompareValue.getFullYear() + parseInt(range/365),maxCompareValue.getMonth(),maxCompareValue.getDate() + (range%365));								
			break;
			
		case "Number":
		case "Float":
			controlValue = parseInt(controlValue);
			compareValue = parseInt(compareValue);			
			minCompareValue = compareValue - range;															
			maxCompareValue = compareValue + range;
			break;
	}
	
	var IsRangeZero = (range == 0);
	
	switch(compareLogic)
	{
		case "IsEqual":
			returnValue = maxCompareValue >= controlValue && minCompareValue <= controlValue;
			break;

		case "IsGreaterThan":	
			if(!ExcludeRange)
				returnValue = (controlValue > compareValue) && ( (controlValue <= maxCompareValue) || IsRangeZero ) ;
			else
				returnValue = controlValue > compareValue && ( !(controlValue <= maxCompareValue) || IsRangeZero );
		break;

		case "IsGreaterThanOrEqual":
			if(!ExcludeRange)
				returnValue = controlValue >= compareValue && ( (controlValue <= maxCompareValue) || IsRangeZero ) ;
			else
				returnValue = controlValue >= compareValue && ( !(controlValue <= maxCompareValue) || IsRangeZero );
		break;

		case "IsLessThan":
			if(!ExcludeRange)
				returnValue = controlValue < compareValue && ( (controlValue >= minCompareValue) || IsRangeZero );
			else
			returnValue = controlValue < compareValue && ( !(controlValue >= minCompareValue) || IsRangeZero );
		break;

		case "IsLessThanOrEqual":
			if(!ExcludeRange)
				returnValue = controlValue <= compareValue && ( (controlValue >= minCompareValue) || IsRangeZero );
			else
				returnValue = controlValue <= compareValue && ( !(controlValue >= minCompareValue) || IsRangeZero );
		break;

		case "IsNotEqual":
			returnValue = !(maxCompareValue >= controlValue && minCompareValue <= controlValue);
		break;
	}
	
	return returnValue;
}

function CompareNumbers(controlValue, compareValue, compareType)
{
	var returnValue = true;
	
	
}

function ValidateRequired(value)
{	
	return !geoIsEmptyString(value);
}

function RegularExpressionValidate(value, regularExpression)
{
	if(value == null || value == "")
		return true;

	var RegEx = new RegExp(regularExpression,"");				
	return value.match(RegEx) != null;
}

//////////////////////////
//	Utility Functions	//
//////////////////////////

function Trim(str)
{
   return str.replace(/^\s*|\s*$/g,'');
}

function geoIsEmptyString(value)
{
	return (value == null || Trim(value) == "");
}

function GeoGetValueRecursive(objSubject)
{	
	switch(objSubject.type)
	{
		case "textarea":
		case "text":
			return objSubject.value;
		break;

		case "radio":
			if( objSubject.checked == true )
				return objSubject.value;
		break;

		case "checkbox":
			if( objSubject.checked == true )
				return "true";
		break;

		case "select-one":		
		case "select-multiple":
			for(var i = 0; i < objSubject.options.length; i++)
				if(objSubject.options[i].selected)
					return objSubject.options[i].value;
		break;
	}

	var returnValue = null;
	for(var i = 0; i < objSubject.childNodes.length; i++)
	{		
		returnValue = GeoGetValueRecursive(objSubject.childNodes[i]);
		if(returnValue != null)
			return returnValue;
	}	
	return null;
}

function GeoIsValidatorEnabled(controlToValidateID,errorTagID)
{
	var returnValue = true;

	if(!geoPageValidationEnabled)	
		returnValue = false;

	var controlToVal = document.getElementById(controlToValidateID);
	var errorTag =  document.getElementById(errorTagID);
	if(typeof(shc_CheckObjectVisibility) == "function")
	{
		if(!shc_CheckObjectVisibility(controlToVal) || !shc_CheckObjectVisibility(errorTag))
			returnValue = false;
	}

	if(!returnValue)
	{
		var errorTag = document.getElementById(errorTagID);		
		GeoSetErrorDisplay(errorTag, null);
	}
	
	return returnValue;
}

function GeoSetErrorDisplay(errorTag,errorText)
{
	if(errorText == null)
		errorTag.style.display = "none";
	else
	{
		errorTag.style.display = "";
		errorTag.innerHTML = errorText;
	}
}

function replaceMaxLengthPlaceholders(text, maxLength, curLength)
{
	var diff = curLength - maxLength;
	text = text.replace(/%0/,diff.toString());
	text = text.replace(/%1/,maxLength.toString());
	text = text.replace(/%2/,curLength.toString());
	return text;
}

function Geo_AttachEvent(elmSubject, strEventName, objFunction, bUseCapture)
{
	if(elmSubject == null)
		return;
		
	var rblList = document.getElementsByName(elmSubject.id.replace("_", ":"));
	if(rblList.length > 0)
		for(var i = 0; i < rblList.length; i++)
		{
			if(rblList[i].type == null || rblList[i].type != "radio")
				continue;
			
			Geo_AddEvent(rblList[i], "click", objFunction, bUseCapture);
		}


	Geo_AddEvent(elmSubject, strEventName, objFunction, bUseCapture);
}

function Geo_AddEvent(elmSubject, strEventName, objFunction, bUseCapture)
{
	if (elmSubject.addEventListener)
		elmSubject.addEventListener(strEventName, objFunction, bUseCapture);
	else if (elmSubject.attachEvent)
		elmSubject.attachEvent("on" + strEventName, objFunction);
}

//////////////////////////////////////
//	Page Level Validation Functions	//
//////////////////////////////////////

function GeoValidatePage()
{
	if(!doValidation)
		return true;

	geoPageValidationEnabled = true;

	var errorCount = 0;
	var pageIsValid = true;
	var errorListHTML = "<ul>";
	for(var i = 0; i < GeoValidators.length; i++)
	{
		var errorMessage = GeoValidators[i].evaluationfunction();
		if(errorMessage == null)
			continue;
	
		errorCount++;
		pageIsValid = false;
	
		if(!haveSummaries)
			continue;
								
		if(GeoValidators[i].anchorID != null)
			errorListHTML += "<li><a onclick=\"document.getElementById('" + GeoValidators[i].controltovalidateID + "').focus(); return false;\" href=\"#" + GeoValidators[i].anchorID + "\">" + errorMessage + "</a></li>";
		else
			errorListHTML += "<li>" + errorMessage + "</li>";		
	}
	errorListHTML += "</ul>";
	
	if(errorCount > 0)
		GeoBindValidationSummary(errorListHTML);
	
	doValidation = false;
	return pageIsValid;
}

function GeoBindValidationSummary(content)
{	
	if(!haveSummaries)
		return;
		
	for(var i = 0; i < aryGeoSummary.length; i++)
		document.getElementById(aryGeoSummary[i].summaryDivID).innerHTML = "<p>" + aryGeoSummary[i].leadingText + "</p>" + content + "<p>" + aryGeoSummary[i].trailingText + "</p>";
}

function InitializeValidation()
{
	if (geoValidationServerVersion == -1)
		alert("The current server-side version of GeoValidators is not properly echoing its version.");
	else if(geoValidationServerVersion != geoValidationClientVersion)
		alert("The server and client side versions of GeoValidators do not match.  Server Version: " + geoValidationServerVersion + ", Client Version: " + geoValidationClientVersion);
	
	
	if(typeof(__doPostBack) == 'function')
	{
		old__doPostBack = __doPostBack;
		__doPostBack = Geo__doPostBack;
	}
	
	if(typeof(Page_ClientValidate) == 'function')
	{
		old_Page_ClientValidate = Page_ClientValidate;
		Page_ClientValidate = GeoPage_ClientValidate;
	}
	else
		Page_ClientValidate = new Function("GeoPage_ClientValidate();");
		
	for(var i = 0; i < GeoValidators.length; i++)
	{
		var elmSubject = document.getElementById(GeoValidators[i].controltovalidateID);

		GeoValidators[i].arrayIndex = i;
		Geo_AttachEvent(elmSubject, "blur", new Function("GeoValidators[" + i + "].evaluationfunction();"), false);
	}
	
	if(typeof(aryGeoSummary) == "object")
		haveSummaries = true;	
}

function GeoValidationSummary(summaryDivID, leadingText, trailingText)
{
	// Make this a full-featured class - with an error list
	this.summaryDivID = summaryDivID;
	this.leadingText = leadingText;
	this.trailingText = trailingText;
}

function GeoValidator(errorTagID, evaluationfunction, controltovalidateID, anchorID, dataBall)
{
	this.errorTagID = errorTagID;
	this.evaluationfunction = evaluationfunction;
	this.controltovalidateID = controltovalidateID;	
	this.dataBall = dataBall;
	this.anchorID = anchorID;
}