/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Class:		stlValidator
//
// Description:	
//
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function stlValidator()
{
	/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	//
	// Function:	fromPresentation()
	//
	// Description:	Converts any user specified input value to a value for internal use.
	//
	/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	this.fromPresentation = function(value)
	{
		return value;
	}
	
	/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	//
	// Function:	toPresentation()
	//
	// Description:	Converts any value for internal use to a user presentable value.
	//
	/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	this.toPresentation = function(value)
	{
		return value;
	}
	
	/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	//
	// Function:	constructor
	//
	// Description:
	//
	/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		this.formats = function() {}
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Class:		stlValidator_Date
//
// Description:	Validator for date content. Accepts european, american and iso8601 date formats. Allows the discartion or convervation of leading
//				zeros en allows for the adjustment of the separator symbol.
//
// Usage:		stlValidator_Date.format			Either "dd-mm-yyyy", "mm-dd-yyyy" or "yyyy-mm-dd" to specify field order. May also be derived
//													from .formats.european, .formats.american and .formats.iso8601 respectively.
//				stlValidator_Date.separator			Any character, typically "/" or "-" to be used as segment separator. May not be empty.
//				stlValidator_Date.leadingZeros		If true maintains leading zeros. If fals omits them.
//
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function stlValidator_Date()
{
	var that = this;
	
	/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	//
	// Inheritance: stlValidator
	//
	/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	this.inheritFrom_stlValidator = stlValidator;
	this.inheritFrom_stlValidator();
	
	/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	//
	// Function:	fromPresentation()
	//
	// Description:	Converts any user specified input value to an ISO8601 compliant date specification for internal use.
	//
	/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	this.fromPresentation = function(value)
	{
		var bDone;
		var arrSegments = value.split(this.separator);
		var segment;
		var curDate = new Date();
		var oldDate = new Date();
		var newDate = new Date();
		newDate.setTime(0);
	
		switch(this.format)
		{
			case this.formats.european:
				segmentYear = 2;
				segmentMonth = 1;
				segmentDate = 0;
				break;
			
			case this.formats.american:
				segmentYear = 2;
				segmentMonth = 0;
				segmentDate = 1;
				break;

			case this.formats.iso8601:
				segmentYear = 0;
				segmentMonth = 1;
				segmentDate = 2;
				break;
		}
		
		/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		// Extract segment year	
		/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		bDone = false;
		if(arrSegments.length > segmentYear)
		{
			if((segment = parseInt(arrSegments[segmentYear], 10)) != "")
			{
				if(isNaN(segment))
					segment = 1970;
				if(segment < 1970)
					segment = 1970;
				newDate.setFullYear(segment);
				bDone = true;
			}
		}
		if(!bDone)
			newDate.setFullYear(curDate.getFullYear());
		
		/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		// Extract segment month
		/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		bDone = false;
		if(arrSegments.length > segmentMonth)
		{
			if(arrSegments[segmentMonth] != "")
			{
				segment = parseInt(arrSegments[segmentMonth], 10)
				if(isNaN(segment))
					segment = 1;
				if(segment < 1)
					segment = 1;
				if(segment > 12)
					segment = 12;
				newDate.setMonth(segment - 1);
				bDone = true;
			}
		}
		if(!bDone)
			newDate.setMonth(curDate.getMonth());
		
		/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		// Extract segment date
		/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		bDone = false;
		if(arrSegments.length > segmentDate)
		{
			if(arrSegments[segmentDate] != "")
			{
				segment = parseInt(arrSegments[segmentDate], 10)
				if(isNaN(segment))
					segment = 1;
				if(segment < 1)
					segment = 1;
				oldDate.setTime(newDate.getTime());
				while(1)
				{
					newDate.setDate(segment);
					if((newDate.getMonth() == oldDate.getMonth()) && (newDate.getFullYear() == oldDate.getFullYear()))
						break;
					newDate.setTime(oldDate.getTime());
					segment--;
					if(segment < 0)
					{
						newDate.setDate(0);
						break;
					}
				}				
				bDone = true;
			}
		}
		if(!bDone)
			newDate.setDate(curDate.getDate());
		
		return (newDate.getFullYear() + "-" + (newDate.getMonth() < 9 ? "0" : "") + (newDate.getMonth() + 1) + "-" + (newDate.getDate() < 10 ? "0" : "") + newDate.getDate());
	}

	/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	//
	// Function:	toPresentation
	//
	// Description:	Converts any ISO8601 compliant date specification to a presentation form for an input element.
	//
	/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	this.toPresentation = function(value)
	{
		switch(this.format)
		{
			case this.formats.european:
				return (!this.leadingZeros ? parseInt(value.substr(8,2), 10) : value.substr(8,2)) + this.separator + (!this.leadingZeros ? parseInt(value.substr(5,2), 10) : value.substr(5,2)) + this.separator + (!this.leadingZeros ? parseInt(value.substr(0,4), 10) : value.substr(0,4));

			case this.formats.american:
				return (!this.leadingZeros ? parseInt(value.substr(5,2), 10) : value.substr(5,2)) + this.separator + (!this.leadingZeros ? parseInt(value.substr(8,2), 10) : value.substr(8,2)) + this.separator + (!this.leadingZeros ? parseInt(value.substr(0,4), 10) : value.substr(0,4));

			case this.formats.iso8601:
				return (!this.leadingZeros ? parseInt(value.substr(0,4), 10) : value.substr(0,4)) + this.separator + (!this.leadingZeros ? parseInt(value.substr(5,2), 10) : value.substr(5,2)) + this.separator + (!this.leadingZeros ? parseInt(value.substr(8,2), 10) : value.substr(8,2));
		}
	}
	
	/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	//
	// Function:	constructor
	//
	// Description:
	//
	/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		this.formats.european	= "dd-mm-yyyy";
		this.formats.american	= "mm-dd-yyyy";
		this.formats.iso8601	= "yyyy-mm-dd";

		this.format = this.formats.american;
		this.separator = "-";
		
		this.leadingZeros	= true;		
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Class:		stlValidator_Time
//
// Description:	Validator for time content. Accepts iso8601 time format. Allows for the adjustment of the separator symbol.
//
// Usage:		stlValidator_Time.format			Either "hh", "hh:mm" or "hh:mm:ss" to specify field order. May also be derived
//													from .formats.hours, .formats.minutes and .formats.seconds respectively.
//				stlValidator_Time.separator			Any character, typically "/" or "-" to be used as segment separator. May not be empty.
//
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function stlValidator_Time()
{
	var that = this;
	
	/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	//
	// Inheritance: stlValidator
	//
	/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	this.inheritFrom_stlValidator = stlValidator;
	this.inheritFrom_stlValidator();

	/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	//
	// Function:	fromPresentation()
	//
	// Description:	Converts any user specified input value to an ISO8601 compliant time specification for internal use.
	//
	/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	this.fromPresentation = function(value)
	{
		var arrSegments = value.split(":");
		
		var hours = 0;
		var minutes = 0;
		var seconds = 0;

		if(arrSegments.length > 0)
		{
			if(arrSegments[0] != "")
			{
				hours = parseInt(arrSegments[0], 10)
				if(isNaN(hours))
					hours = 0;
				if(hours < 0)
					hours = 0;
				if(hours > 23)
					hours = 23;
			}
		}	

		if(arrSegments.length > 1)
		{
			if(arrSegments[1] != "")
			{
				minutes = parseInt(arrSegments[1], 10)
				if(isNaN(minutes))
					minutes = 0;
				if(minutes < 0)
					minutes = 0;
				if(minutes > 59)
					minutes = 59;
			}
		}	

		if(arrSegments.length > 2)
		{
			if(arrSegments[2] != "")
			{
				seconds = parseInt(arrSegments[2], 10)
				if(isNaN(minutes))
					seconds = 0;
				if(seconds < 0)
					seconds = 0;
				if(seconds > 59)
					seconds = 59;
			}
		}
		
		return (hours < 10 ? "0" : "") + hours + ":" + (minutes < 10 ? "0" : "") + minutes + ":" + (seconds < 10 ? "0" : "") + seconds;
	}

	/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	//
	// Function:	toPresentation
	//
	// Description:	Converts any ISO8601 compliant time specification to a presentation form for an input element.
	//
	/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	this.toPresentation = function(value)
	{
		switch(this.format)
		{
			case this.formats.hours:
				return value.substr(0, 2);
			
			case this.formats.minutes:
				return value.substr(0, 2) + this.separator + value.substr(3, 2);
			
			default:
				return value.substr(0, 2) + this.separator + value.substr(3, 2) + this.separator + value.substr(6, 2);
		}
	}
	
	/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	//
	// Function:	constructor
	//
	// Description:
	//
	/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		this.formats.hours = "hh";
		this.formats.minutes = "hh:mm";
		this.formats.seconds = "hh:mm:ss";
		
		this.format = this.formats.minutes;
		
		this.separator = ":";
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Class:		stlValidator_Number
//
// Description:	Validator for numeral content.
//
// Usage:		stlValidator_Number.numDecimals			The number of decimals approved
//				stlValidator_Number.decimalPoint		The symbol for the decimal point
//
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function stlValidator_Number()
{
	var that = this;
	
	/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	//
	// Inheritance: stlValidator
	//
	/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	this.inheritFrom_stlValidator = stlValidator;
	this.inheritFrom_stlValidator();

	/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	//
	// Function:	fromPresentation()
	//
	// Description:	Converts any user specified input value to an ISO8601 compliant time specification for internal use.
	//
	/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	this.fromPresentation = function(value)
	{
		var r = new RegExp((this.decimalPoint == "." ? "\\" : "") + this.decimalPoint, "g");
		value = parseFloat(value.replace(r, "."));
		value = value.toFixed(this.numDecimals);	
		if(isNaN(value))
			value = 0;	

		return value;
	}

	/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	//
	// Function:	fromPresentation()
	//
	// Description:	Converts any user specified input value to an ISO8601 compliant time specification for internal use.
	//
	/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	this.toPresentation = function(value)
	{
		value = parseFloat(value);
		return value.toFixed(this.numDecimals).replace(/\./g, this.decimalPoint);
	}

	/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	//
	// Function:	constructor
	//
	// Description:
	//
	/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		this.numDecimals = 0;
		this.decimalPoint = ".";
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Class:		stlValidator_Number_Amount
//
// Description:	Validator for amount content which is stored in memory in cents
//
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function stlValidator_Number_Amount()
{
	var that = this;
	
	/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	//
	// Inheritance: stlValidator_Number
	//
	/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	this.inheritFrom_stlValidator_Number = stlValidator_Number;
	this.inheritFrom_stlValidator_Number();

	/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	//
	// Function:	fromPresentation()
	//
	// Description:	Converts any user specified input value to an ISO8601 compliant time specification for internal use.
	//
	/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	this.parent_fromPresentation = this.fromPresentation;
	this.fromPresentation = function(value)
	{
		return this.parent_fromPresentation(value) * 100;
	}

	/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	//
	// Function:	fromPresentation()
	//
	// Description:	Converts any user specified input value to an ISO8601 compliant time specification for internal use.
	//
	/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	this.parent_toPresentation = this.toPresentation;
	this.toPresentation = function(value)
	{
		return this.parent_toPresentation(value / 100);
	}

	/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	//
	// Function:	constructor
	//
	// Description:
	//
	/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		this.numDecimals = 2;
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Class:		stlFieldValidator
//
// Description:	Root class for all field validators. Classes derived from this class take an element ID as their sole parameter for class
//				instantiation. Updates in the field are automatically parsed for validation and updated accordingly. In addition the following
//				methods and variables are available:
//
//				toPresentation()			Places an internal value (e.g. ISO) into the field in localized format (e.g. american date)
//				fromPresentaion()			Retrieves the value from the field and retrieves it in the internal format (e.g. ISO)
//				validator					The actual validator performing the job.
//
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function stlFieldValidator(idElement)
{
	var that = this;
	
	/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	//
	// Function:	dateUpdatePresentation
	//
	// Description: Is called if the element blurs. Reads the value of the element through the fromPresentation() method and writes back the
	//				value through the toPresentation() method.
	//
	/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	this.updatePresentation = function(value)
	{
		return this.validator.toPresentation(this.validator.fromPresentation(value));
	}

	/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	//
	// Function:	fromPresentation()
	//
	// Description:	Converts any user specified input value to an ISO8601 compliant time specification for internal use.
	//
	/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	this.fromPresentation = function()
	{
		return this.validator.fromPresentation(this.elElement.value);
	}

	/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	//
	// Function:	toPresentation
	//
	// Description:	Converts any ISO8601 compliant time specification to a presentation form for an input element.
	//
	/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	this.toPresentation = function(value)
	{
		this.elElement.value = this.validator.toPresentation(value);
	}
	
	/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	//
	// Function:	Constructor
	//
	/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		this.formats = function() {}

		this.elElement = document.getElementById(idElement);
		if(this.elElement == undefined)
			return stlApp.messages.add("ERROR\nElement not found.\n\nCould not find element " + idElement);

		this.elElement.onblur = function() { this.value = that.updatePresentation(this.value); }
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Class:		stlFieldValidator_Date
//
// Description:	Validator using stlValidator_Date.
//
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function stlFieldValidator_Date(idElement)
{
	var that = this;
	
	/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	//
	// Inheritance: stlFieldValidator
	//
	/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	this.inheritFrom_stlFieldValidator = stlFieldValidator;
	this.inheritFrom_stlFieldValidator(idElement);	

	/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	//
	// Function:	constructor
	//
	// Description:
	//
	/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		this.validator = new stlValidator_Date();	
}


/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Class:		stlFieldValidator_Time
//
// Description:	Validator using stlValidator_Time.
//
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function stlFieldValidator_Time(idElement)
{
	var that = this;
	
	/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	//
	// Inheritance: stlFieldValidator
	//
	/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	this.inheritFrom_stlFieldValidator = stlFieldValidator;
	this.inheritFrom_stlFieldValidator(idElement);	

	/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	//
	// Function:	constructor
	//
	// Description:
	//
	/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		this.validator = new stlValidator_Time();

}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Class:		stlFieldValidator_Number
//
// Description:	Validator using stlValidator_Number.
//
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function stlFieldValidator_Number(idElement)
{
	var that = this;
	
	/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	//
	// Inheritance: stlFieldValidator
	//
	/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	this.inheritFrom_stlFieldValidator = stlFieldValidator;
	this.inheritFrom_stlFieldValidator(idElement);	

	/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	//
	// Function:	constructor
	//
	// Description:
	//
	/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		this.validator = new stlValidator_Number();

}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Class:		stlFieldValidator_Number_Amount
//
// Description:	Validator using stlValidator_Number_Amount.
//
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function stlFieldValidator_Number_Amount(idElement)
{
	var that = this;
	
	/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	//
	// Inheritance: stlFieldValidator
	//
	/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	this.inheritFrom_stlFieldValidator = stlFieldValidator;
	this.inheritFrom_stlFieldValidator(idElement);	

	/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	//
	// Function:	constructor
	//
	// Description:
	//
	/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		this.validator = new stlValidator_Number_Amount();

}
