// define a Calendar class
function Calendar () 
{
    // add some properties to our Calendar
	this.monthDisp			= null;
	this.yearDisp			= null;
	this.dayDisp			= null;
	this.entireCal			= null;
	this.saveTo				= null;
    this.currentDate		= new Date();
    this.originalDateStart	= new Date();
    this.originalDateEnd	= new Date();
    this.saveStartValue		= null;
    this.saveEndValue		= null;

    // initialize the member function references
    // for the class prototype
    if (typeof(_calendar_prototype_called) == 'undefined')
    {
		_calendar_prototype_called = true;
		Calendar.prototype.updateCal = updateCal ;
		Calendar.prototype.init = init;
		Calendar.prototype.Print = Print;
		Calendar.prototype.Change = Change;
		Calendar.prototype.Link = Link;
		Calendar.prototype.LinkWeek = LinkWeek;
		Calendar.prototype.AddLinkCell = AddLinkCell;
		Calendar.prototype.ShowCalendar = ShowCalendar;
		Calendar.prototype.SaveValue = SaveValue;
		Calendar.prototype.Show = Show;
		Calendar.prototype.Hide = Hide;
		Calendar.prototype.dateToString = dateToString;
		Calendar.prototype.stringToDate = stringToDate;
		Calendar.prototype.Clear = Clear;
	}
    
    function Clear()
    {
		this.monthDisp			= null;
		this.yearDisp			= null;
		this.dayDisp			= null;
		this.entireCal			= null;
		this.saveTo				= null;
		this.currentDate		= null;
		this.originalDateStart	= null;
		this.originalDateEnd	= null;
		this.saveStartValue		= null;
		this.saveEndValue		= null;
    }

    // define the clock's methods
	function init(monthSpan, yearSpan, table, allCalendar, selectedDateStart, selectedDateEnd, calStartSaveId, calEndSaveId)
	{
		
		this.monthDisp = document.getElementById(monthSpan);
		this.yearDisp = document.getElementById(yearSpan);
		this.dayDisp = document.getElementById(table);
		this.entireCal = document.getElementById(allCalendar);
		
		//This is for creating two hidden input fields used to submit the start date and enddate
		if(typeof(calStartSaveId) == 'undefined')
		{
			this.saveStartValue = document.createElement("INPUT");
			this.entireCal.appendChild(this.saveStartValue);
			this.saveStartValue.type = "hidden";
			this.saveStartValue.name = "calendarStart";
			this.saveStartValue.id = "calendarStart";
			
		}
		else
		{
			this.saveStartValue = document.getElementById(calStartSaveId);
		}
		this.saveStartValue.value = selectedDateStart;
		
		if(typeof(calEndSaveId) == 'undefined')
		{
			this.saveEndValue = document.createElement("INPUT");
			this.entireCal.appendChild(this.saveEndValue);
			this.saveEndValue.type = "hidden";
			this.saveEndValue.name = "calendarEnd";
			this.saveEndValue.id = "calendarEnd";
		}
		else
			this.saveEndValue = document.getElementById(calEndSaveId);
		this.saveEndValue.value = selectedDateEnd;
		
		
		var selectedD = selectedDateStart+"";
		if(selectedD.length == 8)
		{
			var year = selectedD.substring(0,4);
			var month = selectedD.substring(4,6)-1;
			var day = selectedD.substring(6,8);
			this.originalDateStart = new Date(year, month, day);
		}
		else
			//This is needed otherwise time is added and late we cannot use it correctly
			this.originalDateStart = new Date(new Date().getFullYear(), new Date().getMonth(), new Date().getDate()); 
		
		var selectedDEnd = selectedDateEnd+"";
		if(selectedD.length == 8)
		{
			var year = selectedDEnd.substring(0,4);
			var month = selectedDEnd.substring(4,6)-1;
			var day = selectedDEnd.substring(6,8);
			this.originalDateEnd = new Date(year, month, day);
		}
		else
			this.originalDateEnd = new Date(this.originalDateStart);

			
		this.currentDate = new Date(this.originalDateStart);
	
		var ca = this;
		var nestedUnload = function() { ca.Clear(); };
		//addEventListener(window, "unload", nestedUnload);
		$addHandler(window, "unload", nestedUnload);
		this.updateCal();
	}
	
	function ShowCalendar(currentDate, ypos, xpos, savetofield)
	{
		this.saveTo = document.getElementById(savetofield);
		this.originalDateStart = new Date(this.stringToDate(this.saveTo.value));
		this.currentDate = new Date(this.originalDateStart);
		this.Show();
		this.updateCal();
	}
	
    function updateCal()
    {
		deleteChildren(this.dayDisp);
		deleteChildren(this.yearDisp);
		deleteChildren(this.monthDisp);
		
		//Then all the days must be written
		//Find first day of the month it will be set on the scale 0 - 6 is configured because Date has sunday as 0
		//and in our case it should be 6
		var firstDay = new Date(this.currentDate.getFullYear(), this.currentDate.getMonth(), 1);
		firstDay = (firstDay.getDay()+Days.length-1)%Days.length;
		
		//dP contains the amount of days in the previous month
		var dP = new Date(this.currentDate.getFullYear(), this.currentDate.getMonth()-1, 1);
		var dPdays = isLeapYear(dP.getFullYear()) ? daysMonthLeap[dP.getMonth()] : daysMonth[dP.getMonth()];
		
		//Countdays counts the days written
		var countDays = 1;
		var DaysFromPrevious = firstDay;
		//We find the number of days in the current month
		var noDays = isLeapYear(this.currentDate.getFullYear()) ? daysMonthLeap[this.currentDate.getMonth()] : daysMonth[this.currentDate.getMonth()];
		//We create an integer to count the days from the next month
		var extras = 1;
		
		this.yearDisp.appendChild(document.createTextNode( this.currentDate.getFullYear()));
		
		
		this.monthDisp.innerHTML = this.AddLinkCell("", Months[this.currentDate.getMonth()], this.monthDisp, 
						new Date(this.currentDate.getFullYear(), this.currentDate.getMonth(), 1),
						new Date(this.currentDate.getFullYear(), this.currentDate.getMonth(), noDays),
						"span"
					);
	//	var tableBody = document.createElement("TBODY");
	//	this.dayDisp.appendChild(tableBody);
		var tableHTML = '<table class="calendartable"><tbody>';
		var rowHTML = '<tr><th>'+weekText + '</th><th class="seperatorcell"></th>';
		
		var tableCell;
//		var tableRow = document.createElement("TR");
//		tableBody.appendChild(tableRow);
//		var tableCell = document.createElement("TH");
//		tableRow.appendChild(tableCell);
//		tableCell.appendChild(document.createTextNode(weekText));
//		tableCell = document.createElement("TH");
//		tableCell.className = 'seperatorcell';
//		tableRow.appendChild(tableCell);

		//All the days are added from the array
		for(i=0;i<Days.length;i++)
		{
		//	tableCell = document.createElement("TH");
		//	tableRow.appendChild(tableCell);
		//	tableCell.appendChild(document.createTextNode(Days[i]));
			rowHTML += '<th>'+Days[i]+'</th>';
		}
		tableHTML += rowHTML + '</tr>';
				
		var row = 0;
		var thismonth = true;
		//We then make a row as long as we have not yet written all the days of the month
		var breaker = 10; //we create a breaker to avoid an infinite loop
		var breakCount = 0;
		
		while(countDays <= noDays && breakCount++ < breaker)
		{
		//	tableRow = document.createElement("TR");
		//	tableBody.appendChild(tableRow);
		
			rowHTML = '<tr>';
			//First we add the week number
		//	tableCell = document.createElement("TD");
		//	tableRow.appendChild(tableCell);
			rowHTML += this.LinkWeek(new Date(this.currentDate.getFullYear(), this.currentDate.getMonth(), countDays), tableCell);
		//	tableCell = document.createElement("TD");
		//	tableCell.className = 'seperatorcell';
		//	tableRow.appendChild(tableCell);
		
			rowHTML += '<td class="seperatorcell"></td>';
			
			//The we add a cell for each day available in the week
			for(var i=0;i<Days.length;i++)
			{
		//		tableCell = document.createElement("TD");
		//		tableRow.appendChild(tableCell);
				
				if(row == 0)	//First Row
				{
					if(DaysFromPrevious > 0) //If this should be a date from the previous month
					{ 
						nextDate = dPdays-DaysFromPrevious+1;
						dato = new Date(dP.getFullYear(),dP.getMonth(),(nextDate));
						DaysFromPrevious--;
						thismonth = false;
					}
					else
					{ 
						//Creates new Date with (year, month, date)
						//This is a normal day in this month
						dato = new Date(this.currentDate.getFullYear(), this.currentDate.getMonth(), countDays++); 
						thismonth = true;
					}
				}
				else
				{
					if((countDays+Days.length-1) > noDays) //Last row
					{
						if(countDays > noDays) 
						{ 
							dato = new Date(this.currentDate.getFullYear(), this.currentDate.getMonth()+1,extras++);
							thismonth = false;
						}
						else
						{
							//This is a normal day in this month
							dato = new Date(this.currentDate.getFullYear(), this.currentDate.getMonth(), countDays++); 
							thismonth = true;
						}
					}
					else
					{
						//This is a normal day in this month
						dato = new Date(this.currentDate.getFullYear(), this.currentDate.getMonth(), countDays++); 
						thismonth = true;
					}
				}
				
				rowHTML += this.Link(dato, tableCell, thismonth);
			}
			row++;
			tableHTML += rowHTML +'</tr>';
		}
		tableHTML += '</tbody></table>';
		this.dayDisp.innerHTML = tableHTML;
		tableBody = null;
		tableRow = null;
		tableCell = null;
    }
    
    function Change(change)
	{
		this.currentDate.setMonth(this.currentDate.getMonth() + change);
		this.updateCal();
	}
	
	//Function to ensure that a number is printed with a specific number of digits
	function Print(number, digits)
	{
		number = number + "";											//Conversion to force the number to be recognized as a string
		for(var vc=0;vc < (digits-number.length) && vc < 3; vc++) { number = "0"+number; }	//Adds leading zeros to fulfill the required number of digits
		return number;
	}
	
	//Function which sets a link given by a specific date. This is done to ensure that the formatting is the same
	function Link(dato, cell, thismonth)
	{
		thismonth = typeof(thismonth)=='undefined' ? true : thismonth;
		if(typeof(dato) != 'object' || dato == null) // || typeof(cell) == 'undefined' )
			return "";
	
		var a = this.originalDateStart; 
		var b = this.originalDateEnd;
		var c = dato;
		var selected =  (c-a)>=0 && (b-c)>=0 ;
		var compareDate = new Date( (new Date()-c) );
		var oldDate = (compareDate.getTime()) > 0 && (compareDate.getDate() != 1 || compareDate.getFullYear()!=new Date(0).getFullYear() || compareDate.getMonth() != new Date(0).getMonth() );

		var classText =  (selected) ? "calendaractivecell" : oldDate ? "calenderolddate" : (thismonth) ? "" : "calenderolddate";

		return this.AddLinkCell(classText, c.getDate(), cell, c, c, "td");
		//Clear objects
		cell = null; 
		thismonth = null;
		selected = null;
//		compareDate = null;
//		oldDate = null;
	}
	
	function LinkWeek(dato, cell)
	{
		var day = (dato.getDay()+Days.length-1)%Days.length; // now day has a value from 0-6 ill. monday-sunday
		var fromdate = new Date(dato.getTime() + (-day)*24*60*60*1000);
		var todate = new Date(dato.getTime() + (6-day)*24*60*60*1000);
		return this.AddLinkCell("weekselect",GetWeekNumberFromDate(dato),cell, fromdate, todate, "td");
		
		//free resources
	//	day = null;
		cell = null;
	//	fromdate = null;
	//	todate = null;
	}
	
	function AddLinkCell(classText, value, cell, startdate, enddate, tagName)
	{
		var startid = this.saveStartValue.id;
		var endid = this.saveEndValue.id;
		var startdaten = dateToString(startdate);
		var enddaten = dateToString(enddate);
		//instead of using DOM which ruins IE, we simply generate the html for a cell
		var mouseevents = ' onmouseout="this.className=\''+classText+'\';" onmouseover="this.className=\'calendaractivecell\';" onclick="document.getElementById(\''+startid+'\').value = \''+startdaten+'\';document.getElementById(\''+endid+'\').value = \''+enddaten+'\';document.forms[0].submit();"';
		var htmlcell = "";
		htmlcell = '<'+tagName+' class="'+classText+'" '+mouseevents+'>';
		htmlcell += '<a class="'+classText+'" '+mouseevents+'>';
		htmlcell += value;
		htmlcell += '</a></'+tagName+'>';
		return htmlcell;
/*
		var link = document.createElement("a");
		
		link.appendChild(document.createTextNode(value))
		cell.appendChild(link);
		
		cell.className = classText;
		link.className = classText;

		//To avoid memory leaks in IE		
		var nested_myOnMouseOut = function() { this.className=classText; };
		(function(){
			link.onmouseout = nested_myOnMouseOut;
			cell.onmouseout = nested_myOnMouseOut;
		})();
		
		addEventListener(link, "mouseout", nested_myOnMouseOut);
		addEventListener(cell, "mouseout", nested_myOnMouseOut);

		var nested_myOnMouseOver = function() { this.className='calendaractivecell'; };
		(function() {
			link.onmouseover = nested_myOnMouseOver;
			cell.onmouseover = nested_myOnMouseOver;
			})();
			
		
		var startid = this.saveStartValue.id;
		var endid = this.saveEndValue.id;
		var startdaten = dateToString(startdate);
		var enddaten = dateToString(enddate);
		var nested_myOnClick = function()	{ document.getElementById(startid).value = startdaten;document.getElementById(endid).value = enddaten;document.forms[0].submit(); };
		addEventListener(link, "click", nested_myOnClick);
		addEventListener(cell, "click", nested_myOnClick);
		//Free resources
		link = null;
		cell = null;
		nested_myOnClick = null;
		nested_myOnMouseOut = null;
*/
	}
	
	function SaveValue(result)
	{
		this.saveTo.value = result;
		this.Hide();
	}
	
	function Show()
	{
		this.entireCal.style.display = 'block';
		this.entireCal.style.visibility = 'visible';
	}
	function Hide()
	{
		this.entireCal.style.display = 'none';
		this.entireCal.style.visibility = 'hidden';
	}
	
	function stringToDate(datestring)
	{
		var year, month, date = "";
		if(datestring.indexOf("-") > 0)
		{
			date = datestring.substring(0, datestring.indexOf("-"));
			if(datestring.lastIndexOf("-") > datestring.indexOf("-") )
			{
				month = datestring.substring(datestring.indexOf("-")+1, datestring.lastIndexOf("-"));
				if(datestring.indexOf("-") > 0)
				{
					year = datestring.substring(datestring.lastIndexOf("-")+1, datestring.length );
				}
			}
		}
		if(year!="" && month!="" && date != "")
		return new Date(year, month-1, date);
		return new Date();
	}
	
	function dateToString(dato)
	{
		return dato.getFullYear()+Print(dato.getMonth()+1,2)+Print(dato.getDate(),2);
	}
}

function deleteChildren(node)
{
		for(var i=0;i<node.childNodes.length;i++)//First we delete existing calendar
		{ node.removeChild(node.childNodes[i]); }
}
//Function to test whether a year is leap year or not
function isLeapYear(year) 
{
	if ((year/4)   != Math.floor(year/4))   return false;
	if ((year/100) != Math.floor(year/100)) return true;
	if ((year/400) != Math.floor(year/400)) return false;
	return true;
}

