/*	GLOBAL VARIABLES:
	------------------------------------------------------------------------------------------------------------------------------------------- */
var tnCal;
var tnCalHiddenSelects = null;

if (!Array.prototype.map) {
	Array.prototype.map = function(f) {
		var result = [], length = this.length;
		for (var i = 0; i<length; i++) {
			result.push(f(this[i]));
		}
		return result;	
	};
}

/*	TN CALENDAR:
	------------------------------------------------------------------------------------------------------------------------------------------- */
function TnCalendar() {
	this.MinDate = new Date();
	
	this.CurrentMonth = this.MinDate.getMonth() + 1;
	this.CurrentYear = this.MinDate.getFullYear();
	this.Target = null;
	this.TargetForMinDate = null;
	this.Holder = $('CalendarHolder');
	
	this.PrevMonthCaption = "Previous month";
	this.NextMonthCaption = "Next month";

	this.FirstDayOfWeek = 1; // monday

	this.SetMonthCaptions = function(prevMonthCaption, nextMonthCaption) {
		this.PrevMonthCaption = prevMonthCaption;
		this.NextMonthCaption = nextMonthCaption;
	};

	// SHOW CALENDAR:
	this.Show = function(target, callBack, minDateTarget) {
		// SETUP:
		this.MinDateTarget = minDateTarget;
		this.Target = target;
		this.ParseTargetDate();
		this.CallBack = callBack;

		// DRAW CALENDAR:
		this.Draw(this.CurrentMonth, this.CurrentYear);

		// MOVE HOLDER AND SHOW:
		var positions = Position.cumulativeOffset(this.Target);
		this.Holder.style.left = positions[0] + 'px';
		this.Holder.style.top = positions[1] + Element.getHeight(this.Target) + 3 + 'px';
		Element.show(this.Holder);
	
		// HIDE SELECTS:
		tnCalHideSelectsUnder(this.Holder);
	};

	// HIDE CALENDAR:
	this.Hide = function() {
		tnCalShowSelectsUnder(this);
		this.EmptyHolder();
		Element.hide(this.Holder);
	};

	// EMPTY THE HOLDER:
	this.EmptyHolder = function() {
		this.Holder.innerHTML = '';
	};

	// SELECT DATE:
	this.SelectDate = function(day) {
		var formatted = tnCalFormatDate(day, this.CurrentMonth, this.CurrentYear);

		if (typeof(this.Target.value) != 'undefined') {
			this.Target.value = formatted;
		} else if (typeof(this.Target.innerHTML) != 'undefined') {
			this.Target.innerHTML = formatted;
		} else {
			alert(formatted);
		}

		this.Hide();

		if (this.CallBack) {
			this.CallBack(formatted);
		}
	};
	
	// GO TO NEXT MONTH:
	this.NextMonth = function() {
		var currentMonth = this.CurrentMonth;
		var currentYear = this.CurrentYear;

		if (currentMonth.length > 1 && currentMonth.substring(0,1) == '0') {
			currentMonth = currentMonth.substring(1,2);
		}

		var newMonth = parseInt(currentMonth, 10) + 1;
		var newYear = parseInt(currentYear, 10);

		if (newMonth > 12) {
			newMonth = 1;
			newYear = parseInt(newYear, 10) + 1;
		}

		this.CurrentMonth = newMonth;
		this.CurrentYear = newYear;

		this.EmptyHolder();
		this.Draw(newMonth, newYear);
	};

	// GO TO PREVIOUS MONTH:
	this.PrevMonth = function() {
		var currentMonth = this.CurrentMonth;
		var currentYear = this.CurrentYear;

		var newMonth = parseInt(currentMonth, 10) - 1;
		var newYear = currentYear;

		if (newMonth < 1) {
			newMonth = 12;
			newYear = parseInt(newYear, 10) - 1;
		}

		this.CurrentMonth = newMonth;
		this.CurrentYear = newYear;

		this.EmptyHolder();
		this.Draw(newMonth, newYear);
	};

	// DRAW CALENDAR:
	this.Draw = function(month, year) {
		// TABLE BEGINNING:
		var tbl = '';		

		// TOP:
		tbl += this.DrawTop(month, year);

		// CALENDAR:
		tbl += this.DrawDays(month, year);

		// TABLE END:
		tbl += this.DrawBottom();

		this.Holder.innerHTML = tbl;
	};

	// DRAW TOP OF CALENDAR TABLE:
	this.DrawTop = function(month, year) {
		var tbl = '<table border="0" cellspacing="1" cellpadding="0" class="TnCalendar">';
		var cDateFirstDay = new Date(year, month - 1, 1);

		var prev = '<td class="Link" onclick="tnCal.PrevMonth();"><img src="' + appFolder + 'images/btn_calendar_prev_year.gif" width="18" height="14" alt="' + this.PrevMonthCaption + '" /></td>';
		var next = '<td class="Link" onclick="tnCal.NextMonth();"><img src="' + appFolder + 'images/btn_calendar_next_year.gif" width="18" height="14" alt="' + this.NextMonthCaption + '" /></td>';

		if (this.MinDate > cDateFirstDay) {
			prev = '<td class="NoLink"><img src="' + appFolder + 'images/btn_calendar_prev_year_off.gif" width="18" height="14" alt="Previous year" /></td>';
		}
		
		var close = '<td class="Link CloseCalendar" onclick="tnCal.Hide();">X</td>';

		// NAV:
		tbl += '<tr class="Head">' + prev + '<td class="CalendarMonthName" colspan="4">' + tnCalMonthNames[month - 1] + ' ' + year + '</td>' + next + close + '</tr>';

		// DAYS:
		var dayIndex = this.FirstDayOfWeek;
		tbl += '<tr class="DayHeads">' +
			'<td>' + tnCalDayNames[dayIndex++ % 7] + '</td>' +
			'<td>' + tnCalDayNames[dayIndex++ % 7] + '</td>' +
			'<td>' + tnCalDayNames[dayIndex++ % 7] + '</td>' +
			'<td>' + tnCalDayNames[dayIndex++ % 7] + '</td>' +
			'<td>' + tnCalDayNames[dayIndex++ % 7] + '</td>' +
			'<td>' + tnCalDayNames[dayIndex++ % 7] + '</td>' +
			'<td>' + tnCalDayNames[dayIndex++ % 7] + '</td>' +
			'</tr>';

		return tbl;
	};

	// DRAW ACTIVE DAYS:
	this.DrawDays = function(month, year) {
		// First day of month at 12 o'clock (lunchtime) to prevent weird effects when adding offset below
		var monthFirstDay = new Date(year, month - 1, 1, 12); 

		// Create dates array
		var dates = [];
		var oneDay = 24 * 60 * 60 * 1000;
		for (var offset = -6; offset <= 31 + 6; offset++) {
			dates.push(new Date(monthFirstDay.getTime() + (offset * oneDay)));
		}

		// Strip the days before this.FirstDayOfWeek
		while (dates[0].getDay() != this.FirstDayOfWeek) { dates.shift(); }

		// Collect days in weeks
		weeks = [];
		while (dates.length > (weeks.length + 1) * 7) {
			weeks.push(dates.slice(weeks.length * 7, (weeks.length + 1) * 7));
		}

		// Remove weeks at end with days only from next month
		while (weeks[weeks.length - 1][0].getMonth() + 1 != month) {
			weeks.pop();
		}

		var minDate = this.MinDate;

		// Return table with joined weeks and days
		return '<tr class="Days">' + weeks.map(function(week) {
			return week.map(function(date) {
				if (date.getMonth() + 1 == month) {
					if (date >= minDate) {
						return '<td onclick="tnCal.SelectDate(' + date.getDate() + ');">' + date.getDate() + '</td>';
					} else {
						return '<td class="Inactive">' + date.getDate() + '</td>';
					}
				} else {
					return '<td class="Inactive">&nbsp;</td>';
				}
			}).join('');
		}).join('</tr><tr class="Days">') + '</tr>';
	};

	// DRAW BOTTOM OF CALENDAR TABLE:
	this.DrawBottom = function() {
		return '</table>';
	};

	// PARSE CURRENT DATE:
	this.ParseTargetDate = function() {
		var currentValue = this.Target.value;

		try {
			if (tnCalValidateDateString(currentValue)) {
				this.CurrentYear = currentValue.substring(0,4);
				this.CurrentMonth = currentValue.substring(5,7);
			}

			if (this.MinDateTarget) {
				this.MinDate = tnCalGetDateFromString(this.MinDateTarget.value);
			} else {
				this.MinDate = new Date();
			}
		} catch(err) {
			alert(err);
		}
	};
}



/*	FUNCTIONS:
	------------------------------------------------------------------------------------------------------------------------------------------- */
function tnCalGetBlankCells(count) {
	var cells = '';
	
	for (var i = 0; i < count; i++) {
		cells += '<td class="Inactive">&nbsp;</td>';
	}

	return cells;
}

function tnCalGetDayCount(month, year) {
	var days = 0;

	if (month == 1 || month == 3 || month == 5 || month == 7 || month == 8 || month == 10 || month == 12) {
		days = 31;
	} else if (month == 4 || month == 6 || month == 9 || month == 11) {
		days = 30;
	} else {
		// Safe leap year check until 2100
		days = (year % 4 === 0) ? 29 : 28;
	}

	return days;
}

function tnCalFormatDate(day, month, year) {
	var m2 = '00' + month;
		m2 = m2.substr(m2.length - 2);
	var d2 = '00' + day;
		d2 = d2.substr(d2.length - 2);
	return year + '-' + m2 + '-' + d2;
}

function tnCalGetDateFromString(str) {
	try {
		return new Date(str.substring(0,4), str.substring(5,7) - 1, str.substring(8,10));
	} catch(err) {
		return new Date();
	}
}

function tnCalHideSelectsUnder(cal) {
	var selects = document.getElementsByTagName('select');
	tnCalShowSelectsUnder(cal);
	tnCalHiddenSelects = [];

	for (var i = 0; i < selects.length; i++) {
		var selectPosition = Position.cumulativeOffset(selects[i]);
		if (Position.within(cal, selectPosition[0], selectPosition[1])) {
			selects[i].style.visibility = 'hidden';
			tnCalHiddenSelects.push(selects[i]);
		}
	}
}

function tnCalShowSelectsUnder(cal) {	
	if (tnCalHiddenSelects) {
		for (var i =0; i<tnCalHiddenSelects.length; i++) {
			tnCalHiddenSelects[i].style.visibility = 'visible';
		}
	}
	tnCalHiddenSelects = [];
}

function tnCalValidateDateString(toValidate) {
	var pattern = new RegExp(/(\d{4})-(\d{1,2})-(\d{1,2})/);
	return toValidate.match(pattern);
}

