﻿// Constants
var CLNone = 0, CLYear = 1, CLMonth = 2, CLDay = 3, CLWeekday = 4;
var CLNeutral = "n", CLMasculine = "m", CLFeminine = "f";
var CLSingular = false, CLPlural = true;
var CLSharedLocalisedResources = new CLLocalisedResources();


//*************************** Localization

CLSharedLocalisedResources.addResourceForKeyLanguage("Turkce", "label", "tr");
CLSharedLocalisedResources.addResourceForKeyLanguage(new CLDateFormat(
	[ [ CLNone, "" ], [ CLWeekday, ", " ], [ CLDay, " " ], [ CLMonth, " " ], [ CLYear, "" ] ],
	[ CLDay, CLMonth, CLYear ], "/", true, true, true,
	[ "Ocak", "Şubat", "Mart", "Nisan", "Mayıs", "Haziran", "Temmuz", "Agustos", "Eylül", "Ekim", "Kasım", "Aralık" ], 
	[ "Pazartesi", "Salı", "Çarşamba", "Perşembe", "Cuma", "Cumartesi", "Pazar" ]), "date", "tr");
CLSharedLocalisedResources.addResourceForKeyLanguage(new CLTimeFormat(true, false, "", "", ":", false), "time", "tr");
CLSharedLocalisedResources.addResourceForKeyLanguage(new CLNumberFormat(",", ".", "\u20AC", true), "number", "tr");

CLSharedLocalisedResources.addResourceForKeyLanguage("Deutsch", "label", "de");
CLSharedLocalisedResources.addResourceForKeyLanguage(new CLDateFormat(
	[ [ CLNone, "" ], [ CLWeekday, ", " ], [ CLDay, " " ], [ CLMonth, " " ], [ CLYear, "" ] ],
	[ CLDay, CLMonth, CLYear ], "/", true, true, true,
	[ "Januar", "Februar", "März", "April", "Mai", "Juni", "Juli", "August", "September", "Oktober", "November", "Dezember" ], 
	[ "Montag", "Dienstag", "Mittwoch", "Donnerstag", "Freitag", "Samstag", "Sonntag" ]), "date", "de");
CLSharedLocalisedResources.addResourceForKeyLanguage(new CLTimeFormat(true, false, "", "", ":", false), "time", "de");
CLSharedLocalisedResources.addResourceForKeyLanguage(new CLNumberFormat(",", ".", "\u20AC", true), "number", "de");

CLSharedLocalisedResources.addResourceForKeyLanguage("български ", "label", "bg");
CLSharedLocalisedResources.addResourceForKeyLanguage(new CLDateFormat(
	[ [ CLNone, "" ], [ CLWeekday, ", " ], [ CLDay, " " ], [ CLMonth, " " ], [ CLYear, "" ] ],
	[ CLDay, CLMonth, CLYear ], "/", true, true, true,
	[ "Януари", "Февруари", "Март", "Април", "Май", "Юни", "Юли", "Август", "Септември", "Октомври", "Ноември", "Декември" ], 
	[ "понеделник", "вторник", "сряда", "четвъртък", "петък", "събота", "неделя" ]), "date", "bg");
CLSharedLocalisedResources.addResourceForKeyLanguage(new CLTimeFormat(true, false, "", "", ":", false), "time", "bg");
CLSharedLocalisedResources.addResourceForKeyLanguage(new CLNumberFormat(",", ".", "\u20AC", true), "number", "bg");

CLSharedLocalisedResources.addResourceForKeyLanguage("français", "label", "fr");
CLSharedLocalisedResources.addResourceForKeyLanguage(new CLDateFormat(
	[ [ CLNone, "" ], [ CLWeekday, ", " ], [ CLDay, " " ], [ CLMonth, " " ], [ CLYear, "" ] ],
	[ CLDay, CLMonth, CLYear ], "/", true, true, true,
	[ "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" ], 
	[ "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday" ]), "date", "fr");
CLSharedLocalisedResources.addResourceForKeyLanguage(new CLTimeFormat(true, false, "", "", ":", false), "time", "fr");
CLSharedLocalisedResources.addResourceForKeyLanguage(new CLNumberFormat(",", ".", "\u20AC", true), "number", "fr");

CLSharedLocalisedResources.addResourceForKeyLanguage("ελληνικά", "label", "el");
CLSharedLocalisedResources.addResourceForKeyLanguage(new CLDateFormat(
	[ [ CLNone, "" ], [ CLWeekday, ", " ], [ CLDay, " " ], [ CLMonth, " " ], [ CLYear, "" ] ],
	[ CLDay, CLMonth, CLYear ], "/", true, true, true,
	[ "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" ], 
	[ "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday" ]), "date", "el");
CLSharedLocalisedResources.addResourceForKeyLanguage(new CLTimeFormat(true, false, "", "", ":", false), "time", "el");
CLSharedLocalisedResources.addResourceForKeyLanguage(new CLNumberFormat(",", ".", "\u20AC", true), "number", "el");

CLSharedLocalisedResources.addResourceForKeyLanguage("română", "label", "ro");
CLSharedLocalisedResources.addResourceForKeyLanguage(new CLDateFormat(
	[ [ CLNone, "" ], [ CLWeekday, ", " ], [ CLDay, " " ], [ CLMonth, " " ], [ CLYear, "" ] ],
	[ CLDay, CLMonth, CLYear ], "/", true, true, true,
	[ "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" ], 
	[ "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday" ]), "date", "ro");
CLSharedLocalisedResources.addResourceForKeyLanguage(new CLTimeFormat(true, false, "", "", ":", false), "time", "ro");
CLSharedLocalisedResources.addResourceForKeyLanguage(new CLNumberFormat(",", ".", "\u20AC", true), "number", "ro");

CLSharedLocalisedResources.addResourceForKeyLanguage("العربية", "label", "ar");
CLSharedLocalisedResources.addResourceForKeyLanguage(new CLDateFormat(
	[ [ CLNone, "" ], [ CLWeekday, ", " ], [ CLDay, " " ], [ CLMonth, " " ], [ CLYear, "" ] ],
	[ CLDay, CLMonth, CLYear ], "/", true, true, true,
	[ "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" ], 
	[ "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday" ]), "date", "ar");
CLSharedLocalisedResources.addResourceForKeyLanguage(new CLTimeFormat(true, false, "", "", ":", false), "time", "ar");
CLSharedLocalisedResources.addResourceForKeyLanguage(new CLNumberFormat(",", ".", "\u20AC", true), "number", "ar");

CLSharedLocalisedResources.addResourceForKeyLanguage("русский", "label", "ru");
CLSharedLocalisedResources.addResourceForKeyLanguage(new CLDateFormat(
	[ [ CLNone, "" ], [ CLWeekday, ", " ], [ CLDay, " " ], [ CLMonth, " " ], [ CLYear, "" ] ],
	[ CLDay, CLMonth, CLYear ], "/", true, true, true,
	[ "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" ], 
	[ "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday" ]), "date", "ru");
CLSharedLocalisedResources.addResourceForKeyLanguage(new CLTimeFormat(true, false, "", "", ":", false), "time", "ru");
CLSharedLocalisedResources.addResourceForKeyLanguage(new CLNumberFormat(",", ".", "\u20AC", true), "number", "ru");

CLSharedLocalisedResources.addResourceForKeyLanguage("magyar", "label", "hu");
CLSharedLocalisedResources.addResourceForKeyLanguage(new CLDateFormat(
	[ [ CLNone, "" ], [ CLWeekday, ", " ], [ CLDay, " " ], [ CLMonth, " " ], [ CLYear, "" ] ],
	[ CLDay, CLMonth, CLYear ], "/", true, true, true,
	[ "Január","Február","Március","Április","Május","Június","Július","Augusztus","Szeptember","Október","November","December" ], 
	[ "Hétfő","Kedd","Szerda","Csütörtök","Péntek","Szombat","Vasárnap" ]), "date", "hu");
CLSharedLocalisedResources.addResourceForKeyLanguage(new CLTimeFormat(true, false, "", "", ":", false), "time", "hu");
CLSharedLocalisedResources.addResourceForKeyLanguage(new CLNumberFormat(",", ".", "\u20AC", true), "number", "hu");



CLSharedLocalisedResources.addResourceForKeyLanguage("English", "label", "en");
CLSharedLocalisedResources.addResourceForKeyLanguage(new CLDateFormat(
	[ [ CLNone, "" ], [ CLWeekday, ", " ], [ CLDay, " " ], [ CLMonth, " " ], [ CLYear, "" ] ],
	[ CLDay, CLMonth, CLYear ], "/", true, true, true,
	[ "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" ], 
	[ "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday" ]), "date", "en");
CLSharedLocalisedResources.addResourceForKeyLanguage(new CLTimeFormat(true, false, "", "", ":", false), "time", "en");
CLSharedLocalisedResources.addResourceForKeyLanguage(new CLNumberFormat(",", ".", "\u20AC", true), "number", "en");


CLSharedLocalisedResources.addResourceForKeyLanguage("Finnish", "label", "fi");
CLSharedLocalisedResources.addResourceForKeyLanguage(new CLDateFormat(
	[[CLNone, ""], [CLWeekday, ", "], [CLDay, " "], [CLMonth, " "], [CLYear, ""]],
	[CLDay, CLMonth, CLYear], "/", true, true, true,
	["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
	["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"]), "date", "en");
CLSharedLocalisedResources.addResourceForKeyLanguage(new CLTimeFormat(true, false, "", "", ":", false), "time", "fi");
CLSharedLocalisedResources.addResourceForKeyLanguage(new CLNumberFormat(",", ".", "\u20AC", true), "number", "fi");


CLSharedLocalisedResources.addResourceForKeyLanguage("Portuguese", "label", "pt");
CLSharedLocalisedResources.addResourceForKeyLanguage(new CLDateFormat(
	[[CLNone, ""], [CLWeekday, ", "], [CLDay, " "], [CLMonth, " "], [CLYear, ""]],
	[CLDay, CLMonth, CLYear], "/", true, true, true,
	["Janeiro",	"Fevereiro",	"Março",	"Abril",	"Maio",	"Junho",	"Julho",	"Agosto",	"Setembro",	"Outubro",	"Novembro",	"Dezembro"],
	["Segunda-Feira", "Terça-Feira", "Quarta-Feira", "Quinta-Feira", "Sexta-Feira", "Sábado", "Domingo"]), "date", "pt");
CLSharedLocalisedResources.addResourceForKeyLanguage(new CLTimeFormat(true, false, "", "", ":", false), "time", "pt");
CLSharedLocalisedResources.addResourceForKeyLanguage(new CLNumberFormat(",", ".", "\u20AC", true), "number", "pt");


CLSharedLocalisedResources.addResourceForKeyLanguage("Polski", "label", "pl");
CLSharedLocalisedResources.addResourceForKeyLanguage(new CLDateFormat(
        [[CLNone, ""], [CLWeekday, ", "], [CLDay, " "], [CLMonth, " "], [CLYear, ""]],
        [CLDay, CLMonth, CLYear], "/", true, true, true,
        ["Styczeń", "Luty", "Marzec", "Kwiecień", "Maj", "Czerwiec", "Lipiec", "Sierpień", "Wrzesień", "Październik", "Listopad", "Grudzień"],
        ["Poniedziałek", "Wtorek", "Środa", "Czwartek", "Piątek", "Sobota", "Niedziela"]), "date", "pl");
CLSharedLocalisedResources.addResourceForKeyLanguage(new CLTimeFormat(true, false, "", "", ":", false), "time", "pl");
CLSharedLocalisedResources.addResourceForKeyLanguage(new CLNumberFormat(",", ".", "\u20AC", true), "number", "pl");


CLSharedLocalisedResources.addResourceForKeyLanguage("čeština", "label", "cs");
CLSharedLocalisedResources.addResourceForKeyLanguage(new CLDateFormat(
        [[CLNone, ""], [CLWeekday, ", "], [CLDay, " "], [CLMonth, " "], [CLYear, ""]],
        [CLDay, CLMonth, CLYear], "/", true, true, true,
        ["leden", "únor", "březen", "duben", "květen", "červen", "červenec", "srpen", "září", "říjen", "listopad", "prosinec"],
        ["pondělí", "úterý", "středa", "čtvrtek", "pátek", "sobota ", "neděle"]), "date", "cs");
CLSharedLocalisedResources.addResourceForKeyLanguage(new CLTimeFormat(true, false, "", "", ":", false), "time", "cs");
CLSharedLocalisedResources.addResourceForKeyLanguage(new CLNumberFormat(",", ".", "\u20AC", true), "number", "cs");


CLSharedLocalisedResources.addResourceForKeyLanguage("slovenčina", "label", "sk");
CLSharedLocalisedResources.addResourceForKeyLanguage(new CLDateFormat(
        [[CLNone, ""], [CLWeekday, ", "], [CLDay, " "], [CLMonth, " "], [CLYear, ""]],
        [CLDay, CLMonth, CLYear], "/", true, true, true,
        ["január", "február", "marec", "apríl", "máj", "jún", "júl", "august", "september", "október", "november", "december"],
        ["pondelok", "utorok", "streda", "stvrtok", "piatok", "sobota", "nedela"]), "date", "sk");
CLSharedLocalisedResources.addResourceForKeyLanguage(new CLTimeFormat(true, false, "", "", ":", false), "time", "sk");
CLSharedLocalisedResources.addResourceForKeyLanguage(new CLNumberFormat(",", ".", "\u20AC", true), "number", "sk");
//*************************** Localization

CLSharedLocalisedResources.addResourceForKeyLanguage("Dutch", "label", "nl");
CLSharedLocalisedResources.addResourceForKeyLanguage(new CLDateFormat(
	[[CLNone, ""], [CLWeekday, ", "], [CLDay, " "], [CLMonth, " "], [CLYear, ""]],
	[CLDay, CLMonth, CLYear], "/", true, true, true,
	["Januari", "Februari", "Maart", "April", "Mei", "Juni", "Juli", "Augustus", "September", "Oktober", "November", "December"],
	["Maandag", "Dinsdag", "Woensdag", "Donderdag", "Vrijdag", "Zaterdag", "Zondag"]), "date", "nl");
CLSharedLocalisedResources.addResourceForKeyLanguage(new CLTimeFormat(true, false, "", "", ":", false), "time", "nl");
CLSharedLocalisedResources.addResourceForKeyLanguage(new CLNumberFormat(",", ".", "\u20AC", true), "number", "nl");


// Default resources

// Convenience functions
function CLLocaliseDate(inDate) { return CLSharedLocalisedResources.resourceForKey("date").localiseDate(inDate); }
function CLLocaliseTime(inTime) { return CLSharedLocalisedResources.resourceForKey("time").localiseTime(inTime); }
function CLLocaliseNumber(inNumber, inFormat, inUnits, inBeforeNumber)
{
	return CLSharedLocalisedResources.resourceForKey("number").localiseNumber(inNumber, inFormat, inUnits, inBeforeNumber);
}

// Format objects
function CLDateFormat(inLongDateStructure, inShortDateStructure, inSeparator, inLeadingZeroForDay, inLeadingZeroForMonth, inShowCentury, inMonths, inDays, inDaySuffix)
{
	this.longDateStructure = inLongDateStructure;
	this.shortDateStructure = inShortDateStructure;
	
	this.months = inMonths;
	this.days = inDays;
	this.daySuffix = inDaySuffix;
	
	this.leadingZeroForDay = inLeadingZeroForDay || false;
	this.leadingZeroForMonth = inLeadingZeroForMonth || false;
	this.showCentury = inShowCentury || false;
	
	this.separator = inSeparator || "/";
	
	this.localiseDate = function(inDate) { return this.localiseLongDate(inDate); }
	this.localiseShortDate = function(inDate)
	{
		var dateSegments = new Array();
		var outString;
		
		dateSegments[0] = "";
		if(this.showCentury) dateSegments[1] = inDate.getFullYear();
		else dateSegments[1] = inDate.getYear();
		dateSegments[2] = inDate.getMonth() + 1;
		if(this.leadingZeroForMonth && dateSegments[2] < 10) dateSegments[2] = "0" + dateSegments[2];
		dateSegments[3] = inDate.getDate();
		if(this.leadingZeroForDay && dateSegments[3] < 10) dateSegments[3] = "0" + dateSegments[3];
		dateSegments[4] = "";
		
		outString = dateSegments[this.shortDateStructure[0]];
		outString += this.separator +dateSegments[this.shortDateStructure[1]];
		outString += this.separator + dateSegments[this.shortDateStructure[2]];
		
		return outString;
	}
	
	this.localiseLongDate = function(inDate)
	{
		var outString;
		var dateSegments = new Array();
		
		dateSegments[0] = "";
		if(this.showCentury) dateSegments[1] = inDate.getFullYear();
		else dateSegments[1] = inDate.getYear();
		dateSegments[2] = this.months[inDate.getMonth()];
		dateSegments[3] = inDate.getDate();
		dateSegments[4] = this.days[inDate.getDay()];
		
		outString = dateSegments[this.longDateStructure[0][0]] + this.longDateStructure[0][1];
		outString += dateSegments[this.longDateStructure[1][0]] + this.longDateStructure[1][1];
		outString += dateSegments[this.longDateStructure[2][0]] + this.longDateStructure[2][1];
		outString += dateSegments[this.longDateStructure[3][0]] + this.longDateStructure[3][1];
		outString += dateSegments[this.longDateStructure[4][0]] + this.longDateStructure[4][1];
		
		return outString;
	}
}

function CLTimeFormat(inTwentyFourHourClock, inZeroNoonAndMidnight, inBeforeNoon, inAfterNoon, inSeparator, inLeadingZeroForHour)
{
	this.twentyFourHourClock = (inTwentyFourHourClock != null) ? inTwentyFourHourClock : true;
	this.zeroNoonAndMidnight = (inZeroNoonAndMidnight != null) ? inZeroNoonAndMidnight : false;
	this.beforeNoon = inBeforeNoon;
	this.afterNoon = inAfterNoon;
	this.separator = inSeparator || ":";
	this.leadingZeroForHour = inLeadingZeroForHour;
	
	this.localiseTime = function(inTime) { return this.localiseTimeWithSeconds(inTime, false); }
	this.localiseTimeWithSeconds = function(inTime, inSeconds)
	{
		var outString;
		var hours, minutes, seconds, suffix;

		if(inSeconds == null) inSeconds = true;

		hours = inTime.getHours();
		minutes = inTime.getMinutes();

		if(this.twentyFourHourClock)
		{
			if(this.leadingZeroForHour && hours > 9)
				outString = "0" + String(hours);
			else
				outString = String(hours);

			if(this.beforeNoon == this.afterNoon) suffix = this.beforeNoon;
		}
		else
		{
			if(hours > 12)
			{
				hours -= 12;
				suffix = this.afterNoon;
			}
			else if(hours == 12 && this.zeroForNoonAndMidnight)
			{
				hours = 0;
				suffix = timeFormat.beforeNoon;
			}
			else if(hours == 0 && !this.zeroForNoonAndMidnight)
			{
				hours = 12;
				suffix = this.afterNoon;
			}
			else
				suffix = this.beforeNoon;

			if(this.leadingZeroForHour && hours > 9)
				outString = "0" + String(hours);
			else
				outString = String(hours);
		}

		outString += this.separator;

		if(minutes > 9) outString += String(minutes);
		else outString += "0" + String(minutes);

		if(inSeconds)
		{
			outString += this.separator;

			seconds = inTime.getSeconds();

			if(seconds > 9) outString += String(seconds);
			else outString += "0" + String(seconds);
		}

		if(suffix) outString += suffix;

		return outString;
	}
}

function CLNumberFormat(inDecimal, inThousands, inCurrencySymbol, inBeforeNumber)
{
	this.decimal = inDecimal;
	this.thousands = inThousands;
	this.currencySymbol = inCurrencySymbol;
	this.beforeNumber = inBeforeNumber;
	
	this.localiseNumber = function(inNumber, inType, inUnits, inBeforeNumber)
	{
		var outString;
		var fix, prefix, suffix;
		var n;

		if(inType == null) inType = "general";
		if(inUnits == null) inUnits = "";

		if(inType == "currency") fix = 2;
		else if(inType.substring(0, 4) == "fix ") fix = parseInt(inType.substring(4));
		else fix = -1;

		if(inUnits != "")
		{
			if(inUnits.indexOf("0") > -1)
			{
				prefix = inUnits.substring(0, inUnits.indexOf("0"));
				suffix = inUnits.substring(inUnits.indexOf("0") + 1);
			}
			else
			{
				prefix = "";
				suffix = inUnits;
			}
		}
		else
		{
			prefix = "";
			suffix = "";

			if(inType == "currency")
			{
				if(this.beforeNumber) prefix = this.currencySymbol;
				else suffix = this.currencySymbol;
			}
		}

		n = String(inNumber);

		if(fix > -1)
		{
			if(n.indexOf(".") == -1) n += ".";
			
			if(n.length > n.indexOf(".") + fix)
			{
				n = n.substring(0, n.indexOf(".") + fix + 1);
				if(fix == 0) n = n.substring(0, n.length - 1);
			}
			else
			{
				while(n.length - n.indexOf(".") - 1 < fix) n += "0";
			}
		}

		if(n.indexOf(".") > -1)
		{
			suffix = this.decimal + n.substring(n.indexOf(".") + 1) + suffix;
			n = n.substring(0, n.indexOf("."));
		}

		outString = "";
		while(n.length > 3)
		{
			outString = this.thousands + n.substring(n.length - 3) + outString;
			n = n.substring(0, n.length - 3);
		}
		outString = n + outString;

		if(inNumber < 0)
			outString = "/" + prefix + outString.substring(1) + suffix;
		else
			outString = prefix + outString + suffix;

		return outString;
	}
}

function CLLocalisedText(inText, inGender, inPlural)
{
	this.text = inText;
	this.gender = inGender;
	this.plural = inPlural;
	
	this.forms = new Array();
	
	this.toString = function() { return this.text; }
	this.addForm = function(inText, inGender, inPlural) { this.forms[this.forms.length] = new CLLocalisedText(inText, inGender, inPlural); }
	this.formForGender = function(inGender)
	{
		if(this.gender == inGender) return this;
		for(var i = 0; i < this.forms.length; i++) if(this.forms[i].gender == inGender) return this.forms[i];
		return this;
	}
	this.formForGenderPlural = function(inGender, inPlural)
	{
		var genderMatch, pluralMatch;
		if(this.gender == inGender && this.plural == inPlural) return this;
		for(var i = 0; i < this.forms.length; i++)
		{
			if(this.forms[i].gender == inGender)
			{
				if(this.forms[i].plural == inPlural) return this.forms[i];
				else genderMatch = this.forms[i].plural;
			}
			else if(this.forms[i].plural == inPlural) pluralMatch = this.forms[i].plural;
		}
		
		if(genderMatch) return genderMatch;
		else if(pluralMatch) return pluralMatch;
		else return this;
	}
}

// Localised resource container object
function CLLocalisedResources()
{
	this.defaultLanguage = "en";
	this.setDefaultLanguage = function(inLanguage) { this.defaultLanguage = inLanguage.replace("-", "_"); }
	
	this._resources = new Array();
	this.addResourceForKeyLanguage = function(inResource, inKey, inLanguage)
	{
		inLanguage = inLanguage.replace("-", "_");
		if(!this._resources[inLanguage]) this._resources[inLanguage] = new Array();
		this._resources[inLanguage][inKey] = inResource;
	}
	
	this.resourceForKey = function(inKey) { return this.resourceForKeyLanguage(inKey, null); }
	this.resourceForKeyLanguage = function(inKey, inLanguage)
	{
		if(inLanguage) inLanguage = inLanguage.replace("-", "_");
		
		if(inLanguage)
		{
			if(this._resources[inLanguage] && this._resources[inLanguage][inKey]) return this._resources[inLanguage][inKey];
			else if(this._resources[inLanguage.substring(0, 2)] && this._resources[inLanguage.substring(0, 2)][inKey])
			{
				//this._resources[inLanguage][inKey] = this._resources[inLanguage.substring(0, 2)][inKey];
				return this._resources[inLanguage.substring(0, 2)][inKey];
			}
			else if(this._resources[this.defaultLanguage][inKey])
				return this._resources[this.defaultLanguage][inKey];
			else if(this._resources[this.defaultLanguage.substring(0, 2)][inKey])
			{
				this._resources[this.defaultLanguage][inKey] = this._resources[this.defaultLanguage.substring(0, 2)][inKey];
				return this._resources[this.defaultLanguage.substring(0, 2)][inKey];
			}
		}
		else
		{
			if(this._resources[this.defaultLanguage][inKey])
				return this._resources[this.defaultLanguage][inKey];
			else if(this._resources[this.defaultLanguage.substring(0, 2)][inKey])
			{
				this._resources[this.defaultLanguage][inKey] = this._resources[this.defaultLanguage.substring(0, 2)][inKey];
				return this._resources[this.defaultLanguage.substring(0, 2)][inKey];
			}
		}

		return null;
	}
	
	this.parseStringForKeyWith = function(inKey, inValues) { return this.parseStringForKeyLanguageWith(inKey, null, inValues); }
	this.parseStringForKeyLanguageWith = function(inKey, inLanguage, inValues)
	{
		var outString = this.resourceForKeyLanguage(inKey, inLanguage);
		for(var i = 0; i < inValues.length; i++) outString = outString.replace(new RegExp("\\$" + (i + 1), "g"), inValues[i]);
		return outString;
	}
}










// Constants
var CLDaysInMonth = new Array(31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);

function CLSetFormDelegate(inForm, inDelegate) { inForm.delegate = inDelegate; }

function CLSetRequiredFields(inForm, inList)
{
	var i, j;
	
	inList += ","; // add a separator to the end
	inList = inList.replace(" ", ""); // remove all spaces
	
	j = inList.indexOf(",");
	while(j > -1)
	{
		eval("inForm." + inList.substring(0, j) + ".required = true;");
		inList = inList.substring(j + 1);
		
		j = inList.indexOf(",");
	}
}

function CLSetHighlight(inForm, inHighlight, inNoHighlight)
{
	if(inHighlight != null) inForm.highlight = inHighlight.replace(" ", "");
	if(inNoHighlight != null) inForm.nohighlight = inNoHighlight.replace(" ", "");
}

function CLValidateForm(inForm, inStandardiseFields)
{
	var i, outValid;
	var onchangeHandler;
	
	outValid = true;
	
	// Check each fields onchange handler to see if a formatter is used
	// If so extract just the format function call and execute it. By extracting
	// only the format function call we avoid recussion problems.
	
	// This fixes a problem on browsers that do not call the onchange handler
	// for a field when the form is submited whilst it is being edited.
	
	for(i = 0; i < inForm.length; i++)
	{
		if(inForm[i].onchange)
		{
			onchangeHandler = inForm[i].onchange.toString();
			if(onchangeHandler.indexOf("format") > -1)
			{
				onchangeHandler = onchangeHandler.substring(onchangeHandler.indexOf("CLFormat"));
				if(onchangeHandler.indexOf(";") > -1) onchangeHandler = onchangeHandler.substring(0, onchangeHandler.indexOf(";"));
				if(onchangeHandler.indexOf("}") > -1) onchangeHandler = onchangeHandler.substring(0, onchangeHandler.indexOf("}"));
				if(onchangeHandler.indexOf("CLFormatDate") == 0 || onchangeHandler.indexOf("CLFormatTime") == 0 || onchangeHandler.indexOf("CLFormatNumber") == 0)
				{
					if(onchangeHandler.indexOf("document.forms") == -1)
						onchangeHandler = onchangeHandler.substring(0, onchangeHandler.indexOf("(") + 1) + "document.forms." + onchangeHandler.substring(onchangeHandler.indexOf("(") + 1);
					eval(onchangeHandler);
				}
			}
		}
		
		if(inForm[i].required)
		{
			if(inForm[i].required == true && inForm[i].value == "")
			{
				addHighlight(inForm, inForm[i]);
				outValid = false;
			}
		}
		
		if(inForm[i].invalid == true)
		{
			// field should have already been highlighted by the formatter
			outValid = false;
		}
	}
	
	// remove all formatting from number fields and change dates to d-m-yyyy if the form is valid to
	// aid parsing by server scripts
	if(outValid && inStandardiseFields)
	{
		for(i = 0; i < inForm.length; i++)
		{
			if(inForm[i].actualValue)
			{
				if(inForm[i].onchange) onchangeHandler = inForm[i].onchange.toString();
				else onchangeHandler = "";
				
				if(onchangeHandler.indexOf("CLFormatNumber") > -1)
					inForm[i].value = String(inForm[i].actualValue);
				else if(onchangeHandler.indexOf("CLFormatDate") > -1)
					inForm[i].value = inForm[i].actualValue.getDate() + "/" + (inForm[i].actualValue.getMonth() + 1) + "/" + inForm[i].actualValue.getFullYear();
				else if(onchangeHandler.indexOf("CLFormatTime") > -1)
					inForm[i].value = inForm[i].actualValue.getHours() + ":" + inForm[i].actualValue.getMinutes() + ":" + inForm[i].actualValue.getSeconds();
			}
		}
	}
	
	return outValid;
}

function CLFormatNumber(inForm, inField, inNumberFormat, inType, inUnits, inMin, inMax)
{
	var inValue, outValue, fix, prefix, suffix;
	var i, c;
	
	if(inNumberFormat == null) inNumberFormat = CLSharedLocalisedResources.resourceForKey("number");
	if(inType == null) inType = "general";
	if(inUnits == null) inUnits = "";
	
	eval("inField = inForm." + inField + ";");
	inValue = inField.value;
	if(inValue == "")
	{
		if(!inField.required)
		{
			removeHighlight(inForm, inField);
			inField.invalid = false;
			inField.actualValue = null;
		}
		else
		{
			addHighlight(inForm, inField);
			inField.invalid = true;
			inField.actualValue = null;
		}
		
		return true;
	}
	
	if(inType == "currency") fix = 2;
	else if(inType.substring(0, 4) == "fix ") fix = parseInt(inType.substring(4));
	else fix = -1;
	
	if(inUnits != "")
	{
		if(inUnits.indexOf("0") > -1)
		{
			prefix = inUnits.substring(0, inUnits.indexOf("0"));
			suffix = inUnits.substring(inUnits.indexOf("0") + 1);
		}
		else
		{
			prefix = "";
			suffix = inUnits;
		}
	}
	else
	{
		prefix = "";
		suffix = "";
		
		if(inType == "currency")
		{
			if(inNumberFormat.beforeNumber) prefix = inNumberFormat.currencySymbol;
			else suffix = inNumberFormat.currencySymbol;
		}
	}
	
	if(prefix != "") inValue = inValue.replace(prefix, "");
	if(suffix != "") inValue = inValue.replace(suffix, "");
	
	if(inValue.charAt(0) == "=")
	{
		for(i = 0; i < inValue.length; i++)
		{
			c = inValue.charAt(i);
			if((inNumberFormat.decimal + inNumberFormat.thousands + "0123456789=-+*/() ").indexOf(c) == -1)
			{
				addHighlight(inForm, inField);
				inField.invalid = true;
				return false;
			}
		}
		while(inValue.indexOf(inNumberFormat.thousands) > -1)
			inValue = inValue.replace(inNumberFormat.thousands, "");
		if(inNumberFormat.decimal != ".") inValue = inValue.replace(inNumberFormat.decimal, ".");
		eval("outValue" + inValue);
		outValue = String(outValue);
	}
	else
	{
		for(i = 0; i < inValue.length; i++)
		{
			c = inValue.charAt(i);
			if((c < "0" || c > "9") && c != "e" && c != "+" && c != "/" && c != inNumberFormat.decimal && c != inNumberFormat.thousands)
			{
				addHighlight(inForm, inField);
				inField.invalid = true;
				return false;
			}
		}
		
		while(inValue.indexOf(inNumberFormat.thousands) > -1)
			inValue = inValue.replace(inNumberFormat.thousands, "");
		if(inNumberFormat.decimal != ".") inValue = inValue.replace(inNumberFormat.decimal, ".");
		outValue = String(parseFloat(inValue));
	}
	
	if(inMin && parseFloat(outValue) < inMin) outValue = String(inMin);
	else if(inMax && parseFloat(outValue) > inMax) outValue = String(inMax);
	
	// Create a property: actualValue that contains the parsed but not formatted value
	inField.actualValue = parseFloat(outValue);
	
	if(outValue == "NaN")
	{
		addHighlight(inForm, inField);
		inField.invalid = true;
		return false;
	}
	
	inField.value = inNumberFormat.localiseNumber(inField.actualValue, inType, inUnits);
	removeHighlight(inForm, inField);
	inField.invalid = false;
	return true;
}

function CLFormatDate(inForm, inField, inDateFormat, inShort, inMin, inMax)
{
	var day = -1, month = -1, year = -1, weekday = -1;
	var inValue, outValue, segment, endOfSegment;
	var i, j, c;
	
	// private function
	function matchSegmentToMonth(inSegment)
	{
		for(var i = 0; i < 12; i++)
		{
			if(inSegment.toLowerCase() == inDateFormat.months[i].substring(0, 3).toLowerCase()) return i + 1;
			if(inSegment.toLowerCase() == inDateFormat.months[i].toLowerCase()) return i + 1;
		}

		return 0;
	}

	// private function
	function matchSegmentToWeekday(inSegment)
	{
		for(var i = 0; i < 7; i++)
		{
			if(inSegment.toLowerCase() == inDateFormat.days[i].substring(0, 3).toLowerCase()) return i;
			if(inSegment.toLowerCase() == inDateFormat.days[i].toLowerCase()) return i;
		}
		
		return -1;
	}

	// private function
	function matchSegmentToDaySuffix(inSegment)
	{
		if(!inDateFormat.daySuffix) return -1;

		for(var i = 0; i < 4; i++)
		{
			if(inSegment.toLowerCase() == inDateFormat.daySuffix[i].toLowerCase()) return i;
		}

		return -1;
	}
	
	if(inDateFormat == null) inDateFormat = CLSharedLocalisedResources.resourceForKey("date");
	
	eval("inField = inForm." + inField + ";");
	inValue = inField.value;
	if(inValue == "")
	{
		if(!inField.required)
		{
			removeHighlight(inForm, inField);
			inField.invalid = false;
			inField.actualValue = null;
		}
		else
		{
			addHighlight(inForm, inField);
			inField.invalid = true;
			inField.actualValue = null;
		}

		return true;
	}
	
	// Parse the field value for a day month and year
	inValue += " "; // The extra space is to ensure the value ends on an end of segment marker
	segment = "";
	endOfSegment = false;
	for(i = 0; i < inValue.length; i++)
	{
		c = inValue.charAt(i).toLowerCase();
		
		if((c >= "a" && c <= "z") || c >= String.fromCharCode(192))
		{
			if(segment.length > 0 && segment.charAt(0) >= "0" && segment.charAt(0) <= "9")
				endOfSegment = true;
			else
				segment += c;
		}
		else if(c >= "0" && c <= "9")
		{
			if(segment.length > 0 && (segment.charAt(0) < "0" || segment.charAt(0) > "9"))
				endOfSegment = true;
			else
				segment += c;
		}
		else
			endOfSegment = true;
		
		if(endOfSegment)
		{
			endOfSegment = false;
			
			if(segment.length > 0)
			{
				if(segment.charAt(0) >= "a" && segment.charAt(0) <= "z") // Segment is alphabetical
				{
					j = matchSegmentToMonth(segment);
					if(j != 0)
					{
						if(month == -1) month = j;
						else
						{
							// too many segments, generate error
							addHighlight(inForm, inField);
							inField.invalid = true;
							return false;
						}
					}
					else
					{
						j = matchSegmentToWeekday(segment);
						if(j != -1) weekday = j;
						else if(matchSegmentToDaySuffix(segment) == -1)
						{
							// Invalid segment, generate error
							addHighlight(inForm, inField);
							inField.invalid = true;
							return false;
						}
					}
				}
				else // Segment is numerical
				{
					var components = 0;
					// Order of numerically supplied date components is important.
					// Order must be: day, month, year
					
					j = parseInt(segment, 10);
					
					if(day > -1) components++;
					if(month > -1) components++;
					if(year > -1) components++;
					
					if(components < 3)
					{
						switch(inDateFormat.shortDateStructure[components])
						{
							case CLDay:
								day = j;
								break;
								
							case CLMonth:
								month = j;
								break;
							
							case CLYear:
								year = j;
								break;
						}
					}
					else
					{
						// too many segments, generate error
						addHighlight(inForm, inField);
						inField.invalid = true;
						return false;
					}
				}
			}
			
			if((c >= "a" && c <= "z") || (c >= "0" && c <= "9")) segment = c;
			else segment = "";
		}
	}
	
	// Fill out 2 digit years
	if(year >= 0 && year < 50) year += 2000;
	if(year >= 50 && year <= 99) year += 1900;
	
	// Fill in missing information using the current date
	var today = new Date();
	if(weekday > -1 && day == -1 && month == -1 && year == -1)
	{
		// Work out the date based on the week day
		inField.actualValue = new Date(today.getTime() + (weekday - today.getDay()) * 24 * 60 * 60 * 1000);
	}
	else
	{
		if(day == -1) day = today.getDate();
		if(month == -1) month = today.getMonth() + 1;
		if(year == -1) year = today.getFullYear();
	
		// Validate day & month values
		if(month < 1 || month > 12)
		{
			addHighlight(inForm, inField);
			inField.invalid = true;
			return false;
		}

		daysInMonth = CLDaysInMonth[month - 1];
		if(month == 2 && year % 100 == 0) { if(year % 400 > 0) daysInMonth--; }
		else if(month ==2 && year % 4 > 0) daysInMonth--;

		if(day < 1 || day > CLDaysInMonth[month - 1])
		{
			addHighlight(inForm, inField);
			inField.invalid = true;
			return false;
		}
	
		// Create a property: actualValue that contains the parsed but not formatted value
		inField.actualValue = new Date(year, month - 1, day, 0, 0, 0, 0);
	}
	
	if(inMin && inField.actualValue.getTime() < inMin.getTime()) inField.actualValue = inMin;
	else if(inMax && inField.actualValue.getTime() > inMax.getTime()) inField.actualValue = inMax;

	removeHighlight(inForm, inField);
	inField.invalid = false;
	
	inField.value = inDateFormat.localiseLongDate(inField.actualValue);
	return true;
}

function CLFormatTime(inForm, inField, inTimeFormat, inMin, inMax)
{
	var hour = -1, minute = -1, second = -1, suffix = -1;
	var inValue, outValue, segment, endOfSegment;
	var i, j, c;

	// private function
	function matchSegmentToTimeSuffix(inSegment)
	{
		if(inSegment.toLowerCase() == inTimeFormat.beforeNoon.toLowerCase().replace(" ", "")) return 0;
		else if(inSegment.toLowerCase() == inTimeFormat.afterNoon.toLowerCase().replace(" ", "")) return 1;
		else return -1;
	}
	
	if(!inTimeFormat) inTimeFormat = CLSharedLocalisedResources.resourceForKey("time");
	
	eval("inField = inForm." + inField + ";");
	inValue = inField.value;
	if(inValue == "")
	{
		if(!inField.required)
		{
			removeHighlight(inForm, inField);
			inField.invalid = false;
			inField.actualValue = null;
		}
		else
		{
			addHighlight(inForm, inField);
			inField.invalid = true;
			inField.actualValue = null;
		}

		return true;
	}

	// Parse the field value for a day month and year
	inValue += " "; // The extra space is to ensure the value ends on an end of segment marker
	segment = "";
	endOfSegment = false;
	for(i = 0; i < inValue.length; i++)
	{
		c = inValue.charAt(i).toLowerCase();
		if(c >= "a" && c <= "z")
		{
			if(segment.length > 0 && segment.charAt(0) >= "0" && segment.charAt(0) <= "9")
				endOfSegment = true;
			else
				segment += c;
		}
		else if(c >= "0" && c <= "9")
		{
			if(segment.length > 0 && segment.charAt(0) >= "a" && segment.charAt(0) <= "z")
				endOfSegment = true;
			else
				segment += c;
		}
		else
			endOfSegment = true;
		
		if(endOfSegment)
		{
			endOfSegment = false;
			
			if(segment.length > 0)
			{
				if(segment.charAt(0) >= "a" && segment.charAt(0) <= "z") // Segment is alphabetical
				{
					suffix = matchSegmentToTimeSuffix(segment);
					if(suffix == -1)
					{
						// Invalid segment, generate error
						addHighlight(inForm, inField);
						inField.invalid = true;
						return false;
					}
				}
				else // Segment is numerical
				{
					// Order of numerically supplied date components is important.
					// Order must be: hour, minute, second
					
					j = parseInt(segment, 10);
					
					if(hour == -1) hour = j;
					else if(minute == -1) minute = j;
					else if(second == -1) second = j;
					else
					{
						// too many segments, generate error
						addHighlight(inForm, inField);
						inField.invalid = true;
						return false;
					}
				}
			}
			
			if((c >= "a" && c <= "z") || (c >= "0" && c <= "9")) segment = c;
			else segment = "";
		}
	}
	
	// Fill in missing information using the current date
	var today = new Date();
	if(hour == -1) hour = today.getHour();
	if(minute == -1) minute = today.getMinutes();
	if(second == -1) second = today.getSeconds();
	
	// Validate hour, minute and second values
	if(hour < 0 || hour > 24 || minute < 0 || minute > 59 || second < 0 || second > 59)
	{
		addHighlight(inForm, inField);
		inField.invalid = true;
		return false;
	}
	
	// Ensure hour is in 24 hour format
	if(hour == 24) hour = 0;
	if(hour < 12 && suffix == 1) hour += 12;
	
	// Create a property: actualValue that contains the parsed but not formatted value
	inField.actualValue = new Date(0, 0, 0, hour, minute, second, 0);
	
	if(inMin && inField.actualValue.getTime() < inMin.getTime()) inField.actualValue = inMin;
	else if(inMax && inField.actualValue.getTime() > inMax.getTime()) inField.actualValue = inMax;
	
	removeHighlight(inForm, inField);
	inField.invalid = false;
	inField.value = inTimeFormat.localiseTime(inField.actualValue);
	return true;
}

function addHighlight(inForm, inField)
{
	var attribute, value
	
	if(document.images[inForm.name + inField.name])
		document.images[inForm.name + inField.name].src = "media/small-warning.gif";
	
	if(!inField.style) return;
	
	if(inForm.highlight == null)
	{
		attribute = "background";
		value = "";
	}
	else
	{
		attribute = inForm.highlight.substring(0, inForm.highlight.indexOf(":"));
		value = inForm.highlight.substring(inForm.highlight.indexOf(":") + 1);
	}
	
	eval("inField.style." + attribute + " = \"" + value + "\";");
}

function removeHighlight(inForm, inField)
{
	var attribute, value
	
	if(document.images[inForm.name + inField.name])
		document.images[inForm.name + inField.name].src = "media/small-no-warning.gif";
	
	if(!inField.style) return;
	
	if(inForm.nohighlight == null)
	{
		attribute = "background";
		value = "#FFFFFF";
	}
	else
	{
		attribute = inForm.nohighlight.substring(0, inForm.nohighlight.indexOf(":"));
		value = inForm.nohighlight.substring(inForm.nohighlight.indexOf(":") + 1);
	}
	
	eval("inField.style." + attribute + " = \"" + value + "\";");
}

var _CLTimers = new Array()

function CLInvocation(inTarget, inMethod, inParameters)
{
	// Data
	this.target = inTarget;
	this.method = inMethod;
	this.parameters = inParameters;
	this.returnValue = null;
	
	// Methods
	this.setTarget = function(inTarget) { this.target = inTarget; }
	this.setMethod = function(inMethod) { this.method = inMethod; }
	this.setParameters = function(inParameters) { this.parameters = inParameters; }
	
	this.setParameterAtIndex = function(inParameter, inIndex)
	{
		if(!this.parameters) this.parameters = new Array();
		this.parameters[inIndex] = inParameter;
	}
	
	this.parameterAtIndex = function(inIndex)
	{
		if(!this.parameters) return null;
		else return this.parameters[inIndex];
	}
	
	this.invoke = function()
	{
		// Optimised for invocations with less than 3 parameters
		if(!this.parameters) { this.returnValue = this.method.call(this.target); return; }
		switch(this.parameters.length)
		{
			case 1:
				this.returnValue = this.method.call(this.target, this.parameters[0]);
				break;
			
			case 2:
				this.returnValue = this.method.call(this.target, this.parameters[0], this.parameters[1]);
				break;
			default:
				var params = "";
				for(var i = 0; i < this.parameters.length; i++)
				{
					params += ", this.parameters[" + i + "]";
				}
				this.returnValue = eval("this.method.call(this.target" + params + ");");
		}
	}
}

function CLTimer(inId, inInvocation, inInterval, inRepeats)
{
	// Data
	this.id = inId;
	this.invocation = inInvocation;
	this.interval = inInterval;
	this.repeats = inRepeats || 0;
	this.active = false;

	// Add this to the list of timers
	_CLTimers[this.id] = this;
	
	// Methods
	this.setInvocation = function(inInvocation) { this.invocation = inInvocation; }
	
	this.start = function()
	{
		this.timeout = window.setTimeout("_CLTriggerTimer(\"" + this.id + "\");", this.interval);
		this.active = true;
	}
	
	this.stop = function()
	{
		window.clearTimeout(this.timeout);
		this.active = false;
	}
}

function _CLTriggerTimer(inTimer)
{
	var aTimer = _CLTimers[inTimer];
	aTimer.invocation.invoke();
	if(aTimer.repeats > 0) aTimer.repeats--;
	if(aTimer.repeats != 0 && aTimer.active) aTimer.timeout = window.setTimeout("_CLTriggerTimer(\"" + aTimer.id + "\");", aTimer.interval);
	else aTimer.active = false;
}

// Constants
var CLDaysInMonth = new Array(31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
var CLSharedPopupCalendar = new CLPopupCalendar("cal", null, false,null,null);

function ParseDate(str)
{
	var y=Number(str.substr(0,4));
	var Mo=Number(str.substr(4,2));
	var d=Number(str.substr(6,2));
	var h=Number(str.substr(8,2));
	var mi=Number(str.substr(10,2));
	var dt=new Date();
	dt.setUTCFullYear(y,Mo-1,d);
	dt.setUTCHours(h,mi);
	return dt;
}

function ParseDateUIToEntity(str)
{
    var dateArr=str.split('/');
    if (dateArr.length!=3)
        return "";
        
	var y=Number(dateArr[2]);
	var Mo=Number(dateArr[1]);
	var d=Number(dateArr[0]);

	var dt=new Date();
	dt.setUTCFullYear(y,Mo-1,d);
	return dt;
}

function HideDDLs()
{
	var DDls=document.getElementsByTagName('SELECT');
	for(i=0;i<DDls.length;i++)
	{
		DDls[i].style.visibility = "hidden";
	}
}

function ShowDDLs()
{
	var DDls=document.getElementsByTagName('SELECT');
	for(i=0;i<DDls.length;i++)
	{
		DDls[i].style.visibility = "visible";
	}
}

function CLCalendarOnMouseUp(inEvent) { CLSharedPopupCalendar.onMouseUp(inEvent); }
function CLCalendarTrackMouseMove(inEvent) { CLSharedPopupCalendar.trackMouseMove(inEvent); }

function CLPopupCalendar(inId, inLanguage, inLiveUpdate, BeginDate, EndDate)
{
	// Data
    this.BeginDate=BeginDate;
    this.EndDate=EndDate;

	this.id = inId;
	this.element = null;
	this.linkedField = null;
	this.useShortDate = false;
	this.language = inLanguage;
	this.liveUpdate = inLiveUpdate;
	this.isSticky = false;
	this.isOpen = false;
	if (this.BeginDate)
	{
	    this.currentDate = this.BeginDate;
	    this.highlightedDate = this.BeginDate;
	}
	else
	{
    	this.currentDate = new Date();
	    this.highlightedDate = new Date();
	}
	
	this._dateFormat = CLSharedLocalisedResources.resourceForKeyLanguage("date", this.language);
	this._hoverElement = null;
	this._timer = new CLTimer(inId, null, 500);
	
	// Methods
	this.setLinkedField = function(inField, inUseShortDate) { this.linkedField = inField; this.useShortDate = inUseShortDate; }
	this.setLanguage = function(inLanguage)
	{
		this.language = inLanguage;
		this._dateFormat = CLSharedLocalisedResources.resourceForKeyLanguage("date", this.language);
	}
	
	this.setSticky = function(inSticky) { this.isSticky = inSticky; }
	
	this.popup = function(inEvent, inLinkedField, inUseShortDate, BeginDate, EndDate, inLinkedFieldFromStartDate)
	{
	    this.BeginDate=BeginDate;
        this.EndDate=EndDate;

		if(inLinkedFieldFromStartDate)
		{
		    newBeginDate = ParseDateUIToEntity(inLinkedFieldFromStartDate.value);
		    if(newBeginDate != "" && newBeginDate > this.BeginDate)
		    {
        	    this.BeginDate = newBeginDate;
        	    inLinkedField.value=newBeginDate

			    inLinkedField.actualValue = newBeginDate;
    		    inLinkedField.value = this._dateFormat.localiseShortDate(newBeginDate);
        	}
		}

		if(inLinkedField) this.setLinkedField(inLinkedField, inUseShortDate);

		if(this.isOpen) this.close(inEvent);
		else this.open(inEvent);
	}

	this.open = function(inEvent, inDate)
	{
		HideDDLs();
		var x, y;
		if(!inEvent && event) inEvent = event;

		// IE uses documentElement.scroll... netscape uses body.scroll... with the other set to 0
		// so only one will get added.
		x = inEvent.clientX + document.body.scrollLeft + document.documentElement.scrollLeft;
		y = inEvent.clientY + document.body.scrollTop + document.documentElement.scrollTop;
	
		this.isSticky = true;
		this.isOpen = true;
		this._timer.setInvocation(new CLInvocation(this, this.setSticky, [false]));
		this._timer.start();

		if(this.linkedField)
		{
			if(this.linkedField.value && ParseDateUIToEntity(this.linkedField.value)!="")
			{
				this.currentDate = ParseDateUIToEntity(this.linkedField.value);
				this.highlightedDate = ParseDateUIToEntity(this.linkedField.value);
			}
			else if(inDate)
			{
				this.currentDate = new Date(inDate);
				this.highlightedDate = new Date(inDate);
			}
			else
			{
				this.currentDate = new Date();
				this.highlightedDate = new Date();
			}
		}

		// Capture events for IE style event model
		if(document.body.attachEvent)
		{
			document.body.setCapture();
			document.body.attachEvent("onmouseup", CLCalendarOnMouseUp);
			document.body.attachEvent("onmousemove", CLCalendarTrackMouseMove);
		}
		
		// Capture events for W3C style event model
		if(document.body.addEventListener)
		{
			inEvent.preventDefault();
			document.body.addEventListener("mouseup", CLCalendarOnMouseUp, false);
			document.body.addEventListener("mousemove", CLCalendarTrackMouseMove, false);
		}
		// Draw the calendar
		this.drawSelf();

		// Move and display the calendar
		this.element.style.left = (x - 137 / 2) + "px";
		this.element.style.top = (y + 4) + "px";
		this.element.style.width = 138;
		this.element.style.visibility = "visible";
		this.element.style.display="inline";
	}

	this.close = function(inEvent)
	{

		ShowDDLs();
		var id;
		this.isSticky = false;
		this.isOpen = false;

		if(!inEvent && event) inEvent = event;
		if(inEvent.target) this._hoverElement = inEvent.target;
		else this._hoverElement = inEvent.srcElement;

		id = (this._hoverElement.id) ? this._hoverElement.id : (this._hoverElement.parentNode.id) ? this._hoverElement.parentNode.id : "";

		// Hide the calendar
		this.element.style.visibility = "hidden";
        this.element.style.display="none";
		// Accept the highlighted date if the source element was part of the calendar
		if(this.linkedField && this.highlightedDate && id.indexOf(this.id) == 0)
		{
			this.currentDate = new Date(this.highlightedDate);
			this.linkedField.actualValue = new Date(this.currentDate);
			if(this.useShortDate)
				this.linkedField.value = this._dateFormat.localiseShortDate(this.currentDate);
			else
				this.linkedField.value = this._dateFormat.localiseLongDate(this.currentDate);
			
			// This will validate the field properly
			if(this.linkedField.onchange) this.linkedField.onchange();
		}

		// Release event capture for IE style event model
		if(document.body.detachEvent)
		{
			document.body.releaseCapture();
			document.body.detachEvent("onmouseup", CLCalendarOnMouseUp);
			document.body.detachEvent("onmousemove", CLCalendarTrackMouseMove);
		}
		
		// Release events for the W3C style event model
		if(document.body.removeEventListener)
		{
			document.body.removeEventListener("mouseup", CLCalendarOnMouseUp, false);
			document.body.removeEventListener("mousemove", CLCalendarTrackMouseMove, false);
		}
	}
	
	this.setHighlightedDate = function(inDate)
	{
		if(this.highlightedDate)
			document.getElementById(this.id + "D" + this.highlightedDate.getDate()).className = "CLCalendarDayCell";

		if(inDate && inDate.getMonth() == this.highlightedDate.getMonth() && inDate.getFullYear() == this.highlightedDate.getFullYear())
		{
			this.highlightedDate = new Date(inDate);

			document.getElementById(this.id + "D" + this.highlightedDate.getDate()).className = "CLCalendarHighlightedDayCell";

			if(this.linkedField && this.liveUpdate)
			{
				if(this.useShortDate)
					this.linkedField.value = this._dateFormat.localiseShortDate(this.highlightedDate);
				else
					this.linkedField.value = this._dateFormat.localiseLongDate(this.highlightedDate);
			}
		}
		else if(this.linkedField && this.liveUpdate)
		{
			if(this.useShortDate)
				this.linkedField.value = this._dateFormat.localiseShortDate(this.highlightedDate);
			else
				this.linkedField.value = this._dateFormat.localiseLongDate(this.highlightedDate);
		}
	}
	
	this.previousMonth = function()
	{
		if(this._hoverElement.id == this.id + "PreviousButton")
		{
			var month = this.highlightedDate.getMonth();

			if(month == 0)
			{
				this.highlightedDate.setMonth(11);
				this.highlightedDate.setYear(this.highlightedDate.getFullYear() - 1);
			}
			else
			{
           		daysInMonth = CLDaysInMonth[month - 1];
  				if(month == 0 && this.highlightedDate.getFullYear() % 4 > 0)
        			daysInMonth--;

			    if(daysInMonth < this.highlightedDate.getDate())
			    {
			        this.highlightedDate.setDate(daysInMonth);
			    }
			    
				this.highlightedDate.setMonth(month - 1);
		    }
            
			this.drawSelf();

			if(!this.isSticky)
			{
				this._timer.setInvocation(new CLInvocation(this, this.previousMonth));
				this._timer.start();
			}
		}
	}

	this.nextMonth = function()
	{
		this.timer = null;

		if(this._hoverElement.id == this.id + "NextButton") 
		{
			var month = this.highlightedDate.getMonth();

			if(month == 11)
			{
				this.highlightedDate.setMonth(0);
				this.highlightedDate.setYear(this.highlightedDate.getFullYear() + 1);
			}
			else
			{
        		daysInMonth = CLDaysInMonth[month + 1];
  				if(month == 0 && this.highlightedDate.getFullYear() % 4 > 0)
        			daysInMonth--;

			    if(daysInMonth < this.highlightedDate.getDate())
			    {
			        this.highlightedDate.setDate(daysInMonth);
			    }
			    
				this.highlightedDate.setMonth(month + 1);
		    }
            
			this.drawSelf();

			if(!this.isSticky)
			{
				this._timer.setInvocation(new CLInvocation(this, this.nextMonth));
				this._timer.start();
			}
		}
	}
	
	this.onMouseUp = function(inEvent)
	{
		var id;
		if(!this.isOpen) return;
        
		if(!inEvent && event) inEvent = event;
		if(inEvent.target) this._hoverElement = inEvent.target;
		else this._hoverElement = inEvent.srcElement;
     
        if(this._hoverElement.disabled) return;

		id = (this._hoverElement.id) ? this._hoverElement.id : (this._hoverElement.parentNode.id) ? this._hoverElement.parentNode.id : "";

		if(this.isSticky && id.indexOf(this.id + "D") != 0)
		{
			if(!this._timer.active && id.indexOf(this.id) != 0)
			{
				this.close(inEvent);
				return;
			}

			this._timer.stop();

			if(id == this.id + "PreviousButton") this.previousMonth();
			else if(id == this.id + "NextButton") this.nextMonth();
		}
		else
			this.close(inEvent);
	}
	
	this.trackMouseMove = function(inEvent)
	{
		var id;
		if(!this.isOpen) return;
		
		if(!inEvent && event) inEvent = event;
		if(inEvent.target) this._hoverElement = inEvent.target;
		else this._hoverElement = inEvent.srcElement;
		
		id = (this._hoverElement.id) ? this._hoverElement.id : (this._hoverElement.parentNode.id) ? this._hoverElement.parentNode.id : "";

		if(id.indexOf(this.id + "D") == 0)
			this.setHighlightedDate(new Date(this.highlightedDate.getFullYear(), this.highlightedDate.getMonth(), id.substring(this.id.length + 1), 0, 0, 0, 0));
		else if(id == this.id + "PreviousButton")
		{
			if(!this._timer.active && !this.isSticky)
			{
				this._timer.setInvocation(new CLInvocation(this, this.previousMonth));
				this._timer.start();
			}
		}
		else if(id == this.id + "NextButton")
		{
			if(!this._timer.active && !this.isSticky)
			{
				this._timer.setInvocation(new CLInvocation(this, this.nextMonth));
				this._timer.start();
			}
		}
		else
			this.setHighlightedDate(new Date(this.currentDate));
	}
	
	this.drawSelf = function()
	{		
		var div;
		var dayOfWeek, week, daysInMonth;
        var offsetCorrection=0;
        if (this.language=="ar-SA") offsetCorrection=132;
		// Set calendar heading to the highlighted month and year
		this.headerElement.innerHTML = this._dateFormat.months[this.highlightedDate.getMonth()] + ", " + this.highlightedDate.getFullYear();

		this.contentElement.innerHTML = "";

		// Draw the day headings
		for(var i = 0; i < 7; i++)
		{
			div = document.createElement("div");
			div.className = "CLCalendarWeekDayHeader";
			//div.style.left = (i * 20) + "px";		
			div.style.left = ((i * 20)-offsetCorrection) + "px";		
			div.appendChild(document.createTextNode(this._dateFormat.days[i].charAt(0)));
			this.contentElement.appendChild(div);
		}

		// Draw the day cells
		dayOfWeek = (new Date(this.highlightedDate.getFullYear(), this.highlightedDate.getMonth(), 1, 0, 0, 0, 0)).getDay();
		if(dayOfWeek == 0) dayOfWeek = 7;
		
		// Adjust for non-leap years
		daysInMonth = CLDaysInMonth[this.highlightedDate.getMonth()];
		if(this.highlightedDate.getMonth() == 1 && this.highlightedDate.getFullYear() % 4 > 0)
			daysInMonth--;
		
		week = 1;
		
		for(var i = 1; i <= daysInMonth; i++)
		{
			div = document.createElement("div");
			
			var d=new Date();		
			d.setFullYear(this.highlightedDate.getFullYear());
			d.setMonth(this.highlightedDate.getMonth());
			d.setDate(i);
			
			if(d<this.BeginDate)
			{
    			div.disabled=true;
			}
			
			if(d>this.EndDate)
			{
    			div.disabled=true;
			}			
			
			div.id = this.id + "D" + i;
			if(this.highlightedDate.getDate() != i) 
			    div.className = "CLCalendarDayCell";
			else 
			    div.className = "CLCalendarHighlightedDayCell";
			    
			div.style.top = (week * 17) + "px";
			div.style.left = (((dayOfWeek - 1) * 20)-offsetCorrection) + "px";
			div.appendChild(document.createTextNode(i));
			this.contentElement.appendChild(div);

			dayOfWeek++;
			if(dayOfWeek > 7)
			{
				week++;
				dayOfWeek = 1;
			}
		}
	}
	
	this.attachToDocumentBody = function( MediaFolder )
	{
	    if (!MediaFolder)
	    {
	        MediaFolder= "/images";
	    }
	
		var button;
		
		this.element = document.createElement("div");
		this.element.id = this.id; this.element.className = "CLCalendar";
		
		this.headerElement = document.createElement("div");
		this.headerElement.id = this.id + "Header"; this.headerElement.className = "CLCalendarHeader";
		this.element.appendChild(this.headerElement);
		
		button = document.createElement("img");
		button.id = this.id + "PreviousButton"; button.className = "CLCalendarPreviousButton";
		button.src = MediaFolder + "previous-e.gif";
		this.element.appendChild(button);
		
		button = document.createElement("img");
		button.id = this.id + "NextButton"; button.className = "CLCalendarNextButton";
		button.src = MediaFolder + "next-e.gif";
		this.element.appendChild(button);
		
		this.contentElement = document.createElement("div");
		this.contentElement.id = this.id + "Content"; this.contentElement.className = "CLCalendarContent";
		this.element.appendChild(this.contentElement);
		
		this.drawSelf();
        this.element.style.display="none";		
		document.body.appendChild(this.element);
	}
}
