
/*Date format matching pattern add on.*/
Date.prototype.strftime.formatCodes.W = 'Week';
		

/**
* Returns the week number for this date. dowOffset is the day of week the week
* "starts" on for your locale - it can be from 0 to 6. If dowOffset is 1 (Monday),
* the week returned is the ISO 8601 week number.
* @param int dowOffset
* @return int
*/
Date.prototype.getWeek = function (dowOffset) {
	/*getWeek() was developed by Nick Baicoianu at MeanFreePath: http://www.meanfreepath.com */

	dowOffset = typeof(dowOffset) == 'int' ? dowOffset : 1; //default dowOffset to zero
	var newYear = new Date(this.getFullYear(),0,1);
	var day = newYear.getDay() - dowOffset; //the day of week the year begins on
	day = (day >= 0 ? day : day + 7);
	/*var daynum = Math.floor((this.getTime() - newYear.getTime())/86400000);*/
	var daynum = Math.floor((this.getTime() - newYear.getTime() -
			(this.getTimezoneOffset()-newYear.getTimezoneOffset())*60000)/86400000) + 1;
	var weeknum;
	//if the year starts before the middle of a week
	if(day < 4) {
		weeknum = Math.floor((daynum+day-1)/7) + 1;
		if(weeknum > 52) {
			nYear = new Date(this.getFullYear() + 1,0,1);
			nday = nYear.getDay() - dowOffset;
			nday = nday >= 0 ? nday : nday + 7;
			/*if the next year starts before the middle of
			the week, it is week #1 of that year*/
			weeknum = nday < 4 ? 1 : 53;
		}
	}
	else {
		weeknum = Math.floor((daynum+day-1)/7);
	}
return weeknum;
};

Date.prototype.getLastDayOfMonth=function() {

  	var D=new Date(this.getTime());

  	var D2=new Date();
  	D2.setTime(D.getTime());

  	var tmpMonth=D.getMonth();

  	while(D2.getMonth()==tmpMonth)
  	{
  		D2.setDate(D2.getDate()+1);

  		if(D2.getMonth()==tmpMonth)
  		{
  			D.setTime(D2.getTime());
  		}
  	}
  	
  	D.setHours(0);

	return D;
}

Date.prototype.getFirstDayOfMonth = function() {

	var D=new Date(this.getTime());

	D.setDate(1);
	D.setHours(0,0,0,0);

	return D;
}
/*
Date.prototype.setFromDBFormat = function(dateStr) {

	this.setTime(0);
	
	var parts=new Array();
	var dateParts=new Array();
	var timeParts=new Array();
	
	parts=dateStr.split(" ");
	
	dateParts=parts[0].split("-");

	this.setFullYear(dateParts[0],dateParts[1]-1,dateParts[2]);
	
	this.setHours(0,0,0,0);
	
	if(parts.length>1)
	{
		timeParts=parts[1].split(":");
		
		switch(timeParts.length)
		{
			case 2:
				this.setHours(timeParts[0],timeParts[1]);
				break;
			case 3:
				this.setHours(timeParts[0],timeParts[1],timeParts[2]);
				break;
			case 4:
				this.setHours(timeParts[0],timeParts[1],timeParts[2],timeParts[3]);
				break;
		}
	}
	
}*/

Date.prototype.getDBFormatString = function(withTime) {
	
	var returnString='';
	
	returnString+=this.getFullYear();
	returnString+='-'+(this.getMonth()+1).toPaddedString(2);
	returnString+='-'+this.getDate().toPaddedString(2);

	
	if(withTime == undefined)
	{
		;
	}else
	{
		returnString += ' '+this.getHours().toPaddedString(2);
		returnString += ':'+this.getMinutes().toPaddedString(2);
		returnString += ':'+this.getSeconds().toPaddedString(2);
	}
	
	return returnString;
}


var NFX_RandomUtils = {
	getRandomNumber: function(rng) {
		return Math.floor(Math.random()*rng);
	},
	
	getRandomChar: function() {
		var chars = "0123456789abcdefghijklmnopqrstuvxyzABCDEFGHIJKLMNOPQRSTUVXYZ";
		
		return chars.substr(NFX_RandomUtils.getRandomNumber(62),1);
	}
};

var NFX_UID_Store=new Array();

var NFX_UID = Class.create({
	
	initialize: function(options)
	{
		this.options = {
			prefix: 'NFX_',
			length: 10
			};
		
		Object.extend( this.options, options || {} );
		
		this.prefix = this.options.prefix;
		this.length = this.options.length;
		
	},
	
	uid: function()
	{
		var tmp=this.prefix;
		
		for(var i=0;i<this.length;i++)
		{
			tmp+=NFX_RandomUtils.getRandomChar();
		}
		
		if(NFX_UID_Store.indexOf(tmp)==-1)
		{
			NFX_UID_Store[NFX_UID_Store.length]=tmp;
			
			return tmp;
		}else
		{
			// rerandom
			
			return this.uid();
		}
	}
}); 		 

/**
 * Calendar with possibility of changing month. Uses ajax.
 *
 * Dependencies: Prototype.js Script.aculo.us
 * 
 * Available options:
 * 
 * Ajax returned required JSON items:
 * 	json.results		Contains result rows. Table body is filled based on this array.
 * 	json.currentCount	Number of rows in returned results.
 * 	json.totalCount		Total number of rows (without paging).
 * 	json.errors			Optional. Contains error information.
 * 
 * @since 2008/07/16
 * @author Matti Järvinen <matti.jarvinen@nitro.fi>
 */
var NFX_Calendar = Class.create({

	/**
	 * Constructor.
	 * 
	 * @param {String} url		Url to the ajax request.
	 * @param {String} target	Id of the container where to add calendar
	 * @param {Object} options	Options to configure the Calendar. See comments of the class for more details.
	 */
	initialize: function(url, target, options)
	{
		var IDGen= new NFX_UID();
	
		this.id = IDGen.uid(); 
		
		this.url = url;
		this.target = $(target);
		this.events = new Array();
		this.eventDates = new Array();
		
		this.options = {
			haltOnAjaxResultError: true,
			displayAjaxResultErrors: false,
			showDays: new Array('M','T','K','T','P','L','S'),
			monthNames: new Array('Tammikuu','Helmikuu','Maaliskuu','Huhtikuu','Toukokuu','Kesäkuu','Heinäkuu','Elokuu','Syyskuu','Lokakuu','Marraskuu','Joulukuu'),
			currentDate: new Date(),
			calendarDate: new Date(),
			EventTemplate: new Template('<p><b>#{name}</b><br /> #{startDate}&nbsp;&mdash;&nbsp;#{endDate} <br /><i>#{ingress}</i></p>'),
			/*dateDisplayFormat: '%#d.%#m.%Y&nbsp;%#H:%M'*/
			dateDisplayFormat: '%#d.%#m.%Y' 	
				
		};
		
		
		
		Object.extend( this.options, options || {} );

		this.options.calendarDate=this.options.calendarDate.getFirstDayOfMonth();
		
		// just for sure
		this.options.calendarDate.setHours(0,0,0,0);
		this.options.currentDate.setHours(0,0,0,0);
		
		this.load();
	},
	
	load: function()
	{
		var startDate = this.options.calendarDate.getFirstDayOfMonth(); 
		var endDate = this.options.calendarDate.getLastDayOfMonth();
		
		endDate.setHours(23,59,59,59);
		
		var params = $H({
							type: 'json', 
							start: startDate.getDBFormatString(), 
							end: endDate.getDBFormatString() 
						}).toQueryString();
		
		
		/*
		this.fillCalendar([{startDate: '2008-06-28 12:30:22',endDate: '2008-07-04 12:30', name: 'Tapahtuma 1',link: 'http://www.google.fi',ingress: 'Lorem ipsum dolor sit amet. Lorem ipsumma blahblahblöha'},
						   {startDate: '2008-07-16 12:30:22',endDate: '2008-07-17 12:30', name: 'Tapahtuma 2',link: 'http://www.google.fi',ingress: 'Lorem ipsum dolor sit amet. Lorem ipsumma blahblahblöha'},
						   {startDate: '2008-07-17 12:30:22',endDate: '2008-07-17 14:30', name: 'Tapahtuma 3',link: 'http://www.google.fi',ingress: 'Lorem ipsum dolor sit amet. Lorem ipsumma blahblahblöha'},
						   {startDate: '2008-07-20 10:30:22',endDate: '2008-07-20 12:30', name: 'Tapahtuma 4',link: 'http://www.google.fi/?q=moi',ingress: 'Lorem2 ipsum dolor sit amet. Lorem ipsumma blahblahblöha'},
						   {startDate: '2008-07-30 10:30:22',endDate: '2008-08-01 12:30', name: 'Tapahtuma 5',link: 'http://www.google.fi/?q=moi',ingress: 'Lorem2 ipsum dolor sit amet. Lorem ipsumma blahblahblöha'}
						   ]);
		
		*/
		
		this.startLoad();
		
		new Ajax.Request(this.url,{
			method: 'post',
			parameters: params,
			on403: function(transport)
			{
				alert('HTTP Error 403, please login!');
			},
			onSuccess: function(transport)
			{
				
				var json=transport.responseJSON;
			
				
				this.createCalendar();
				
				if(this.options.haltOnAjaxResultError && json.errors.length > 0)
				{
					var tmpStr = 'Calendar: Errors occurred!';
					
					if(this.options.displayAjaxResultErrors)
					{
						tmpStr+="\n"+json.errors.join("\n");
					} 
					
					alert(tmpStr);
				}else
				{
					
					this.fillCalendar(json.results);
					
				}
				
			}.bind(this),
			onComplete: function(transport)
			{
				
				this.endLoad();
			}.bind(this)
		});
		
	},
	
	startLoad: function()
	{},
	
	endLoad: function()
	{},
	
	createCalendar: function()
	{	
		/*
		this.target.innerHTML='\
				<a id="'+this.id+'_previous'+'" href="#" class="previous"><span>◄</span></a>\
				<span class="month">'+this.options.monthNames[this.options.calendarDate.getMonth()]+' '+this.options.calendarDate.getFullYear()+'</span>\
				<a id="'+this.id+'_next'+'" href="#" class="next"><span>►</span></a>\
				<div id="'+this.id+'_toolTip" class="toolTip" style="display: none;"><div id="'+this.id+'_toolTipContents"  class="toolTipContents"></div></div>';
		
		var link_prev = $(this.id+'_previous');
		var link_next = $(this.id+'_next');
		
		if(link_prev != null)
		{
			Event.observe(link_prev, 'click', function(event)
			{
				this.previousMonth();
			}.bind(this) );
		}
		
		if(link_next != null)
		{
			Event.observe(link_next, 'click', function(event)
			{
				this.nextMonth();
			}.bind(this) );
		}
	
		*/
		this.target.innerHTML='';
		var firstDayOfCalendar=this.options.calendarDate.getDay();
		
		
		var lastDayOfCalendar=this.options.calendarDate.getLastDayOfMonth().getDay();
		
		
		var calendarTable = Builder.node('table',{className: 'NFX_Calendar'}); //'<table class="NFX_Calendar"></table>';
		
		
		if(this.options.showDays.length==8)
		{
			var thead = Builder.node('thead');
			var tr = Builder.node('tr');
			
			for(var i=0;i<8;i++)
			{
				tr.appendChild(Builder.node('th',this.options.showDays[i]));
			}
			
			thead.appendChild(tr);
			calendarTable.appendChild(thead);
		}
		
		var tbody=Builder.node('tbody');
		var tr = Builder.node('tr');
		
		//tr.appendChild(Builder.node('td',{className: 'weekNo'},[Builder.node('div',this.options.calendarDate.getFirstDayOfMonth().getWeek(1))]));
		tr.appendChild(Builder.node('td',{className: 'weekNo'},[Builder.node('div',this.options.calendarDate.getFirstDayOfMonth().strftime('%W'))]));
		
		if(firstDayOfCalendar > 1 )
		{
			tr.appendChild(Builder.node('td',{colSpan: firstDayOfCalendar-1},' '));
			
		}else if(firstDayOfCalendar == 0)
		{
			tr.appendChild(Builder.node('td',{colSpan: 6},' '));			
		}
		
		lastDay=this.options.calendarDate.getLastDayOfMonth();
		var today=false;
		for(i=new Date(),
			i.setTime(this.options.calendarDate.getTime());
			i<=lastDay;
			i.setDate(i.getDate()+1))
		{
			if(
				i.getMonth()==this.options.currentDate.getMonth()
				&& 
				i.getDate()==this.options.currentDate.getDate()
				&& 
				i.getYear()==this.options.currentDate.getYear()
			)
			{
				tr.appendChild(Builder.node('td',{className: 'currentDay',id: this.makeDateIdentifier(i)},[Builder.node('div', i.getDate()<10 ? '0'+i.getDate() : i.getDate())]));
				today=true;
			}else
			{
				tr.appendChild(Builder.node('td',{id: this.makeDateIdentifier(i)},[Builder.node('div', i.getDate()<10 ? '0'+i.getDate() : i.getDate())]));
			}
			
			
			
			if(i.getDate()==lastDay.getDate())
			{
				
			
				if(lastDayOfCalendar>0)
				{
					tr.appendChild(Builder.node('td',{colSpan: 7-lastDayOfCalendar},' '));
					
				}
			
				tbody.appendChild(tr);
			}
			
			if(i.getDay()==0 && i.getDate()!=lastDay.getDate())
			{
				
				tbody.appendChild(tr);
				
				tr = Builder.node('tr');
				var daytemp = i.clone();
				tr.appendChild(Builder.node('td',{className: 'weekNo'},[Builder.node('div',daytemp.add(1,'days').getWeek(1))]));
				
				
				
			}
		}
		
	
		calendarTable.appendChild(tbody);
		

		
		
		Element.insert(this.target,calendarTable);
		this.target.innerHTML+='\
			<a id="'+this.id+'_previous'+'" class="previous"><span>◄</span></a>\
			<span class="month">'+this.options.monthNames[this.options.calendarDate.getMonth()]+' '+this.options.calendarDate.getFullYear()+'</span>\
			<a id="'+this.id+'_next'+'" class="next"><span>►</span></a>\
			<div id="'+this.id+'_toolTip" class="toolTip" style="display: none;"><div id="'+this.id+'_toolTipContents"  class="toolTipContents"></div></div><br/>\
			<div class="exactSearchDiv"><a href="'+this.url+'">Tarkka haku</a></div>';
	
		var link_prev = $(this.id+'_previous');
		var link_next = $(this.id+'_next');
		
		if(link_prev != null)
		{
			Event.observe(link_prev, 'click', function(event)
			{
				this.previousMonth();
			}.bind(this) );
		}
		
		if(link_next != null)
		{
			Event.observe(link_next, 'click', function(event)
			{
				this.nextMonth();
			}.bind(this) );
		}		
		
		
		
		
	},
	
	nextMonth: function()
	{
		this.options.calendarDate.setDate(this.options.calendarDate.getLastDayOfMonth().getDate()+1);
		
		this.setCalendarDate(this.options.calendarDate);
	},
	previousMonth: function()
	{
		
		this.options.calendarDate.setDate(this.options.calendarDate.getFirstDayOfMonth().getDate()-1);
	
		this.setCalendarDate(this.options.calendarDate);
	},
	
	setCalendarDate: function(newDate)
	{
		this.options.calendarDate=newDate.getFirstDayOfMonth();
		
		// do load
		this.load();
	},
	
	fillCalendar: function(results)
	{
		var calendarStartDate=this.options.calendarDate.getFirstDayOfMonth();
		var calendarEndDate=this.options.calendarDate.getLastDayOfMonth();
		
		this.eventDates=new Array();
		
		for(var dayNo=0, e=calendarEndDate.getDate();dayNo<=e;dayNo++)
		{
			this.eventDates[dayNo]=new Array();
		}
		
		this.events=results;
		
		for(var i=0,len=results.length;i<len;i++)
		{
			var row=results[i];
			
			
			/*
			var startDate=new Date();
			var endDate=new Date();
			
			startDate.setFromDBFormat(row.startDate);
			endDate.setFromDBFormat(row.endDate);
			*/
			var startDate=$D(row.startDate);
			var endDate=$D(row.endDate);
			
			var startD=new Date();
			startD.setTime(startDate.getTime());
			startD.setHours(0,0,0,0);
			
			var endD=new Date();
			endD.setTime(endDate.getTime());
			endD.setHours(0,0,0,0);
			
			if(startD<calendarStartDate)
			{
				startD=calendarStartDate;
			}
			
			if(endD>calendarEndDate)
			{
				endD=calendarEndDate;
			}
			
			//alert(row.name+' s'+startD.toLocaleString()+' e'+endD.toLocaleString());
			
			for(;startD<=endD;startD.setDate(startD.getDate()+1))
			{
				var tmpId=this.makeDateIdentifier(startD);
				
				this.eventDates[startD.getDate()].push(i);
				
				if(!$(tmpId).hasClassName('hasEvent'))
				{
					$(tmpId).addClassName('hasEvent');
					
					Event.observe($(tmpId).down(), 'click', function(event)
					{
						var Elem = Event.element(event).up();
						var tmp = Elem.getAttribute('id');
						
						if(tmp==null) return;
						
						var dateNo=tmp.substr( ( tmp.length ) - 2);
						
						dateNo=parseInt(dateNo, 10);
						
						var len=this.eventDates[dateNo].length;
						
						if(len>1)
						{
							var tmpDate = this.options.currentDate;
							tmpDate.setDate(dateNo);
							tmpDate.setMonth(parseInt(this.options.calendarDate.getMonth(), 10));
							tmpDate.setYear(parseInt(this.options.calendarDate.getFullYear()));
						
							//document.location.href=this.url+'?event_id='+tmpId;
							
							 document.location.href=this.url+'?date='+$D(tmpDate).strftime('%Y-%m-%d');
							 
						}else
						{
							var tmpDate = this.options.currentDate;
							tmpDate.setDate(dateNo);
							tmpDate.setMonth(parseInt(this.options.calendarDate.getMonth(),10));
							tmpDate.setYear(parseInt(this.options.calendarDate.getFullYear()));
							
							//document.location.href=this.url+'?event_id='+tmpId;
							
							//document.location.href=this.events[this.eventDates[dateNo][0]].link;
							document.location.href=this.url+'?date='+$D(tmpDate).strftime('%Y-%m-%d');
							
						}
						
						
					}.bind(this));
					
					Event.observe($(tmpId).down(), 'mouseover', function(event)
					{
						var Elem = Event.element(event).up();
						var tmp = Elem.getAttribute('id');
						
						if(tmp==null) return;
						
						var dateNo=tmp.substr( ( tmp.length ) - 2);
						
						dateNo=parseInt(dateNo, 10);
						
						var toShow=new Array();
						
						
						for(var o=0, len=this.eventDates[dateNo].length; o<len;o++)
						{
							toShow.push(this.parseCalendarEvent(this.eventDates[dateNo][o]));
						}
						
						
						toolTip=$(''+this.id+'_toolTip');
						
						toolTip.down().update(toShow.join("<hr />"));
						
						if(navigator.userAgent.toLowerCase().indexOf("msie 6")!=-1)
						{
							var foo=Elem.positionedOffset();
						
							foo[1]+=Elem.getHeight()/4;
							foo[0]+=Elem.getWidth()/4;
							
							
							toolTip.absolutize();
							//toolTip.style.position = 'absolute';		
							toolTip.style.display='block';
							
							toolTip.style.top = (foo[1] - (toolTip.getHeight()) ) + "px";
   							toolTip.style.left = (foo[0] - (toolTip.getWidth())) + "px";
						
						}else
						{
							var foo=Elem.cumulativeOffset();
						
							foo[1]+=Elem.getHeight()/4;
							foo[0]+=Elem.getWidth()/4;
							
							
							toolTip.style.position = 'absolute';		
							toolTip.style.display='block';
							
							toolTip.style.top = (foo[1] - toolTip.getHeight()) + "px";
   							toolTip.style.left = (foo[0] - toolTip.getWidth()) + "px";
						}
						
						
   					
   						
						//toolTip.style.top = (foo[1] - toolTip.getHeight() + "px";
   						//toolTip.style.left = (foo[0] - toolTip.getWidth()) + "px";
						
   						
						Event.stop(event);
						
					}.bind(this) );
					
					
					
					Event.observe($(tmpId).down(), 'mouseout', function(event)
					{
						var Elem = Event.element(event);
						
						var tmp = Elem.getAttribute('id');
						
						toolTip=$(this.id+'_toolTip');
						
						toolTip.down().update('');
						
						toolTip.style.display='none';
						
						Event.stop(event);
						
					}.bind(this) );
					
					
				}
				
				
			}
			
		}
		
	},
	
	parseCalendarEvent: function(eventNo)
	{
		var showEvent=Object.clone(this.events[eventNo]);
		
		
		showEvent.startDate=$D(showEvent.startDate).strftime(this.options.dateDisplayFormat);
		showEvent.endDate=$D(showEvent.endDate).strftime(this.options.dateDisplayFormat)
		return this.options.EventTemplate.evaluate(showEvent);
	},
	
	makeDateIdentifier: function( dateToIdent )
	{
		var tmpId=this.id+'_day_'+dateToIdent.getFullYear();
		
		var tmp='';
		
		tmp=dateToIdent.getMonth()+1;
		tmp=tmp.toString();
		
		var pad="0";
		
		if(tmp.length<2)
		{
			tmp=pad.concat(tmp);
		}
		
		tmpId += "-"+tmp;
		
		tmp=dateToIdent.getDate();
		tmp=tmp.toString();
		
		if(tmp.length<2)
		{
			tmp=pad.concat(tmp);
			
		}
		
		tmpId += "-"+tmp;
		
		return tmpId;
	}

});