var Cathmhaol = window.Cathmhaol || {};

/**
* Extends the functionality offered in the Date object
*
* @author	Robert King (hrobertking@cathmhaol.com)
*
* @example	var sShortDayName = Cathmhaol.Calendar.DAYS["en"][Cathmhaol.Calendar.SUNDAY].shortName
*/
Cathmhaol.Calendar = {
	/**
	* @property	Hash of day names
	* @type	{variant[]}
	*/
	DAYS: {
		// DAYS is a hash that uses an ISO language code as the key. Each value is a 7-element array that contains an
		// object specifying the long and short version of the day name. For example, for English, the array element 
		// for Cathmhaol.Calendar.SUNDAY contains an object with the property longName (Sunday) and shortName (Sun),
		// which is a common abbreviation of the name.

		"da": new Array({longName: "s&#248;ndag", shortName: "s&#248;n"}, {longName: "mandag", shortName: "man"}, {longName: "tirsdag", shortName: "tirs"}, {longName: "onsdag", shortName: "ons"}, {longName: "torsdag", shortName: "tors"}, {longName: "fredag", shortName: "fre"}, {longName: "l&#248;rdag", shortName: "l&#248;r"}),
		"de": new Array({longName: "Sonntag", shortName: "So"}, {longName: "Montag", shortName: "Mo"}, {longName: "Dienstag", shortName: "Di"}, {longName: "Mittwoch", shortName: "Mi"}, {longName: "Donnerstag", shortName: "Do"}, {longName: "Freitag", shortName: "Fr"}, {longName: "Samstag", shortName: "Sa"}),
		"en": new Array({longName: "Sunday", shortName: "Sun"}, {longName: "Monday", shortName: "Mon"}, {longName: "Tuesday", shortName: "Tue"}, {longName: "Wednesday", shortName: "Wed"}, {longName: "Thursday", shortName: "Thu"}, {longName: "Friday", shortName: "Fri"}, {longName: "Saturday", shortName: "Sat"}),
		"es": new Array({longName: "domingo", shortName: "dom"}, {longName: "lunes", shortName: "lun"}, {longName: "martes", shortName: "mar"}, {longName: "mi&#233;rcoles", shortName: "mi&#233;"}, {longName: "jueves", shortName: "jue"}, {longName: "viernes", shortName: "vie"}, {longName: "s&#225;bado", shortName: "s&#225;b"}),
		"fi": new Array({longName: "sunnuntai", shortName: "su"}, {longName: "maanantai", shortName: "ma"}, {longName: "tiistai", shortName: "ti"}, {longName: "keskiviiko", shortName: "ke"}, {longName: "torstai", shortName: "to"}, {longName: "perjantai", shortName: "pe"}, {longName: "lauantai", shortName: "la"}),
		"fr": new Array({longName: "dimanche", shortName: "dim"}, {longName: "lundi", shortName: "lun"}, {longName: "mardi", shortName: "mar"}, {longName: "mercredi", shortName: "mer"}, {longName: "jeudi", shortName: "jeu"}, {longName: "vendredi", shortName: "ven"}, {longName: "samedi", shortName: "sam"}),
		"ga": new Array({longName: "D&#233; Domhnaigh", shortName: "Dom"}, {longName: "D&#233; Luain", shortName: "Lua"}, {longName: "D&#233; M&#225;irt", shortName: "M&#225;i"}, {longName: "D&#233; Ch&#233;adaoin", shortName: "Ch&#233;"}, {longName: "D&#233;ardaoin", shortName: "Dao"}, {longName: "D&#233; hAoine", shortName: "Aoi"}, {longName: "D&#233; Sathairn", shortName: "Sat"}),
		"hu": new Array({longName: "vas&#225;map", shortName: "vas"}, {longName: "h&#233;tf&#246;", shortName: "h&#233;"}, {longName: "kedd", shortName: "ked"}, {longName: "szerda", shortName: "sze"}, {longName: "cs&#252;t&#246;rt&#246;k", shortName: "cs&#252"}, {longName: "p&#233;ntek", shortName: "p&#233;n"}, {longName: "szombat", shortName: "szo"}),
		"it": new Array({longName: "domenica", shortName: "dom"}, {longName: "lunedì", shortName: "lun"}, {longName: "martedì", shortName: "mar"}, {longName: "mercoledì", shortName: "mer"}, {longName: "giovedì", shortName: "gio"}, {longName: "venerdì", shortName: "ven"}, {longName: "sabato", shortName: "sab"}),
		"nl": new Array({longName: "zondag", shortName: "zondag"}, {longName: "maandag", shortName: "maan-"}, {longName: "dinsdag", shortName: "dins-"}, {longName: "woensdag", shortName: "woens-"}, {longName: "donderdag", shortName: "donder-"}, {longName: "vrijdag", shortName: "vrij-"}, {longName: "zaterdag", shortName: "zat-"}),
		"pl": new Array({longName: "niedziela", shortName: "nie"}, {longName: "poniedzia&#322;ek", shortName: "pon"}, {longName: "wtorek", shortName: "wto"}, {longName: "&#347;roda", shortName: "&#347;rd"}, {longName: "czwartek", shortName: "czw"}, {longName: "pi&#261;tek", shortName: "pi&#261;"}, {longName: "sobota", shortName: "sob"}),
		"pt": new Array({longName: "domingo", shortName: "dom"}, {longName: "segunda-feira", shortName: "seg"}, {longName: "ter&#231;a-feira", shortName: "ter"}, {longName: "quarta-feira", shortName: "qua"}, {longName: "quinta-feira", shortName: "qui"}, {longName: "sexta-feira", shortName: "sex"}, {longName: "s&#225;bado", shortName: "s&#225;"}),
		"sv": new Array({longName: "s&#246;ndag", shortName: "s&#246;n"}, {longName: "m&#229;ndag", shortName: "m&#229;n"}, {longName: "tisdag", shortName: "tis"}, {longName: "onsdag", shortName: "ons"}, {longName: "torsdag", shortName: "tors"}, {longName: "fredag", shortName: "fre"}, {longName: "l&#246;rdag", shortName: "l&#246;r"})
	},

	/**
	* @property	Constant numeric value of Friday
	* @type	{integer}
	*/
	FRIDAY: 5,

	/**
	* @property	Constant numeric value of Monday
	* @type	{integer}
	*/
	MONDAY: 1,

	/**
	* @property	Hash of month names
	* @type	{variant[]}
	*/
	MONTHS: {
		// MONTHS is a hash that uses an ISO language code as the key. Each value is a 12-element array that contains
		// an object specifying the long and short version of the month name. For example, for English, the 0-element 
		// contains an object with the property longName (January) and shortName (Jan), which is a common abbreviation
		// of the name. Since the getMonth function returns a 0-based index, the hash uses the same approach.

		"da": new Array({longName: "Januar", shortName: "jan"}, {longName: "Februar", shortName: "feb"}, {longName: "Marts", shortName: "mar"}, {longName: "April", shortName: "apr"}, {longName: "Maj", shortName: "maj"}, {longName: "Juni", shortName: "jun"}, {longName: "Juli", shortName: "jul"}, {longName: "August", shortName: "aug"}, {longName: "September", shortName: "sep"}, {longName: "Oktober", shortName: "okt"}, {longName: "November", shortName: "nov"}, {longName: "December", shortName: "dec"}),
		"de": new Array({longName: "Januar", shortName: "Jan"}, {longName: "Februar", shortName: "Feb"}, {longName: "M&#228;rz", shortName: "M&#228;rz"}, {longName: "April", shortName: "Apr"}, {longName: "Mai", shortName: "Mai"}, {longName: "Juni", shortName: "Juni"}, {longName: "Juli", shortName: "Juli"}, {longName: "August", shortName: "Aug"}, {longName: "September", shortName: "Sept"}, {longName: "Oktober", shortName: "Okt"}, {longName: "November", shortName: "Nov"}, {longName: "Dezember", shortName: "Dez"}),
		"en": new Array({longName: "January", shortName: "Jan"}, {longName: "February", shortName: "Feb"}, {longName: "March", shortName: "Mar"}, {longName: "April", shortName: "Apr"}, {longName: "May", shortName: "May"}, {longName: "June", shortName: "Jun"}, {longName: "July", shortName: "Jul"}, {longName: "August", shortName: "Aug"}, {longName: "September", shortName: "Sep"}, {longName: "October", shortName: "Oct"}, {longName: "November", shortName: "Nov"}, {longName: "December", shortName: "Dec"}),
		"es": new Array({longName: "enero", shortName: "ene"}, {longName: "febrero", shortName: "feb"}, {longName: "marzo", shortName: "mar"}, {longName: "abril", shortName: "abr"}, {longName: "mayo", shortName: "may"}, {longName: "junio", shortName: "jun"}, {longName: "julio", shortName: "jul"}, {longName: "agosto", shortName: "ago"}, {longName: "septiembre", shortName: "sep"}, {longName: "octubre", shortName: "oct"}, {longName: "noviembre", shortName: "nov"}, {longName: "diciembre", shortName: "dic"}),
		"fi": new Array({longName: "tammikuu", shortName: "tammik."}, {longName: "helmikuu", shortName: "helmik."}, {longName: "maaliskuu", shortName: "maalisk."}, {longName: "huhtikuu", shortName: "huhtik."}, {longName: "toukokuu", shortName: "toukok."}, {longName: "kes&#228;kuu", shortName: "kes&#228;k."}, {longName: "hein&#228;kuu", shortName: "hein&#228;k."}, {longName: "elokuu", shortName: "elok."}, {longName: "syyskuu", shortName: "syysk."}, {longName: "lokakuu", shortName: "lokak."}, {longName: "marraskuu", shortName: "marrask."}, {longName: "joulukuu", shortName: "jouluk."}),
		"fr": new Array({longName: "janvier", shortName: "janv"}, {longName: "f&#232;vrier", shortName: "f&#232;vr"}, {longName: "mars", shortName: "mars"}, {longName: "avril", shortName: "avril"}, {longName: "mai", shortName: "mai"}, {longName: "juin", shortName: "juin"}, {longName: "juillet", shortName: "juil"}, {longName: "ao&#251;t", shortName: "ao&#251;t"}, {longName: "septembre", shortName: "sept"}, {longName: "octobre", shortName: "oct"}, {longName: "novembre", shortName: "nov"}, {longName: "d&#232;cembre", shortName: "d&#232;c"}),
		"ga": new Array({longName: "M&#237; Eanair", shortName: "Ean"}, {longName: "M&#237; Feabhra", shortName: "Fea"}, {longName: "M&#237; M&#225;rta", shortName: "Mar"}, {longName: "M&#237; Aibre&#225;n", shortName: "Aib"}, {longName: "M&#237; Bealtaine", shortName: "Bea"}, {longName: "M&#237; Meitheamh", shortName: "Mei"}, {longName: "M&#237; I&#250;il", shortName: "I&#250;l"}, {longName: "M&#237; L&#250;nasa", shortName: "L&#250;n"}, {longName: "M&#237; Me&#225;n Fomhair", shortName: "Mfo"}, {longName: "M&#237; Deireadh Fomhair", shortName: "Dfo"}, {longName: "M&#237; na Samhna", shortName: "Sam"}, {longName: "M&#237; na Nollag", shortName: "Nol"}),
		"hu": new Array({longName: "janu&#225;r", shortName: "jan"}, {longName: "febru&#225;r", shortName: "feb"}, {longName: "m&#225;rcius", shortName: "m&#255;"}, {longName: "&#225;prilis", shortName: "&#255;pr"}, {longName: "m&#225;jus", shortName: "m&#255;j"}, {longName: "j&#250;nius", shortName: "j&#250;n"}, {longName: "j&#250;lius", shortName: "j&#250;l"}, {longName: "augusztus", shortName: "aug"}, {longName: "szeptember", shortName: "sep"}, {longName: "okt&#243;ber", shortName: "okt"}, {longName: "november", shortName: "nov"}, {longName: "december", shortName: "dec"}),
		"it": new Array({longName: "gennaio", shortName: "gen"}, {longName: "febbraio", shortName: "feb"}, {longName: "marzo", shortName: "mar"}, {longName: "aprile", shortName: "apr"}, {longName: "maggio", shortName: "mag"}, {longName: "giugno", shortName: "giu"}, {longName: "luglio", shortName: "lug"}, {longName: "agosto", shortName: "ago"}, {longName: "settembre", shortName: "sett"}, {longName: "ottobre", shortName: "ott"}, {longName: "novembre", shortName: "nov"}, {longName: "dicembre", shortName: "dic"}),
		"nl": new Array({longName: "januari", shortName: "jan"}, {longName: "februari", shortName: "feb"}, {longName: "mart", shortName: "mrt"}, {longName: "april", shortName: "apr"}, {longName: "mei", shortName: "mei"}, {longName: "juni", shortName: "jun"}, {longName: "juli", shortName: "jul"}, {longName: "augustus", shortName: "aug"}, {longName: "september", shortName: "sep"}, {longName: "oktober", shortName: "okt"}, {longName: "november", shortName: "nov"}, {longName: "december", shortName: "dec"}),
		"pl": new Array({longName: "stycze&#324;", shortName: "sty"}, {longName: "luty", shortName: "luty"}, {longName: "marzec", shortName: "mar"}, {longName: "kwiecie&#324;", shortName: "kwi"}, {longName: "maj", shortName: "maj"}, {longName: "czerwiec", shortName: "cze"}, {longName: "lipiec", shortName: "lip"}, {longName: "sierpie&#324;", shortName: "sier"}, {longName: "wrzesie&#324;", shortName: "wrze"}, {longName: "pa&#378;dziernik", shortName: "pa&#378;"}, {longName: "listopad", shortName: "list"}, {longName: "grudzie&#324;", shortName: "gru"}),
		"pt": new Array({longName: "janeiro", shortName: "jan"}, {longName: "fevereiro", shortName: "fev"}, {longName: "mar&#231;o", shortName: "mar"}, {longName: "abril", shortName: "abr"}, {longName: "maio", shortName: "mai"}, {longName: "junho", shortName: "jun"}, {longName: "julho", shortName: "jul"}, {longName: "agosto", shortName: "ago"}, {longName: "setembro", shortName: "set"}, {longName: "outubro", shortName: "out"}, {longName: "novembro", shortName: "nov"}, {longName: "dezembro", shortName: "dez"}),
		"sv": new Array({longName: "januari", shortName: "jan"}, {longName: "februari", shortName: "febr"}, {longName: "mars", shortName: "mars"}, {longName: "april", shortName: "april"}, {longName: "maj", shortName: "maj"}, {longName: "juni", shortName: "juni"}, {longName: "juli", shortName: "juli"}, {longName: "augusti", shortName: "aug"}, {longName: "september", shortName: "sept"}, {longName: "october", shortName: "okt"}, {longName: "november", shortName: "nov"}, {longName: "december", shortName: "dec"})
	},

	/**
	* @property	An enumeration of periods
	* @type	{object}
	*/
	PERIOD: {
		DAY: {code: "d", abbreviation:"dy", name:"day" },
		HOUR: {code: "h", abbreviation:"hr", name:"hour" },
		MINUTE: {code: "n", abbreviation:"min", name:"minute" },
		MONTH: {code: "m", abbreviation:"mo", name:"month" },
		QUARTER: {code: "q", abbreviation:"qt", name:"quarter" },
		SECOND: {code: "s", abbreviation:"sec", name:"second" },
		WEEK: {code: "w", abbreviation:"wk", name:"week" },
		YEAR: {code: "y", abbreviation:"yr", name:"year" },
		normalize: function(s) {
			if ((/^da?y?$/i).test(s)) {
				return this.DAY;
			} else if ((/^h(ou)?r?$/i).test(s)) {
				return this.HOUR;
			} else if ((/^(min|n|minute)$/i).test(s)) {
				return this.MINUTE;
			} else if ((/^mo?(nth)?$/i).test(s)) {
				return this.MONTH;
			} else if ((/^(q|qt|quarter)$/i).test(s)) {
				return this.QUARTER;
			} else if ((/^s((ec)?(ond))?$/i).test(s)) {
				return this.SECOND;
			} else if ((/^w(ee)?k?$/i).test(s)) {
				return this.WEEK;
			} else if ((/^y(ea)?r?$/i).test(s)) {
				return this.YEAR;
			}
		}
	},

	/**
	* @property	Constant numeric value of Saturday
	* @type	{integer}
	*/
	SATURDAY: 6,

	/**
	* @property	Constant numeric value of Sunday
	* @type	{integer}
	*/
	SUNDAY: 0,

	/**
	* @property	Constant numeric value of Thursday
	* @type	{integer}
	*/
	THURSDAY: 4,

	/**
	* @property	Constant numeric value of Tuesday
	* @type	{integer}
	*/
	TUESDAY: 2,

	/**
	* @property	Constant numeric value of Wednesday
	* @type	{integer}
	*/
	WEDNESDAY: 3,

	/**
	* @method	Returns a date after adding the specified number of periods to the starting date. The specified period must be a string specifying one of the following: y[ear], q[uarter], m[onth], d[ay], w[eek], h[our], [mi]n[ute], or s[econd].
	* @returns	{date}
	* @argument	{string|Cathmhaol.Calendar.PERIOD} period
	* @argument	{integer} periods
	* @argument	{string|integer|date} dateStart
	*/
	dateAdd: function(period, periods, dateStart) {
		// We start by making sure that periods and start default to 0 and today respectively. Then
		// this function converts string or integer (milliseconds) arguments to a date object and
		// tests to make sure that the functions we need are available and callable. If they're not,
		// or if the date is an invalid date (getTime returns null) we return null. If all are
		// available and callable and the date is a valid date, then we return the date created
		// by adding the specified number of periods to the starting date. Finally, if the period
		// passed is not valid, we return null.

		period = (!period.code || !period.abbreviation || !period.name) ? this.PERIOD.normalize(period) : period;
		if (!period.code) {
			return;
		}
		periods = periods || 0;
		dateStart = dateStart || new Date();

		dateStart = (typeof(dateStart) == "string" || typeof(dateStart) == "number") ? new Date(dateStart) : dateStart;
		if (!dateStart.setDate.call || !dateStart.setHours.call || !dateStart.setMonth.call || !dateStart.setMinutes.call || !dateStart.setMonth.call || !dateStart.setSeconds.call || !dateStart.setDate.call || !dateStart.setFullYear.call || isNaN(dateStart.getTime())) { return; }
		switch (period.code) {
			case this.PERIOD.DAY.code:
			case this.PERIOD.DAY.abbreviation:
			case this.PERIOD.DAY.name:
				return new Date(dateStart.setDate(dateStart.getDate() + parseFloat(periods)));
			case this.PERIOD.HOUR.code:
			case this.PERIOD.HOUR.abbreviation:
			case this.PERIOD.HOUR.name:
				return new Date(dateStart.setHours(dateStart.getHours() + parseFloat(periods)));
			case this.PERIOD.MONTH.code:
			case this.PERIOD.MONTH.abbreviation:
			case this.PERIOD.MONTH.name:
				return new Date(dateStart.setMonth(dateStart.getMonth() + parseFloat(periods)));
			case this.PERIOD.MINUTE.code:
			case this.PERIOD.MINUTE.abbreviation:
			case this.PERIOD.MINUTE.name:
				return new Date(dateStart.setMinutes(dateStart.getMinutes() + parseFloat(periods)));
			case this.PERIOD.QUARTER.code:
			case this.PERIOD.QUARTER.abbreviation:
			case this.PERIOD.QUARTER.name:
				return new Date(dateStart.setMonth(dateStart.getMonth() + (parseFloat(periods) * 3)));
			case this.PERIOD.SECOND.code:
			case this.PERIOD.SECOND.abbreviation:
			case this.PERIOD.SECOND.name:
				return new Date(dateStart.setSeconds(dateStart.getSeconds() + parseFloat(periods)));
			case this.PERIOD.WEEK.code:
			case this.PERIOD.WEEK.abbreviation:
			case this.PERIOD.WEEK.name:
				return new Date(dateStart.setDate(dateStart.getDate() + (parseFloat(periods) * 7)));
			case this.PERIOD.YEAR.code:
			case this.PERIOD.YEAR.abbreviation:
			case this.PERIOD.YEAR.name:
				return new Date(dateStart.setFullYear(dateStart.getFullYear() + parseFloat(periods)));
		}
		return;
	},

	/**
	* @method	Returns the number of specified intervals between the start date and the end date. The specified period must be a string specifying one of the following: y[ear], q[uarter], m[onth], d[ay], w[eek], h[our], [mi]n[ute], or s[econd].
	* @returns	{float}
	* @argument	{string|Cathmhaol.Calendar.PERIOD} period
	* @argument	{string|integer|date} dateStart
	* @argument	{string|integer|date} dateEnd
	*/
	dateDiff: function(period, dateStart, dateEnd) {
		// We start by making sure that the start and end dates default to today. Then this function
		// converts string or integer (milliseconds) arguments to a date object and tests to make sure
		// that the functions we need are available and callable. If they're not, or if the date is an
		// invalid date (getTime returns null) we return null. If all are available and callable and
		// the date is a valid date, then we return the result calculated by subtracting the year or
		// the number of milliseconds passed since the epoch start (1/1/1970) and adjusting for the
		// period. Finally, if the period passed is not valid, we return null.

		period = (!period.code || !period.abbreviation || !period.name) ? this.PERIOD.normalize(period) : period;
		if (!period.code) {
			return;
		}
		dateStart = dateStart || new Date();
		dateEnd = dateEnd || new Date();

		dateStart = (typeof(dateStart) == "string" || typeof(dateStart) == "number") ? new Date(dateStart) : dateStart;
		dateEnd = (typeof(dateEnd) == "string" || typeof(dateEnd) == "number") ? new Date(dateEnd) : dateEnd;
		if (!dateStart.setDate.call || !dateStart.setHours.call || !dateStart.setMonth.call || !dateStart.setMinutes.call || !dateStart.setMonth.call || !dateStart.setSeconds.call || !dateStart.setDate.call || !dateStart.setFullYear.call || isNaN(dateStart.getTime())) { return; }
		if (!dateEnd.setDate.call || !dateEnd.setHours.call || !dateEnd.setMonth.call || !dateEnd.setMinutes.call || !dateEnd.setMonth.call || !dateEnd.setSeconds.call || !dateEnd.setDate.call || !dateEnd.setFullYear.call || isNaN(dateEnd.getTime())) { return; }
		switch (period.code) {
			case this.PERIOD.DAY.code:
			case this.PERIOD.DAY.abbreviation:
			case this.PERIOD.DAY.name:
				return ((dateEnd.getTime() - dateStart.getTime())/(1000 * 60 * 60 * 24));
			case this.PERIOD.HOUR.code:
			case this.PERIOD.HOUR.abbreviation:
			case this.PERIOD.HOUR.name:
				return ((dateEnd.getTime() - dateStart.getTime())/(1000 * 60 * 60));
			case this.PERIOD.MONTH.code:
			case this.PERIOD.MONTH.abbreviation:
			case this.PERIOD.MONTH.name:
				return ((dateEnd.getFullYear() - dateStart.getFullYear())*12) + (dateEnd.getMonth() - dateStart.getMonth());
			case this.PERIOD.MINUTE.code:
			case this.PERIOD.MINUTE.abbreviation:
			case this.PERIOD.MINUTE.name:
				return ((dateEnd.getTime() - dateStart.getTime())/(1000 * 60));
			case this.PERIOD.QUARTER.code:
			case this.PERIOD.QUARTER.abbreviation:
			case this.PERIOD.QUARTER.name:
				return ((dateEnd.getFullYear() - dateStart.getFullYear())*4) + ((dateEnd.getMonth() - dateStart.getMonth())/4);
			case this.PERIOD.SECOND.code:
			case this.PERIOD.SECOND.abbreviation:
			case this.PERIOD.SECOND.name:
				return ((dateEnd.getTime() - dateStart.getTime())/1000);
			case this.PERIOD.WEEK.code:
			case this.PERIOD.WEEK.abbreviation:
			case this.PERIOD.WEEK.name:
				return ((dateEnd.getTime() - dateStart.getTime())/(1000 * 60 * 60 * 24 * 7));
			case this.PERIOD.YEAR.code:
			case this.PERIOD.YEAR.abbreviation:
			case this.PERIOD.YEAR.name:
				return dateEnd.getFullYear() - dateStart.getFullYear();
		}
		return;
	},

	/**
	* @method	Returns the day of the week for the specified date
	* @returns	{integer}
	* @argument	{string|integer|date} dateStart
	*/
	dayOfTheWeek: function(dateStart) {
		// We start by making sure that the start date defaults to today. Then the function
		// converts a string or integer to a date. If the start date we now have is not valid,
		// we return null. If it is, then we return the numeric equivalent of the day.

		dateStart = dateStart || new Date();
		dateStart = (typeof(dateStart) == "string" || typeof(dateStart) == "number") ? new Date(dateStart) : dateStart;
		if (dateStart.getDay.call && !isNaN(dateStart.getDay())) {
			return dateStart.getDay();
		}
		return;
	},

	/**
	* @method	Calculates the number of days in a month.
	* @returns	{integer}
	* @argument	{string|integer|date} dateStart
	*/
	daysInMonth: function(dateStart) {
		// We start by making sure that the start date defaults to today. Then the function
		// converts a string or integer to a date. If the start date we now have is not valid,
		// we return null. If it is, then we determine the correct number of days based on the month.

		dateStart = dateStart || new Date();
		dateStart = (typeof(dateStart) == "string" || typeof(dateStart) == "number") ? new Date(dateStart) : dateStart;
		if (dateStart.getMonth.call && !isNaN(dateStart.getMonth())) {
			switch (dateStart.getMonth()) {
				case 1:
					if (this.isLeapYear(dateStart.getFullYear())) {
						return 29;
					} else {
						return 28;
					}
				case 3:
				case 5:
				case 8:
				case 10:
					return 30;
				default:
					return 31; 
			}
		}
		return;
	},

	/**
	* @method	Returns true if the year evaluated is a leap year.
	* @returns	{boolean}
	*/
	isLeapYear: function(iYear) {
		// We start by making sure that the year specified defaults to the current year and that it's a
		// valid year. If it's a valid year, we perform a modulus operation to check to see if it's
		// evenly divisible by 4 and not 100 or if it's evenly divisible by 400.

		iYear = iYear || (new Date()).getFullYear();
		if (iYear < 1) { return; }
		return ((iYear % 4 == 0) && (iYear % 100 != 0)) || (iYear % 400 == 0);
	},

	/**
	* @method	Returns true if the specified language code is supported.
	* @returns	{boolean}
	* @argument {string} language
	*/
	isSupportedLanguage: function(language) {
		// We loop through all the keys in the DAYS has to see if a key matches the provided language
		// code. If it does, it's a supported language. If the provided language code is null, we
		// don't even bother going through the loop because we known we'll never know if it's supported
		// or not.

		if (!language) { return; }
		for (var langCode in this.DAYS) {
			if (langCode.toLowerCase() == language.toLowerCase()) {
				return true;
			}
		}
		return false;
	},

	/**
	* @method	Returns an ordinal date given the year, month, ordinal index (must be 1 (first), 2 (second), 3 (third), 4 (fourth), or 5 (fifth)), and day of the week (Sunday = 0, Monday = 1, .. Saturday = 6). For example, ordinalDate(2008, 2, 5, Cathmhaol.Calendar.SUNDAY) would return the fifth Sunday in March, 2008 -- 30-MAR-08.
	* @returns	{date}
	* @argument	{integer} yy
	* @argument	{integer} mm
	* @argument	{integer} oi
	* @argument	{integer} dd
	*/
	ordinalDate: function(yy, mm, oi, dd) {
		// If any argument is null or invalid, we return null; otherwise, we calculate the minimum and maximum values for the ordinal index
		// and then loop through the values to create a date and check what day of the week it is. If it's not possible to determine
		// what the day is, null is returned.

		if (!yy || (yy < 1) || !mm || (mm < 0) || (mm > 11) || !oi || (oi < 1) || (oi > 5) || !dd || (dd < 0) || (dd > 6)) {
			return;
		}
		var min = ((oi - 1) * 7) + 1;
		var max = min + 7;
		for (var c = min; c <= max; c++) {
			var d = new Date(yy, mm, c);
			if (d.getDay() == dd) { return d; }
		}
		return;
	},

	/**
	* @method	Returns an array of ISO 639-1 Alpha-3 language codes supported.
	* @returns	{string[]}
	*/
	supportedLanguages: function() {
		// We loop through all the keys in the DAYS and add the key to the array to return.

		var a = new Array();
		for (var langCode in this.DAYS) {
			a.push(langCode.toLowerCase());
		}
		return a;
	}
};

