// $Id: calendar.js,v 1.10 2009-11-02 16:58:16 smulcahy Exp $
// � 2004 Orbis Technology Ltd. All rights reserved.

// Updated version of the admin screens input calendar.
// Creates and airline style date picker when the user clicks on
// a small calendar image.
//
// You can create a calendar in two ways. What I expect to be the most
// common is to set the class of your input to "calendar". The calendar
// will be automatically created onLoad. You can create it with also
// "time" you can request specify time. You can optionally add, "lo", or "high"
// to the class to specify a default value.
//
//   <input class="calendar time">
//
// Secondly, you can use the constructor to create one.
//
//   new Calendar(inputNode);
//
// Bugs:
//   It has been noticed that divs in IE do not interact will with select boxes.
//
// Reference:
//   http://www.quirksmode.org/js/events_properties.html


//-------------------------------------------------------------------------
// Dependencies
//-------------------------------------------------------------------------
// also expects to find calendar.css and calendar.png in the gif path
Package.provide("calendar");
Package.require("date");


//-------------------------------------------------------------------------
// Constructors
//-------------------------------------------------------------------------

// Create a new calendar
//
//   input    - input to create calendar from
//   showTime - show the time input
//   default  - default ('high' or 'lo' or null)
//
function Calendar(input, childInput, showTime, def) {
	if (showTime == null)
		showTime = false;

	this.input    = input;
	this.childInput = childInput;
	this.showTime = showTime;
	this.def      = def;

	if (Calendar.container == null) {
		Calendar.container = document.createElement("div");
		Calendar.container.id = "calendar";
		// prevent the parent of the input style this
		document.body.appendChild(Calendar.container);
	}

	// the click image to pop the calendar up
	var img = document.createElement("img");
	img.style.float = "left";
	img.src = gifUrl + "/calendar.png";
	img.style.cursor = "pointer";
	img.onclick = Calendar.show;
	input.onclick = Calendar.show;
	img.className = input.name;
	img.id = "calendarImg" + Calendar.maxID++;

	// a very verbose way of doing this.input.parentNode.insertAfter(img, input);
	var nextNode = null; // the node after the input
	var isNext = false; // if the next node is the nextNode
	for (i in this.input.parentNode.childNodes) {
		var node = this.input.parentNode.childNodes[i];

		if (isNext) {
			nextNode = node;
			break;
		}

		if (node == input) {
			isNext = true;
		}
	}


	if (nextNode != null)
		this.input.parentNode.insertBefore(img, nextNode);
	else
		this.input.parentNode.appendChild(img);


	this.selectedDate = new Date();
	this.currentDate  = new Date();

	// this is a great way to look up things related to other things
	// don't always work in firefox

	Calendar.calendars[img.id]   = this;
	Calendar.calendars[input.id] = this;
}


//-------------------------------------------------------------------------
// Class Methods
//-------------------------------------------------------------------------

// on load, hunt down those input with a calendar class name
Calendar._load = function() {
	if (document.addEventListener)
		document.addEventListener("mousedown", Calendar.hide, true);
	else
		document.attachEvent("onmousedown", Calendar.hide);

	var inputs = document.getElementsByTagName("input");

	for (i in inputs) {
		var input = inputs[i];

		// ie bug
		if (!input.className || input.className.indexOf("calendar") == -1)
			continue;

		var showTime = false;
		var def = null;

		if (input.className.indexOf("time") >= 0)
			showTime = true;

		if (input.className.indexOf("lo") >= 0)
			def = "lo";

		if (input.className.indexOf("high") >= 0)
			def = "high";

		var childInput=null;
		if (input.className.indexOf("child=") >= 0) {
			var pos = input.className.indexOf("child=")+6;

			var child = "";

			_char = input.className.charAt(pos);
			while ((pos<input.className.length) && (_char != ' ')) {
				child = child.concat(_char);
				pos++;
				_char = input.className.charAt(pos);
			}

			childInput = document.getElementsByName(child)[0];

		}

		new Calendar(input, childInput, showTime, def);
	}
}



//-------------------------------------------------------------------------
// Object Methods
//-------------------------------------------------------------------------
// draw the calendar
Calendar.draw = function() {
	if (Calendar.container.style.display != "block") {
		return;
	}

	var today = new Date();

	var html  = "";

	html += "<table cellspacing='0'>";

	html += "<tr>";
	html += "<td colspan='7' class='yearMonth' nowrap>";

	// month control
	html += "<a href='javascript: Calendar.calendar.currentDate.prevMonth(); Calendar.draw();'>" +
		Calendar.prevSymbol + "</a> ";
	html += "<select onChange='" +
		"Calendar.calendar.currentDate.setMonth(this.selectedIndex);" +
		"Calendar.draw();'>";
	for (var i = 0; i < 12; i++) {
		html += "<option" +
			(i == Calendar.calendar.currentDate.getMonth() ? " selected" : "") + ">" +
			Date.nameOfMonth[i] + "</option>";
	}
	html += "</select>";
	html += " <a href='javascript: Calendar.calendar.currentDate.nextMonth(); " +
		"Calendar.draw();'>" + Calendar.nextSymbol + "</a>";


	// year control
	html += " ";
	html += "<a href='javascript: Calendar.calendar.currentDate.prevYear(); " +
		 "Calendar.draw();'>" + Calendar.prevSymbol + "</a> ";
	html += "<select onChange='" +
		 "Calendar.calendar.currentDate.setYear(this.options[this.selectedIndex].text);" +
		 "Calendar.draw();' class=calendar>";
	for (var i = Calendar.calendar.currentDate.getFullYear() - Calendar.yearRange;
		i <= Calendar.calendar.currentDate.getFullYear() + Calendar.yearRange; i++) {

		html += "<option" + (i == Calendar.calendar.currentDate.getFullYear() ?
			" selected" : "") + ">" + i + "</option>";
	}
	html += "</select>";
	html += " <a href='javascript: Calendar.calendar.currentDate.nextYear();" +
		 "Calendar.draw();'>" + Calendar.nextSymbol + "</a>";


	// add the name of days, use 14% to keen it spaced equally
	html += "<tr>";
	for (var i = 0; i < 7; i++) {
		html += "<td class='dayName' width='14%'>" +
			Date.nameOfDay[i].substring(0,2);
	}
	html += "<tr>";

	Calendar.calendar.currentDate.set(Calendar.calendar.currentDate.getFullYear(),
		Calendar.calendar.currentDate.getMonth(), 1);

	// put some padding in place
	if (Calendar.calendar.currentDate.getDay() > 0) {
		html += "<td colspan=" + Calendar.calendar.currentDate.getDay() + ">&nbsp";
	}
	for (var i = 1; i < Calendar.calendar.currentDate.getDaysInMonth() + 1; i++) {

		Calendar.calendar.currentDate.setDate(i);

		if (Calendar.calendar.currentDate.getDay() == 0) {html += "<tr>";}

		var isToday    = Calendar.calendar.currentDate.equalDate(today);
		var isSelected = Calendar.calendar.currentDate.equalDate(Calendar.calendar.selectedDate);
		var isWeekend  = Calendar.calendar.currentDate.getDay() == 0 || Calendar.calendar.currentDate.getDay() == 6;

		// we style the anchor today's style before the selectedDate style,
		// but the td the otherway around
		var clazz = "date" + (isSelected ? " selectedDate" : "") +
			(isToday ? " today" : "" ) + (isWeekend ? " weekend" : "");

		var script = "Calendar.select(" +
			Calendar.calendar.currentDate.getFullYear() + ", " +
				Calendar.calendar.currentDate.getMonth() + ", " + i + ", " + Calendar.calendar.showTime + ");"

		html += "<td><a href='javascript: " + script + "' class='" + clazz + "'>" + i + "</a>";
	}

	// pad the end of the calendar
	if (Calendar.calendar.currentDate.getDay() < 6) {
		html += "<td colspan=" + (6 - Calendar.calendar.currentDate.getDay) +">&nbsp";
	}
	Calendar.calendar.currentDate.setDate(1);

	// add some more controls
	html += "<tr><td colspan='7' style='text-align: center;'>";

	if (Calendar.calendar.showTime) {
		html += "<input size='8' maxlength='8' onKeyUp='" +
			"Calendar.fromTime(event);" +
			"' value='" + Calendar.calendar.selectedDate.format("%H:%M:%S") + "'>";
	}

	html += "</table>";

	Calendar.container.innerHTML = html;
}


// select the specifed date
Calendar.select = function (year, month, date) {

	if (!Calendar.calendar.selectedDate) {
		Calendar.calendar.selectedDate = new Date();
	}

	// set the date in this way and in this order to avoid issue.
	// See support tickets #23926 and #37747
	Calendar.calendar.selectedDate.set(null,null,null);

	Calendar.calendar.selectedDate.set(year, month, date);

	var oldValue = Calendar.calendar.input.value;
	Calendar.calendar.input.value =
		Calendar.calendar.selectedDate.format("%a %d-%m-%y");

	// if the child input is not null, was blank, or was the same as the
	// value used to be, update it to the new value
	if ( (Calendar.calendar.childInput!=null) &&
		((Calendar.calendar.childInput.value == '') || (Calendar.calendar.childInput.value == oldValue) ) ) {
		Calendar.calendar.childInput.value =
			Calendar.calendar.selectedDate.format("%a %d-%m-%y");
	}

	// we may need to change the visibility of popup calendars
	Calendar.hide();
}


// display the calendar
Calendar.show = function (e) {
	if (!e)
		e = window.event;

	var t = e.target ? e.target : e.srcElement;

	// we're showing the calendar for this item
	Calendar.calendar = Calendar.calendars[t.id];

	Calendar.fromInput();

	var window_x = window.screen.width;
	var window_y = window.screen.height;

	var centre_x = window_x / 2;
	var centre_y = window_y / 2;

	var offset_x = 50;
	var offset_y = 180;

	var x_pos = centre_x + offset_x;
	var y_pos = centre_y + offset_y;

	Calendar.container.style.display = "block";

	Calendar.draw();
}


// hide the calendar
Calendar.hide = function (e) {
	if (!e)
		e = window.event;

	// if trigger by and event, this needs to one where the parent is ours
	if (e) {
		var t = e.target ? e.target : e.srcElement;

		while (t != null) {
			if (t.id == "calendar")
				return;
			t = t.parentNode;
		}
	}
	if (Calendar.container != null)
		Calendar.container.style.display = "none";
}


// user the value of the input to set the time part of the selected date
Calendar.fromTime = function(e) {
	if (!e)
		e = window.event;

	var t = e.target ? e.target : e.srcElement;

	var d  = new Date(Calendar.calendar.selectedDate);

	if (!d.fromInformixString(t.value))
		return;

	if (Calendar.calendar.selectedDate == d)
		return;

	Calendar.calendar.selectedDate = d;

	Calendar.calendar.input.value =
		Calendar.calendar.selectedDate.toInformixString(Calendar.calendar.showTime);
}


// set the date from this input
Calendar.fromInput = function () {

	var d = new Date();

	if (Calendar.calendar.def != null) {
		switch (Calendar.calendar.def) {
			case "lo":
				Calendar.calendar.selectedDate.setTimePart(0, 0, 0);
				break;
			case "high":
				Calendar.calendar.selectedDate.setTimePart(23, 59, 59);
				break;
			default:
				throw "Unknown default value";
		}
	}

	d.fromInformixString(Calendar.calendar.input.value);

	Calendar.calendar.selectedDate = d;
}


//-------------------------------------------------------------------------
// Class attributes
//-------------------------------------------------------------------------
Calendar.container       = null;
Calendar.calendar        = null; // currently displayed calendar
Calendar.prevSymbol      = "&#171;";
Calendar.nextSymbol      = "&#187;";
Calendar.yearRange       = 6;
Calendar.calendars       = [];
Calendar.maxID        = 0;



if (window.addEventListener)
	window.addEventListener("load", Calendar._load, true);
else
	window.attachEvent("onload", Calendar._load);


