//
//	Build calendar
//

function Season( startDate, endDate, cost, midweekCost, weekendCost )
{
	this.start = startDate;
	this.end = endDate;
	this.cost = cost;
	this.midweekCost = midweekCost;
	this.weekendCost = weekendCost;
	this.rate = 0;
}

var Seasons = new Array();
function RegisterSeason( season )
{
	Seasons.push( season );
}

function CompareSeasons( first, second )
{
	if( first.cost < second.cost ) return -1;
	if( first.cost == second.cost )	return 0;
	return 1;
}

// Number of different cost degrees
var NumberOfDegrees = 10; 
// Table of different costs
var CostsTable = new Array();
for( i=0; i<NumberOfDegrees; i++ )
	CostsTable.push( NaN );

function RateSeasons()
{
	if( Seasons.length == 0 ) return;
	
	Seasons.sort( CompareSeasons );
	var minCost = Seasons[0].cost;
	var maxCost = Seasons[Seasons.length-1].cost;
	var differentCosts = 0;
	var prevCost = Number.MIN_VALUE;
	for( i=0; i<Seasons.length; i++ )
	{
		if( prevCost != Seasons[i].cost ) 
		{
			prevCost = Seasons[i].cost;
			differentCosts++;
		}
	}
	if( differentCosts == 1 )
	{
		var n = Math.round( NumberOfDegrees/2 )-1;
		CostsTable[n] = 0;
		for( i=0; i<Seasons.length; i++ )
		{
			Seasons[i].rate = n;
		}
	}
	else 
	{
		CostsTable[0] = 0;
		Seasons[0].rate = 0;
		CostsTable[NumberOfDegrees-1] = Seasons.length-1;
		Seasons[Seasons.length-1].rate = NumberOfDegrees-1;
		prevCost = minCost;
		var costNumber = 1;
		var pos = 0;
		for( i=1; i<Seasons.length-1; i++ )
		{
			if( prevCost != Seasons[i].cost )
				if( Seasons[i].cost != maxCost )
				{
					prevCost = Seasons[i].cost;
					pos = Math.round( ((NumberOfDegrees-1)/(differentCosts-1)) * costNumber );
					if( !isNaN( CostsTable[pos] ) && pos<Seasons.length-1 )
						pos++;
					CostsTable[pos] = i;
					costNumber++;
				} else {
					pos = NumberOfDegrees - 1;
				}
			Seasons[i].rate = pos;			
		}
	}
}

function Usage( startDate, endDate, status )
{
	this.start = startDate;
	this.end = endDate;
	/* Possible statuses 
	1 - free
	2 - pre-occupied
	3 - occupied
	4 - unavailable
	*/
	this.status = status;
}

var Usages = new Array();
function RegisterUsage( usage )
{
	Usages.push( usage );
}

// Allows or denies weekend highlighting
var AllowChooseWeekends = false;

// Allows date clicking
var AllowClicks = true;

// Ordering mode. 1 - saturday-saturday, 2 - friday-friday, 3 - flexible.
var OrderMode = 2;
// Period of order. 0 - midweek/weekend. 7, 14, 21, etc. - weeks.
var OrderDays = 0;

function PrintCalendar( startYear, startMonth, endYear, endMonth, startDay ) 
{
	var year = startYear;
	var month = startMonth;
	var curMonth = 1;
	
	while( true )
	{
		
		if( curMonth % 2 == 1 )
			document.write( "<tr>" );
		document.write( "<td class='calendarCell'>" );

		// Find first day in the table
		var monthFirst = new Date( year, month-1, 1 );
		var mondayOffset = (monthFirst.getDay() + 7 - Days.Start ) % 7; 
		// First day now is saturday. To move to monday add 6 instead of 1
		
		var now = new Date( year, month-1, 1-mondayOffset );
		var curWeekNo = Math.ceil( ( now - new Date( year, 0, 1 ))/( 7*86400000 ) ) + 1;
		if ( Days.ISO )
		{
			var firstJan = new Date( year, 0, 1 );
			if ( (firstJan.getDay()+7)%8 > 4 )
				curWeekNo--;
			//alert( firstJan + " " + curWeekNo );
		}
		if( startDay == null )
			startDay = new Date( now );
		
		// Output month table
		// Print month table
		document.write( "<table class='calendar' cellspacing='0' cellpadding='0'><tr class='head'>" );
		// Print month and days names
		document.write( "<td class='month'><div>" );
		document.write( Months[month-1] );
		document.write( ", " + year );
		document.write( "</div></td>" );
		
		var skipDays = 0;
		for( var i=0; i<7; i++ )
		{
			var ii = ( 6 + i + Days.Start ) % 7;
			document.write( "<td class='day" + ((ii==Days.Sat || ii==Days.Sun)?" weekend":"") + "'>" + Days[ii] + "</td>" );
		}
			
		document.write( "</tr>" );
		
		// Print days of month
		var curRow = 1, curColumn = 0;
		var monthStarted = false, monthFinished = false;
		var weekId;
		var clickPeriod = new Date( now );
		var fwd = false;
		var prevCost = null, prevUsage = null;
		do {
			curColumn++;
			if( curColumn > 7 ) {
				curColumn = 1;
				fwd = false;
				curRow++;
				document.write( "</tr>" );
				//clickPeriod = new Date( now );
				curWeekNo++;
			}
			
			var date = now.getDate();
			if( !monthStarted && date == 1 ) 
				monthStarted = true;
			else if( monthStarted && date == 1 )
				monthFinished = true;
				
			if( monthFinished && curColumn == 1 )
				break;
			
			if( curColumn == 1 ) {
				//weekId = "w" + year + "-" + month + "-";
				//if( !monthStarted ) weekId += "p";
				//weekId += date;
				// Find lined week
				var lastWeek = false;
				var linkedWeekId = null;
				if( month != now.getMonth()+1 )
					// Linked week in the previous month
					linkedWeekId = "w" + now.getFullYear() + "-" + (now.getMonth()+1) + "-" + date;
				else
				{
					// Linked week in the next month
					var sunday = new Date( now.getFullYear(), now.getMonth(), now.getDate()+6 );
					if( sunday.getMonth()+1 != month )
						linkedWeekId = "w" + sunday.getFullYear() + "-" + (sunday.getMonth()+1) + "-p" + date;
					if ( monthStarted && !linkedWeekId && date == 1 )
						linkedWeekId = weekId;
					sunday.setDate( sunday.getDate() + 1 );
					lastWeek = sunday.getMonth()+1 != month;
					if ( lastWeek && !linkedWeekId )
						linkedWeekId = "w" + sunday.getFullYear() + "-" + (sunday.getMonth()+1) + "-1";
					
				}
				weekId = "w" + year + "-" + month + "-";
				if( !monthStarted ) weekId += "p";
				weekId += date;
				
				document.write( "<tr id='" + weekId + "'" );
				if( linkedWeekId != null )
					document.write( " linkedWeek='" + linkedWeekId + "'" );
				if (curMonth == 1)
					document.write("firstWeek='true'");
				document.write( ">" );
				document.write( "<td class='weekNo" );
				if( lastWeek )
					document.write( " last" );
				if ( curWeekNo )
					document.write( "'>" + curWeekNo + "</td>" );
				else
					document.write( "'> </td>" );
			}
			
			var cssClass = "d";
			var clickable = true;
			
			// Check if selectable period is started
			if( now < startDay )
				clickable = false;
			
			// Check usage
			var currentUsage = 1; // available
			for( i=0; i<Usages.length; i++ ){
				if( now >= Usages[i].start && now <= Usages[i].end ) {
					currentUsage = Usages[i].status;
					break;
				}
			}
			if( currentUsage > 1 )
				clickable = false;
				
			// Check seasons
			var currentCost = -1;
			for( i=0; i<Seasons.length; i++ )
			{
				if( now >= Seasons[i].start && now <= Seasons[i].end ) 
				{
					currentCost = Seasons[i].rate;
					
					// Select color for the cell
					if( currentUsage == 1 )
						cssClass += " cost" + currentCost;
					else if( currentUsage == 2 || currentUsage == 3 )
						cssClass += " cost" + currentCost + "m usage" + currentUsage;
					else
						cssClass += " usage" + currentUsage;
					break;
				}
			}
			if( currentCost == -1 )
			{
				clickable = false;
				cssClass += " usage4";
			}
						
			// Add tail from previous season if necessary
			var prevColor = null;
			if( prevCost != null && prevUsage != null ) 
			{
				if( prevUsage == 4 )
				{
					if( prevUsage != currentUsage )
						prevColor = -1;
				}
				else
				{
					if( prevCost != currentCost || currentUsage == 4 )
					{
						if( prevCost == -1 )
							prevColor = -1;
						else
							prevColor = prevCost
					}
				}
				if( prevColor != null )
					cssClass += " tail" + prevColor;
			}
			prevUsage = currentUsage;
			prevCost = currentCost;
			
			// Check frame of the month				
			if( !monthStarted || monthFinished ) 
			{
				cssClass += " notThisMonth";
				clickable = false;
				skipDays++;
			}
			//if( monthStarted || !monthFinished ) 
			// Check for weekend
			// NOTE: week starts with saturday. It starts with weekend.
			//if( curColumn < 2 )
			//	cssClass += " weekend";
			var ccc = (curColumn - 2 + Days.Start ) % 7;
			if( ccc == Days.Sat ) 
				clickPeriod = new Date( now );				
				
			var bWeekEnd = ( ccc == Days.Sat || ccc == Days.Sun );
			if ( bWeekEnd  )
				fwd = true;
			if (ccc ==Days.Sun && curColumn == 1)
				fwd = false;
			if (bWeekEnd)
				cssClass += " weekend";

			var isToday = false;
			if( AllowClicks && now.valueOf() == startDay.valueOf() ) 
			{
				cssClass += " today";
				isToday = true;
			}
				
			document.write( "<td day='true' " );
			if( cssClass != "" )
			{
				document.write( " class='" + cssClass + "'" );
			}
			
			if ( monthStarted && curColumn == 7 )
			{
				//alert(" validDays=\""+(7-skipDays%7)+"\"" );
				document.write( " validDays=\"" + ( 7 - skipDays % 7 ) + "\"" );
				skipDays = 0;
			}
			
			if( monthStarted && !monthFinished ) 
			{
				var dayId = "d" + year + "-" + month + "-" + date;
				document.write( " id='" + dayId + "'" );
				
				/*
				// Declare event handler
				var eventHandlers = " onmouseover=\"Highlight(true,'" +  + "'";
				eventHandlers += "," + clickable.toString()+","+fwd.toString();
				eventHandlers +=  ")\" onmouseout=\"Highlight(false,'" + dayId + "'";
				eventHandlers += "," + clickable.toString()+","+fwd.toString() + ")\"";
				document.write( eventHandlers );
				*/
			}

			document.write( " date='" + now.valueOf() + "'" );
			document.write( " currentCost='" + currentCost + "'" );
			document.write( " currentUsage='" + currentUsage + "'" );
			document.write( " clickable='" + clickable.toString() + "'" );
			document.write( " isToday='" + isToday + "'" );
			document.write( ">" );
			if( AllowClicks && clickable ) 
			{
				document.write( "<a href='javascript:DoSubmit(\"" 
					+ now.getFullYear() + "-"
					+ ( now.getMonth() + 1 ) + "-"
					+ now.getDate()
					+ "\")'>" );
			}
			if( monthStarted && !monthFinished )
				document.write( date );
			if( AllowClicks && clickable )
				document.write( "</a>" );
			document.write( "</td>" );
			now.setDate( date+1 );
		} 
		while( true );
		
		skipDays = 0;
		document.write( "</table>" );

		document.write( "</td>" );
		if( curMonth % 2 == 0 )
			document.write( "</tr>" );
		
		// Next month
		month++;
		curMonth++;
		if( year == endYear ) 
		{
			if( month > endMonth ) break;
		} 
		else 
		{
			if( month > 12 ) 
			{
				year++;
				month = 1;
				if ( Days.ISO )
				{
					var firstJan = new Date( year, 0, 1 );
					if ( (firstJan.getDay()+7)%8 < 5 )
						curWeekNo=1;
				}
				else
					curWeekNo = 1;
			}
		}
	}
	//document.write( "</table>" );
}

var oHighlighted = null;
var sHighlightedSeason = null;

function CalendarMouseOver( oEvent )
{
	oEvent = window.event ? window.event : oEvent;
	var td = oEvent.target ? oEvent.target : oEvent.srcElement;

	// Get a TD related to a day.	
	while( td.tagName != "TD" )
	{
		td = td.parentNode;
		if( td == null || td.tagName == "TABLE" )
			return;
	}
	if( td.getAttribute( "day" ) != "true" )
		return;
	
	var bOver = oEvent.type == "mouseover";
	if( bOver ) 
	{
		if( IsClickable(td) && AllowClicks )
		{
			Highlight( true, td );
			oHighlighted = td;
		}
		
		sHighlightedSeason = td.getAttribute( "currentCost" );
		HighlightLegend( sHighlightedSeason, true );
	}
	else
	{
		// Remove highlighting
		
		if( oHighlighted != null ) 
		{
			Highlight( false, oHighlighted );
			oHighlighted = null;
		}
		if( sHighlightedSeason != null )
		{
			HighlightLegend( sHighlightedSeason, false );
			sHighlightedSeason = null;
		}
	}
}

function IsClickable( td ) 
{
	var date = new Date(parseInt(td.getAttribute("date")));
	var start = PeriodStart(date);
	if ( start > JStoDays(date.getDay()))
		date = AddDays(date, -7);
	date = AddDays(date, start - JStoDays(date.getDay()));
	var len = PeriodLength(date);

	// check if period can be selected (ie after bold underlined date)
	var td1 = document.getElementById( "d" + date.getFullYear() + "-" + (date.getMonth()+1) + "-" + date.getDate() );
	if (td1 == null || td1.getAttribute("clickable") != "true")
		return false;	

	// look in seasons
	var searchStart = date;
	while (searchStart < AddDays(date, len)) {
		var i = Seasons.length-1;
		while( i >= 0 
			&& ( Seasons[i].start > searchStart || Seasons[i].end < searchStart ) )
			i--;
		if (i < 0)
			return false;
		else
			searchStart = AddDays(Seasons[i].end, 1);
	}



	// look in usages
	for( i=0; i<Usages.length; i++ ){
		if ( !(
		(Usages[i].start < date && Usages[i].end < date) 
		|| (Usages[i].start >= AddDays(date, len) && Usages[i].end >= AddDays(date, len))
		) && Usages[i].status > 1) {
			return false;
		}
	}
	return true;
}

function AddDays( date, days ) {
	var result = new Date(parseInt(date.valueOf()) + days * 1000 * 60 * 60 * 24);
	// Avoid problecs with winter/summer time
	return new Date(parseInt(result.valueOf()) + (result.getTimezoneOffset() - date.getTimezoneOffset()) * 1000 * 60);
}

// Hightlight legend
function HighlightLegend( currentCost, flag )
{
	var legendCost = null;
	if( currentCost != null )
		legendCost = document.getElementById( "legend" + currentCost );
	if( flag && legendCost != null ) 
	{
		legendCost.className = "highlight";
	} 
	else 
	{
		if( legendCost != null ) legendCost.className = "";
	}
}	

// Highlights week and week cost
function Highlight( flag, td )
{
	// Find week
	var tr = td.parentNode;

	var date = new Date(parseInt(td.getAttribute("date")));
	
	// Find linked week
	var weekId = tr.id;
	var linkedWeekId = tr.getAttribute( "linkedWeek" );
	//window.status = weekId+" "+linkedWeekId;
	var linkedTr = document.getElementById( linkedWeekId );
	
	//SetWeekClass( tr, "highlight", flag );
	//SetWeekClass( linkedTr, "highlight", flag );

	var start = PeriodStart(date);
	if ( start <= JStoDays(date.getDay()))
		LitePeriod( tr, "highlight", flag, true, start, PeriodLength(date) );
	else
		LitePeriod( GetPrevRow( tr ), "highlight", flag, true, start, PeriodLength(date) );
}

function PeriodStart(date) {
	if (OrderMode == 1) 
		return Days.Sat;
	else if (OrderMode == 2) {
		if (OrderDays == 0 && date.getDay() >= 1 && date.getDay() <= 4)
			return Days.Mon;
		else
			return Days.Fri;
	}
	else
		return JStoDays(date.getDay());
}

function PeriodLength(date) {
	if (OrderDays > 0)
		return OrderDays;
	else {
		if (date.getDay() >= 1 && date.getDay() <= 4)
			return 4;
		else 
			return 3;
	}
}

function LitePeriod( oTr, sClass, bSet, bForward, iStartIndex, iCount )
{
	if ( !oTr )
		return;

	iCount++;
	var first = true;
	if ( bForward )
	{
		while( iCount > 0 && oTr != null )
		{
			var linkedWeekId = oTr.getAttribute( "linkedWeek" );
			var firstWeek = (oTr.getAttribute("firstWeek") == "true");
			var vd = 0;
			if ( oTr.lastChild.getAttribute( "validDays" ) )
				vd = parseInt( oTr.lastChild.getAttribute( "validDays" ) );
			var realVd = vd;
			var linkedTr = document.getElementById( linkedWeekId );
			var downLinked = ( oTr.nextSibling == null )
			var isTopRow = !downLinked && (linkedTr != null || firstWeek);

			var iEndIndex = iStartIndex + iCount;
			var rowFill = 0;
			if( iEndIndex > 6 )
			{
				rowFill = 7 - iStartIndex; // more than one week
				iCount -= rowFill;
			}
			else
			{
				rowFill = iCount;
				iCount = 0; // within one week
			}
			var fits = true;
			var rowFill2 = rowFill;
			if( first )
				if( !isTopRow )
					vd = vd - iStartIndex;
			if( rowFill > vd )
			{
				iCount += ( rowFill - vd );
				rowFill = vd;
				fits = false;
			}
			
			if ( fits )
			{
				LiteSubRow( oTr, sClass, bSet, iStartIndex, rowFill, first, ( iCount == 0 ) );	
			}
			else
			{
			// won't fit
				if ( downLinked )
				{		
					LiteSubRow( oTr, sClass, bSet, iStartIndex, 7, first, false );	
					iCount -= (rowFill2-vd);
					LiteSubRow( linkedTr, sClass, bSet, 0, rowFill2+iStartIndex, false, ( iCount == 0 ) );	
				}
				else
				{
					iCount -= (rowFill2-vd);
					LiteSubRow( oTr, sClass, bSet, 0, rowFill2+iStartIndex, false, ( iCount == 0 ) );	
					LiteSubRow( linkedTr, sClass, bSet, iStartIndex, 7, first, false );	
				}

			}
			first = false;

			iStartIndex = 0;
			if 	( !oTr.nextSibling )
				if ( linkedTr )
				{
					if ( realVd == 7 && fits )
						oTr = linkedTr;
					else
						oTr = linkedTr.nextSibling;
				}
				else
					oTr = null;
			else
				oTr = oTr.nextSibling;
		}
	}
}

function GetPrevRow( oTr )
{
	var vd = 0;
	if ( oTr.lastChild.getAttribute( "validDays" ) )
		vd = parseInt( oTr.lastChild.getAttribute( "validDays" ) );

	var linkedWeekId = oTr.getAttribute( "linkedWeek" );
	var linkedTr = document.getElementById( linkedWeekId );
	if 	( !oTr.nextSibling && linkedTr )
		oTr = oTr.previousSibling;
	else
		if ( linkedTr )
		{
			if ( vd == 7 )
				oTr = linkedTr;
			else
				oTr = linkedTr.previousSibling;
			
		}
		else
			oTr = oTr.previousSibling;
			
	return oTr;
}

function LiteSubRow( oTr, sClass, bSet, iFirst, nCount, bMarkFirst, bMarkLast )
{
	if ( !oTr )
		return;
		
	var col = oTr.childNodes;
	var cll = col.length;
	iFirst = cll - 7 + iFirst;
	var td = oTr.childNodes[iFirst];
	for( var i=0; i<nCount; i++ )
	{
		var newClass = td.className;
		 
		if( bMarkFirst && i == 0 )
		{
			// Find color of a previous cell, to correctly colorize tail in the first cell.
			var prevTd = td.previousSibling;
			if( prevTd == null || prevTd.className.indexOf("weekNo") >= 0 ) 
			{
				var prevTr = GetPrevRow( oTr );
				if( prevTr != null )
					prevTd = prevTr.lastChild;
			}
			if( prevTd != null )
			{
				var prevCost = prevTd.getAttribute( "currentCost" );
				var prevUsage = prevTd.getAttribute( "currentUsage" );
				if( prevCost == "-1" || prevUsage == "4" )
					newClass = "d cost-1 ";
				else
					newClass = "d cost" + prevCost + " ";
			}
			if( td.getAttribute( "isToday" ) == "true" )
				newClass += " today";
			newClass += " " + sClass + "-start";
		}
		else if( bMarkLast && i == nCount - 1 )
		{
			newClass += " " + sClass + "-end";
		}
		else
		{
			newClass += " " + sClass;
		}

		if( bSet )
		{
			td.setAttribute( "origClass", td.className );
			td.className = newClass;
		}
		else
		{
			td.className = td.getAttribute( "origClass" );
		}
			
		td = td.nextSibling;
		if( td == null )
			break;
	}
}

function PrintLegend( leftAlign )
{
	for( i=0; i<CostsTable.length; i++ )
	{
		if( !isNaN( CostsTable[i] )){
			document.write( "<tr id='legend" + i + "'>" )
			if( !leftAlign ) {
				document.write( "<td class='cost'>&euro;" + Seasons[CostsTable[i]].cost + "</td>" );
				document.write( "<td class='color cost" + i + "'>&nbsp;</td>" );
			} else {
				document.write( "<td class='color cost" + i + "'>&nbsp;</td>" );
				document.write( "<td class='cost'>&euro;" + Seasons[CostsTable[i]].cost + "</td>" );
			}
			document.write( "</tr>" );
			
			document.write("<tr>");
			document.write("<td/><td class='midweek_weekend'>");
			if (Seasons[CostsTable[i]].midweekCost) 
				document.write("midweek: " + Seasons[CostsTable[i]].midweekCost +	"&euro; "); 
			if (Seasons[CostsTable[i]].weekendCost) 
				document.write("weekend: " + Seasons[CostsTable[i]].weekendCost +	"&euro;");
			document.write("</td></tr>");
		}
	}
}

function ChangeDays() {
	var form = document.forms.days_select;
	OrderDays = form.length.options[form.length.selectedIndex].value;
}

function DoSubmit(date) {
	document.forms["days_select"].elements["startdate"].value = date;
	document.forms["days_select"].submit();
}

// Common
if( !String.prototype.trim )
	String.prototype.trim = 
	function() {
		return this.replace(/^\s+|\s+$/g, "");
	};


