// --------------------------------------------------------------------
// Simple calendar
// --------------------------------------------------------------------

/*
Copyright © 2004 Web-Engineer
The software is owned by web-engineer. and is protected by United Kingdom copyright laws,
international treaty provisions, and all other applicable national laws.
You may not modify, adapt, translate, reverse engineer, decompile, dissasemble or otherwise
attempt to discover the code and algorithms of the software.

http://www.web-engineer.co.uk for more information
*/

//required template vars
/*
calendarCellWidth
calendarCellHeight
calendarTopBarHeight
calendarMonthNames
calendarDaysTemplate
calendarTitleTemplate
calendarNoTitleTemplate
*/
//global vars
var calendarLayers = new Array();
var calendarMouseX = 0;
var calendarMouseY = 0;
var offsetX = 3;
var offsetY = -3;
var zVal = 1;
//layer dragging constants
var dragElement,dx,dy;
//helper functions
function intToChar2(val){
	var str = val+"";
	if(str.length==1){
		str = "0"+str;
	}
	return str;
}
function dmyToShortUnix(d,m,y){
	//DD/MM/YYYY -> YYYYMMDD (MM/DD zero based)
	d = intToChar2(d);
	m = intToChar2(m);
	return ""+y+m+d;
	
}
function formatToDate(obj,date, month, year){
	month = intToChar2(month);
	date = intToChar2(date);
	obj.value = date + "/" + month + "/" + year;
}

function beginDrag(element,event){
	var x = parseInt(element.style.left);
	var y = parseInt(element.style.top);
	dx = event.clientX - x+document.body.scrollLeft;
	dy = event.clientY - y+document.body.scrollTop;

	for(i=0; i<calendarLayers.length; ++i){
		if(calendarLayers[i]!=element){
			calendarLayers[i]._getLayer().style.zIndex = 1;
		}
	}
	element.style.zIndex = 2;
	if(document.addEventListener){
		document.addEventListener("mousemove",moveHandler, true);
		document.addEventListener("mouseup",upHandler, true);
	}else if(document.attachEvent){
		document.attachEvent("onmousemove",moveHandler);
		document.attachEvent("onmouseup",upHandler);
	}
	stopProp(event);
	
	dragElement = element;
}
// --------------------------------------------------------------------
// Main method
// --------------------------------------------------------------------
// string objName Name, callbackFunc , [title, min date value as short unix time stamp, max date value as short unix time stamp]
function calendar(objName, callbackFunc){
	//::TODO:: add browser version check here
	this.today = new Date();
	this.date = this.today.getDate();
	this.month = this.today.getMonth();
	this.year = this.today.getFullYear();
	this.objName = objName;
	this.callbackFunc = callbackFunc;
	this.title = arguments[2] ? arguments[2] : '';
	this.minDate = arguments[3] ? arguments[3] : 0;
	this.maxDate = arguments[4] ? arguments[4] : 99999999; 
	this.selectedDay = null;
	this.selectedMonth = null;
	this.selectedYear = null;
	this.setDate = calendarSetDate;
	this.layerID = 'calendarLayer' + calendarLayers.length;

	this.currentMonth = this.month;
	this.currentYear = this.year;
	this.show = calendarShow;
	this.writeHTML = calendarWriteHTML;
	this._hideLayer = calendarHideLayer;
	this._showLayer = calendarShowLayer;
	this.setTitle = calendarSetTitle;
	this.setMaxDate = calendarSetMaxDate;
	this.setMinDate = calendarSetMinDate;
	this.setCurrentMonth = calendarSetCurrentMonth;
	this.setCurrentYear = calendarSetCurrentYear;
	this._setCellSize = calendarSetCellSize;	
	this._setHTML = calendarSetHTML;
	this._setLayerPosition = calendarSetLayerPosition;

	this._getLayer = calendarGetLayer;
	this._getLayerID = calendarGetLayerID;
	this._getDaysInMonth = calendarGetDaysInMonth;
	calendarLayers[calendarLayers.length] = this;
	this.writeHTML();
}
function calendarSetTitle(str){
	this.title = str;
	this.show(null,null,true);
}

// month, year[, set to true if you dont want to re-position]

function calendarShow(){
	var month, year, numdays, thisMonth, firstOfMonth;
	var previousMonth, previousYear, nextMonth, nextYear
	var prevImgStr, prevLinkStr, nextImgStr, nextLinkStr;
	var html;
	var ret, row, i, cssClass, LinkStr
	
	this.currentMonth = month = arguments[0] != null ? arguments[0] : this.currentMonth;
	this.currentYear  = year  = arguments[1] != null ? arguments[1] : this.currentYear;
	numdays = this._getDaysInMonth(month, year);
	thisMonth = new Date(year, month, 1);
	firstOfMonth = thisMonth.getDay();
	// Blanks
	ret = new Array(new Array());
	for(i=0; i<firstOfMonth; i++){
		ret[0][ret[0].length] = '<td class="calendarBlank"><img src="includes/web-engineer.co.uk/spacer.gif" height="1" width="1"></td>';
	}
	row = 0;
	i = 1;
	var j = 0;
	while(i <= numdays){
		if(ret[row].length == 7){
			ret[++row] = new Array();
			j=0;
		}
		j++;
		if(i == this.date && month == this.month && year == this.year){
			LinkStr = "<strong>"+(i++)+"</strong>";
			cssAdj="To";
		}else{
			LinkStr = (i++);
			cssAdj="";
		}
		shortUnixTime = parseInt(""+year+intToChar2(month+1)+intToChar2(i));
		if((shortUnixTime>this.maxDate+1)||(shortUnixTime<=this.minDate)){
					cssClass = 'calendar'+cssAdj+'DayDisabled';
					ret[row][ret[row].length] = '<td width="'+calendarCellWidth+'" height="'+calendarCellHeight+'" align="center" class="' + cssClass + '">' + LinkStr + '</td>';
		}else{
			cssClass = 'calendar'+cssAdj+'Day';
			if(((Number(month) + 1)==this.selectedMonth)&&(this.selectedDay==(i-1))&&(this.selectedYear==year)){
				ret[row][ret[row].length] = '<td width="'+calendarCellWidth+'" height="'+calendarCellHeight+'" style="background-color:'+calendarSelectedDayBackColour+';color:'+calendarSelectedDayColour+';" onClick="' + this.callbackFunc + '(' + (i-1) + ', ' + (Number(month) + 1) + ', ' + year + ');' + this.objName + '.setDate(' + (i-1) + ', ' + (Number(month) + 1) + ', ' + year + '); ' + this.objName + '._hideLayer()" align="center" class="' + cssClass + '" onMouseOver="this.style.backgroundColor=\''+calendarOverDayBackColour+'\';this.style.color=\''+calendarOverDayColour+'\';" onMouseOut="this.style.backgroundColor=\''+calendarSelectedDayBackColour+'\';this.style.color=\''+calendarSelectedDayColour +'\';">' + LinkStr + '</td>';					
			}else{
				ret[row][ret[row].length] = '<td width="'+calendarCellWidth+'" height="'+calendarCellHeight+'" onClick="' + this.callbackFunc + '(' + (i-1) + ', ' + (Number(month) + 1) + ', ' + year + ');' + this.objName + '.setDate(' + (i-1) + ', ' + (Number(month) + 1) + ', ' + year + '); ' + this.objName + '._hideLayer()" align="center" class="' + cssClass + '" onMouseOver="this.style.backgroundColor=\''+calendarOverDayBackColour+'\';this.style.color=\''+calendarOverDayColour+'\';" onMouseOut="this.style.backgroundColor=\''+calendarDayBackColour+'\';this.style.color=\''+calendarDayColour+'\';" style="background-color:'+calendarDayBackColour+';color:'+calendarDayColour+';" >' + LinkStr + '</td>';
			}
		}
	}
	if(j<7){
		for(i=j; i<7; i++){
			ret[row][i] = '<td class="calendarBlank"><img src="includes/web-engineer.co.uk/spacer.gif" height="1" width="1"></td>';
		}
	}
	for(i=0; i<ret.length; i++){
		ret[i] = ret[i].join('');
	}
	previousYear = thisMonth.getFullYear();
	previousMonth = thisMonth.getMonth() - 1;
	if(previousMonth < 0){
		previousMonth = 11;
		previousYear--;
	}
	
	nextYear = thisMonth.getFullYear();
	nextMonth = thisMonth.getMonth() + 1;
	if(nextMonth > 11){
		nextMonth = 0;
		nextYear++;
	}
	
	prevLinkStr = '<a class="handLink" onClick="' + this.objName + '.show(' + previousMonth + ', ' + previousYear + ')"><img src="includes/web-engineer.co.uk/prev.gif" alt="< month" border="0" /></a>';
	nextLinkStr = '<a class="handLink" onClick="' + this.objName + '.show(' + nextMonth + ', ' + nextYear + ')"><img src="includes/web-engineer.co.uk/next.gif" alt="month >" border="0" /></a>';
	prevLinkStr = '<a class="handLink" onClick="' + this.objName + '.show(' + thisMonth.getMonth() + ', ' + (previousYear-1) + ')"><img src="includes/web-engineer.co.uk/prevYear.gif" alt="< year" border="0" /></a>'+prevLinkStr;
	nextLinkStr = nextLinkStr+'<a class="handLink" onClick="' + this.objName + '.show(' + thisMonth.getMonth()+ ', ' + (nextYear+1) + ')"><img src="includes/web-engineer.co.uk/nextYear.gif" alt="year >" border="0" /></a>&nbsp;<a class="handLink" onClick="' + this.objName + '._hideLayer();"><img src="includes/web-engineer.co.uk/close.gif" alt="close window" border="0" hspace="0" vspace="2"/></a>';

	monthText = calendarMonthNames[thisMonth.getMonth()];
	
	yearText = thisMonth.getFullYear();
	var h;
	if(this.title!=''){
		h=((row+2)*calendarCellHeight)+calendarTopBarHeight+((row+3)*calendarCellSpacing);
	}else{
		h=((row+2)*calendarCellHeight)+((row+3)*calendarCellSpacing);
	}
	if(this.title!=''){
		html = calendarTitleTemplate;
		html = html.replace('<title/>',this.title);
	}else{
		html = calendarNoTitleTemplate;
	}
	html = html.replace('<prevLinkStr/>',prevLinkStr);
	html = html.replace('<nextLinkStr/>',nextLinkStr);
	html = html.replace('<monthText/>',monthText);
	html = html.replace('<cellspacing/>',calendarCellSpacing);
	html = html.replace('<yearText/>',yearText);
	html = html.replace(/<width\/>/g,((7*calendarCellWidth)+(8*calendarCellSpacing)+2));
	html = html.replace(/<topBarHeight\/>/g,calendarTopBarHeight);
	
	//alert('rows:'+row+' width:'+(7*calendarCellWidth)+', height:'+h);
	//alert("head: "+html);
	var days = calendarDaysTemplate.replace(/<cellWidth\/>/g,calendarCellWidth);
	days = days.replace(/<cellHeight\/>/g,calendarCellHeight);
	days += '<tr>' + ret.join('</tr><tr>') + '</tr>';
	html = html.replace("<content/>",days);
	this._setHTML(html);
	if (!arguments[0] && !arguments[1] && !arguments[2]){
		this._showLayer();
		this._setLayerPosition();
	}
}
// set the size - args: width,height
function calendarSetCellSize(w,h){
	cellWidth = w;
	cellHeight = h;
}

// Sets the min/max date range - short unix timestamp YYYYMMDD as int/string

function calendarSetMaxDate(max){
	this.maxDate = parseInt(max);
	for(i=0; i<calendarLayers.length; ++i){
		calendarLayers[i].show(null,null,true);
	}
}
function calendarSetMinDate(min){
	this.minDate = parseInt(min);
	for(i=0; i<calendarLayers.length; ++i){
		calendarLayers[i].show(null,null,true);
	}
}

// Sets a date to highlight

function calendarSetDate(date,month,year){
	this.selectedDay = date;
	this.selectedMonth = month;
	this.selectedYear = year;
}

// Sets the current month displayed

function calendarSetCurrentMonth(month){
	this.currentMonth = month;
}

// Sets the currentyear displayed

function calendarSetCurrentYear(year){
	this.currentYear = year;
}

function calendarGetLayer(){
	var layerID = this.layerID;
	if (document.getElementById(layerID)){
		return document.getElementById(layerID);
	} else if (document.all(layerID)){
		return document.all(layerID);
	} else {
		return false;
	}
}

function calendarGetLayerID(){
	return this.layerID;
}

// Hides the calendar layer

function calendarHideLayer(){
	new Effect.Fade(this._getLayerID(), {duration: 0.25});
}

// Shows the calendar layer

function calendarShowLayer(){
	new Effect.Appear(this._getLayerID(), {duration: 0.5});
}
// Sets the layers position

 function calendarSetLayerPosition(){
	this._getLayer().style.top = (calendarMouseY + offsetY+document.body.scrollTop) + 'px';
	this._getLayer().style.left = (calendarMouseX + offsetX+document.body.scrollLeft) + 'px';
	this._getLayer().style.zIndex = (++zVal);
}

// Returns number of days in for given month/year

function calendarGetDaysInMonth(month, year){
	monthDays = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
	if (month != 1){
		return monthDays[month];
	} else {
		return ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0 ? 29 : 28);
	}
}

// Updates the layers innerHTML
	
function calendarSetHTML(html){
	this._getLayer().innerHTML = html;
}
// Draw layer
function calendarWriteHTML(){
	document.write('<div onmousedown="beginDrag(this,event);" style="display:none; zIndex:'+(zVal++)+'" class="calendar" id="' + this.layerID + '"></div>');
}
// --------------------------------------------------------------------

// Handler functions
function stopProp(event){
	if(event.stopPropagation){
		event.stopPropagation();
		event.preventDefault();
	}else{
		event.cancelBubble = true;
		event.returnValue = false;
	}
}
function moveHandler(e){
	if(!e) e = window.event;
	dragElement.style.left = (e.clientX - dx+document.body.scrollLeft) +"px";
	dragElement.style.top = (e.clientY - dy+document.body.scrollTop) +"px";
	stopProp(e);
}
function upHandler(e){
	if(!e) e = window.event;
	if(document.removeEventListener){
		document.removeEventListener("mouseup",upHandler,true);
		document.removeEventListener("mousemove",moveHandler,true);
	}else if(document.detachEvent){
		document.detachEvent("onmouseup",upHandler);
		document.detachEvent("onmousemove",moveHandler);		
	}
	stopProp(e);
	
}

var calendarOldOnMouseMove = document.onmousemove ? document.onmousemove : new Function;

document.onmousemove = function (){
	if(document.body){
		if (arguments[0]){
			calendarMouseX = arguments[0].pageX;
			calendarMouseY = arguments[0].pageY;
		} else {
			if(!event){
				var e = window.event;
			}else{
				var e = event;
			}
			try{
				calendarMouseX = e.clientX + document.body.scrollLeft;
				calendarMouseY = e.clientY + document.body.scrollTop;
			}
			catch(e){
				//console.log(e);
			}
			arguments[0] = null;
		}
	}
}

