
/* ================================================================================================================================================== ARRAY EXTRAS ====
*/
	// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ
			Array.prototype.appendItem		= function(item) { this.push(item); return item; };
	// ------------------------------------------------------------------------------------------------------------------------------------------------
			Array.prototype.indexOfItem		= function(item)
																				{
																				for (var i = 0; i < this.length; i++) { if (this[i] === item) { return i; } }
																				return -1;
																				};
	// ------------------------------------------------------------------------------------------------------------------------------------------------
			Array.prototype.lastItem			= function() { return (!this.length) ? null : this[this.length - 1]; };
	// ------------------------------------------------------------------------------------------------------------------------------------------------
			Array.prototype.putItemFirst	= function(item)
																				{
																				var i = this.indexOfItem(item);
																				if (i != -1) { this.splice(i, 1); this.unshift(item); }
																				};
	// ------------------------------------------------------------------------------------------------------------------------------------------------
			Array.prototype.putItemLast		= function(item)
																				{
																				var i = this.indexOfItem(item);
																				if (i != -1) { this.splice(i, 1); this.push(item); }
																				};
	// ------------------------------------------------------------------------------------------------------------------------------------------------
			Array.prototype.removeItem		= function(item)
																				{
																				var i = this.indexOfItem(item);
																				if (i != -1) { this.splice(i, 1); }
																				};
	// ________________________________________________________________________________________________________________________________________________


/* ================================================================================================================================================== DATE EXTRAS ====
*/
		Date.isLongYear		= function(year) { return (Date.weeksInYear(year) == 53); };
// --------------------------------------------------------------------------------------------------------------------------------------------------
		Date.monthNames 	= ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
// --------------------------------------------------------------------------------------------------------------------------------------------------
		Date.monthNos 		= new (function() { for (var i = 0; i < Date.monthNames.length; i++) { this[Date.monthNames[i]] = i; } });
// --------------------------------------------------------------------------------------------------------------------------------------------------
		Date.startOfWeek	= function(year, week) { return Date.startOfYear(year).addDays(7 * week); };
// --------------------------------------------------------------------------------------------------------------------------------------------------
		Date.startOfYear	= function(year)
													{
													var dt = new Date(year, 0, 1);
													return dt.addDays(3 - (dt.getDay() + 2) % 7);
													};
// --------------------------------------------------------------------------------------------------------------------------------------------------
		Date.weeksInYear	= function(year) { return Date.startOfYear(year + 1).diffInWeeks(Date.startOfYear(year)); };
// --------------------------------------------------------------------------------------------------------------------------------------------------

	// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ
			Date.prototype.addDays			= function(numDays)
																			{
																			this.setUTCDate(this.getUTCDate() + numDays);
																			return this;
																			};
	// ------------------------------------------------------------------------------------------------------------------------------------------------
			Date.prototype.diffInWeeks	= function(dt) { return this.valueOf().diff(dt.valueOf()).intDiv(7 * 24 * 60 * 60 * 1000); };
	// ------------------------------------------------------------------------------------------------------------------------------------------------
			Date.prototype.getMonthName = function() { return Date.monthNames[this.getMonth()]; };
	// ------------------------------------------------------------------------------------------------------------------------------------------------
			Date.prototype.getWeekNo		= function() { return this.diffInWeeks(Date.startOfYear(this.getWeeksYear())); };
	// ------------------------------------------------------------------------------------------------------------------------------------------------
			Date.prototype.getWeeksYear	= function()
																			{
																			var yr = this.getFullYear();

																			if (Date.startOfYear(yr    ) >  this) { yr--; } else
																			if (Date.startOfYear(yr + 1) <= this) { yr++; }

																			return yr;
																			};
	// ------------------------------------------------------------------------------------------------------------------------------------------------
			Date.prototype.setShort			= function(shortDate)
																			{
																			this.setFullYear(shortDate.substr(6, 4), shortDate.substr(3, 2) - 1, shortDate.substr(0, 2));
																			return this;
																			};
	// ------------------------------------------------------------------------------------------------------------------------------------------------
			Date.prototype.toShort			= function()
																			{
																			return  this.getDate().toString().pad('L', 2, '0') + '/' +
																						 (this.getMonth() + 1).toString().pad('L', 2, '0') + '/' + this.getFullYear();
																			};
	// ________________________________________________________________________________________________________________________________________________


/* ================================================================================================================================================== NUMBER EXTRAS ====
*/
	// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ
			Number.prototype.diff   = function(val) { return Math.abs(this - val); };
	// ------------------------------------------------------------------------------------------------------------------------------------------------
			Number.prototype.intDiv = function(divBy) { if (divBy) { return parseInt(this / divBy, 10); } };
	// ________________________________________________________________________________________________________________________________________________


/* ================================================================================================================================================== STRING EXTRAS ====
*/
	// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ
			String.prototype.insert = function(str, pos) { return this.substr(0, pos) + str + this.substr(pos); };
	// ------------------------------------------------------------------------------------------------------------------------------------------------
			String.prototype.pad    = function(padSide, minLength, padChar)
																	{
																	var str = '';
																	if (this.length < minLength) { str = padChar.repeat(minLength - this.length); }
																	return (padSide == 'L') ? str + this : this + str;
																	};
	// ------------------------------------------------------------------------------------------------------------------------------------------------
			String.prototype.repeat = function(count)
																	{
																	for (var i = 0, str = ''; i < count; i++) { str += this; }
																	return str;
																	};
	// ________________________________________________________________________________________________________________________________________________


/* ================================================================================================================================================== CALENDAR PERIOD ====
*/
		function CalendarPeriod(rng)
			{
			var dat = new Date();

			this.setRange(rng || { units: 'm', firstYear: dat.getFullYear(), firstPeriod: dat.getMonth() - 1, interval: 3 });
			}

	// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ
			CalendarPeriod.prototype.getText		= function(period)
																							{
																							if (this.units == 'm') { return Date.monthNames[this[period + 'Period']]; }
																																else { return ((this.units == 'q') ? 'Q' : 'wk') + (this[period + 'Period'] + 1); }
																							};
	// ------------------------------------------------------------------------------------------------------------------------------------------------
			CalendarPeriod.prototype.moveRange	= function(dir)
																							{
																							dir *= this.interval;

																							if (this.units == 'yyyy')
																								{
																								this.firstYear += dir;
																								this.finalYear += dir;
																								}
																							else
																								{
																								this.setPeriod('first', this.firstPeriod + dir);
																								this.setPeriod('final', this.finalPeriod + dir);
																								}

																							this.resetDate();
																							};
	// ------------------------------------------------------------------------------------------------------------------------------------------------
			CalendarPeriod.prototype.resetDate	= function()
																							{
																							if (this.units == 'ww')
																								{
																								this.firstDate = Date.startOfWeek(this.firstYear, this.firstPeriod);
																								}
																							else
																								{
																								this.firstDate = new Date(this.firstYear, this.firstPeriod * ((this.units == 'q') ? 3 : 1), 1);
																								}
																							};
	// ------------------------------------------------------------------------------------------------------------------------------------------------
			CalendarPeriod.prototype.setPeriod	= function(period, val)
																							{
																							var yr = this[period + 'Year'],
																									mx = (this.units == 'q') ? 4 : ((this.units == 'm') ? 12 : Date.weeksInYear(yr)),
																									sn = 1;

																							if ((val < 0) || (val >= mx))
																								{
																								if (val < 0)
																									{
																									sn = -1;
																									if (this.units == 'ww') { mx = Date.weeksInYear(yr - 1); }
																									}

																								val -= sn * mx; yr += sn;

																								if ((val < 0) || (val >= mx))
																									{
																									if (this.units == 'ww') { mx = Date.weeksInYear(yr - (val < 0)); }
																									val -= sn * mx; yr += sn;
																									}

																								this[period + 'Year'] = yr;
																								}

																							this[period + 'Period'] = val;
																							};
	// ------------------------------------------------------------------------------------------------------------------------------------------------
			CalendarPeriod.prototype.setRange		= function(opts)
																							{
																							this.units = opts.units;
																							this.interval = opts.interval;

																							if ('firstYear' in opts)
																								{
																								this.firstYear = opts.firstYear;
																								if (this.units == 'yyyy') { this.firstPeriod = 0; } else { this.setPeriod('first', opts.firstPeriod || 0); }
																								}
																							else
																								{
																								this.firstDate = opts.firstDate;
																								this.firstYear = this.firstDate[(this.units == 'ww') ? 'getWeeksYear': 'getFullYear']();

																								if (this.units == 'yyyy') { this.firstPeriod = 0; }
																								else
																									{
																									if (this.units == 'ww') { this.setPeriod('first', this.firstDate.getWeekNo()); }
																																		else	{ this.setPeriod('first', this.firstDate.getMonth().intDiv((this.units == 'q') ? 3 : 1)); }
																									}
																								}

																							this.finalYear = this.firstYear;

																							if (this.units == 'yyyy') { this.finalYear += this.interval - 1; }
																																	else	{ this.setPeriod('final', this.firstPeriod + this.interval - 1); }

																							this.resetDate();
																							};
	// ------------------------------------------------------------------------------------------------------------------------------------------------
			CalendarPeriod.prototype.toQryStr		= function(cSep) { return cSep + this.firstDate.toShort() + cSep + this.interval + cSep + this.units; };
	// ------------------------------------------------------------------------------------------------------------------------------------------------
			CalendarPeriod.prototype.toString		= function()
																							{
																							var str, spansYears = (this.finalYear != this.firstYear);

																							if (this.units == 'yyyy') { str = this.firstYear + ((spansYears) ? '~' + this.finalYear : ''); }
																							else
																								{
																								str = this.getText('first');

																								if (this.interval == 1) { str += ' ' + this.firstYear; }
																								else
																									{
																									str += ((spansYears) ? ' ' + this.firstYear : '') + '~' + this.getText('final') + ' ' + this.finalYear;
																									}
																								}

																							return str;
																							};
	// ________________________________________________________________________________________________________________________________________________


/* ================================================================================================================================================== STEPPED TIME ====
*/
		function SteppedTime(stepValue)
			{
			this.minutesPerStep	= 15;

			if (typeof stepValue == 'number') { this.value = stepValue; } else { this.toString(stepValue); }
			}

	// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ
			SteppedTime.prototype.stepsPerDay	= function() { return (24 * 60).intDiv(this.minutesPerStep); };
	// ------------------------------------------------------------------------------------------------------------------------------------------------
			SteppedTime.prototype.toString		= function(str)
																						{
																						var h, m, t;

																						if (str)
																							{
																							h = parseInt(str, 10);
																							m = parseInt(str.slice(-2), 10);
																							this.value = (60 * h + m).intDiv(this.minutesPerStep);
																							}
																						else
																							{
																							t = this.value * this.minutesPerStep;
																							h = t.intDiv(60);
																							m = t % 60;
																							}

																						return h.toString().pad('L', 2, '0') + ':' + m.toString().pad('L', 2, '0');
																						};
	// ________________________________________________________________________________________________________________________________________________


/* ================================================================================================================================================== DATE/TIME(S) ====
**
**	Opts:
**		dataType	- 'date' | 'datetime' | 'datetimes' | 'time' | 'times' - MUST BE SPECIFIED
**		value			- initial value as a string formatted according to dataType
**								'dd/mm/yyyy' | 'hh:mm dd/mm/yyyy' | 'hh:mm~hh:mm dd/mm/yyyy' | 'hh:mm' | 'hh:mm~hh:mm'
*/
		function Datetimes(opts)
			{
			this.dataType = this.dataText	= opts.dataType;
			this.pattern  = '';

			if (this.useDate())
				{
				this.pattern  = '/';
				if (opts.value) { this.datePart = opts.value.slice(-10); } else { this.datePart = (new Date()).toShort(); }
				}

			if (this.useTime())
				{
				this.pattern += ':';
				this.timeFrom = new SteppedTime(opts.value && opts.value.substr(0, 5));

				if (this.useRange())
					{
					this.pattern += '~';
					this.timeTo		= new SteppedTime(opts.value && opts.value.substr(6, 5));
					}

				if (this.datePart)
					{
					this.pattern += ' ';
					this.dataText	= this.dataType.insert(' & ', 4);
					}
				}
			}

	// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ
			Datetimes.prototype.toString	= function(str)
																				{
																				var t = '';

																				if (this.timeFrom)
																					{
																					t = this.timeFrom.toString(str && str.substr(0, 5));

																					if (this.timeTo)	 { t += '~' + this.timeTo.toString(str && str.substr(6, 5)); }
																					if (this.datePart) { t += ' '; }
																					}

																				if (this.datePart)
																					{
																					if (str) { this.datePart = str.slice(-10); }

																					t += this.datePart;
																					}

																				return t;
																				};
	// ------------------------------------------------------------------------------------------------------------------------------------------------
			Datetimes.prototype.useDate		= function() { return (this.dataType.substr(0, 4) == 'date'); };
	// ------------------------------------------------------------------------------------------------------------------------------------------------
			Datetimes.prototype.useRange	= function() { return (this.dataType.slice(-1) == 's'); };
	// ------------------------------------------------------------------------------------------------------------------------------------------------
			Datetimes.prototype.useTime		= function() { return (this.dataType != 'date'); };
	// ________________________________________________________________________________________________________________________________________________


/* ================================================================================================================================================== GENERAL FUNCTIONS ====
*/
	// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ
			function formToQryStr(formName, inputNames)
				{
				var data = {}, $frm = $('form[name=' + formName + ']');

				for (var i = 0; i < inputNames.length; i++) { data[inputNames[i]] = $('[name=' + inputNames[i] + ']', $frm).val(); }

				return $.param(data);
				}
	// ------------------------------------------------------------------------------------------------------------------------------------------------
			function makeQueryURL(pageName, formName, inputNames)
				{
				var newURL = pageName, parms = {}, iQry = pageName.indexOf('?'), pg;

				if (iQry == -1) { pg = pageName; } else { pg = pageName.substring(0, iQry); }

				if (location.href.indexOf(pg) == -1)
					{
					delete SSN_State.USX;
					delete SSN_State.USY;
					}
				else
					{
					SSN_State.USX = $(window).scrollLeft();
					SSN_State.USY = $(window).scrollTop();
					}

				for (var nm in SSN_State)
					{
					if (SSN_State[nm] && (pageName.indexOf(nm + '=') == -1)) { parms[nm] = SSN_State[nm]; }
					}

				if (parms) 		{ newURL += ( (iQry == -1) ? '?' : '&' ) + $.param(parms); }
				if (formName) { newURL += '&' + formToQryStr(formName, inputNames); }

				return newURL;
				}
	// ------------------------------------------------------------------------------------------------------------------------------------------------
			function positionCentredInWindow(width, height)
				{
				return { left: Math.round(($(window).width()  - width)  / 2) + $(window).scrollLeft(),
								 top : Math.round(($(window).height() - height) / 2) + $(window).scrollTop() };
				}
	// ------------------------------------------------------------------------------------------------------------------------------------------------
			function prepPageHeader()
				{
				$('.page-head').
					find('.pro-menu a').
						bind( { contextmenu	: function() { window.open( makeQueryURL($(this).attr('href')), 'View2', '' ).focus(); return false; },
										click				: function() { return setLocationURL( $(this).attr('href') ); }
								}	).
						end().
					find('.tcp-menu').
						find('a[href*="/admin/"]').bind('click', function() { return setLocationURL( $(this).attr('href') ); } ).end().
						find('a[href$="logout"]' ).bind('click', function() { location.href = location.href + '&logout=1'; return false; } );

				return $('.page-head').length;
				}
	// ------------------------------------------------------------------------------------------------------------------------------------------------
			function setLocationURL(pageURL)
				{
				location.href = makeQueryURL(pageURL);
				return false;
				}
	// ------------------------------------------------------------------------------------------------------------------------------------------------
			function setupBlockUI()
				{
				$.extend( $.blockUI.defaults, { baseZ			: 20000,
																				css				: {},
																				fadeIn		: 0,
																				fadeOut		: 0,
																				overlayCSS: { background: 'url(/common/styles/images/check_black1024.gif)', opacity: 1, cursor: 'wait' }
																				} );
				}
	// ________________________________________________________________________________________________________________________________________________

