// 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.updateCalAsync = updateCalAsync;
		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, targetlang, calendarUrl)
	{
		this.targetlang = targetlang;
		this.calendarUrl = calendarUrl;
		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()
	{
	    AjaxLibrary.GetActivitiesForMonths(this.currentDate.getFullYear(),this.currentDate.getMonth()+1, this.targetlang, this.updateCalAsync.bind(this), function(res) { alert("FAILED"); })
	}
	
    function updateCalAsync(res)
    {
        var selecteddatesinmonth;
        for(var d in res)
            selecteddatesinmonth = res[d];
		
		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 = Months[this.currentDate.getMonth()];
		var tableHTML = '<table class="calendarselectordaytable"><thead>';
		var rowHTML = '<tr>';
		
		var tableCell;

		//All the days are added from the array
		for(i=0;i<Days.length;i++)
		{
			rowHTML += '<th scope="col">'+Days[i]+'</th>';
		}
		rowHTML += '<th scope="col" class="calendarselectorweek">'+weekText + '</th>';
		tableHTML += rowHTML + '</tr></thead>';
				
		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;
		
		tableHTML += '<tbody>';
		
		while(countDays <= noDays && breakCount++ < breaker)
		{
			rowHTML = '<tr>';
			
			for(var i=0;i<Days.length;i++)
			{
			    var dateindex = 1;
				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;
						dateindex = 0;
					}
					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;
							dateindex = 2;
						}
						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;
					}
				}
				var hasac = false;
				if(selecteddatesinmonth[dateindex])
				{
				    //console.log(selecteddatesinmonth[dateindex].length);
				    for(var icount = 0; icount<selecteddatesinmonth[dateindex].length; icount++)
				    {
    //				    console.log(i);
				        hasac = (selecteddatesinmonth[dateindex][icount] == dato.getDate());
				        if(hasac)
				            break;
				    }
				}
				rowHTML += this.Link(dato, tableCell, thismonth, hasac);
			}
			row++;
			
            rowHTML += this.LinkWeek(new Date(this.currentDate.getFullYear(), this.currentDate.getMonth(), countDays), tableCell);
			
			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, hasactivities)
	{
		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 = "calendarselectorday";
        if(hasactivities)
            if(selected)
                classText = "calendarselectortodayactive";
            else
                classText = "calendarselectordayactive";
        else if(selected)
            classText = "calendarselectortoday";
        
//		var classText =  (selected) ? "calendarselectortoday" : oldDate ? "calendarselectorday" : (thismonth) ? "calendarselectorday" : "calendarselectorday";

		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);
		var htmlcell = '<td><div class="calendarselectorday calendarselectorweek">' + GetWeekNumberFromDate(dato) + '</div></td>';
		return htmlcell;
		
		//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=\'calendarselectortoday\';" onclick="document.getElementById(\''+startid+'\').value = \''+startdaten+'\';document.getElementById(\''+endid+'\').value = \''+enddaten+'\';document.forms[0].submit();"';
        var mouseoverClass = 'calendarselectortoday';
        if (classText == 'calendarselectordayactive' || classText == 'calendarselectortodayactive')
            mouseoverClass = 'calendarselectortodayactive';
        var mouseevents = ' onmouseout="this.className=\''+classText+'\';" onmouseover="this.className=\''+mouseoverClass+'\';" onclick="window.location.href = \''+this.calendarUrl+'?date='+startdaten+'\';return false;"';
		var htmlcell = "";
		htmlcell = '<'+tagName+'>';
		htmlcell += '<div class="'+classText+'" '+mouseevents+'>';
		htmlcell += '<a href="'+this.calendarUrl+'?date='+startdaten+'" title="'+value+'">';
		htmlcell += value;
		htmlcell += '</a>',
		htmlcell += '</div></'+tagName+'>';
		return htmlcell;
	}
	
	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;
}

function GetWeekNumberFromDate( date )
{ 
  date = new Date( Date.UTC( date.getFullYear(), date.getMonth(), date.getDate() ) ); 
  var IsoDayOfWeek = date.getDay()==0? 7: date.getDay(); // Søndag = 7 
  date.setDate( date.getDate() + 4 - IsoDayOfWeek ); // Ændre til nærmeste torsdag 
  var DayOfYear = ( date.getTime() - Date.UTC( date.getFullYear(), 0, 1 )) / 864e5; 
  var week = Math.floor( DayOfYear / 7 ) + 1; 
  return week; 
} 
