/*
requires prototype >1.6

usage:
	var eve1=function(id){
		alert('hi from:'+id);
	}

	var calendar = new Calendar({
		canvas: $('area'),
		year: 2008,
		month: 7,
		eventclickevent: eve1
	});
	
	calendar.init();

	var calendar = new Calendar({
		canvas: $('area'),
		year: 2008,
		month: 8,
		eventclickevent: eve1,
		data: [{id:1,eventstart:'20080801',title:'event1'},
				{id:2,eventstart:'20080802',title:'event2'},
				{id:3,eventstart:'20080803',title:'event3'},
				{id:4,eventstart:'20080804',title:'event4'}]
	});
	
	calendar.init();
	
	
if you want to load events dynamically, 
make a ajax request, 
get response evaluate to a array of event items
then push() each item into the calendar.data
then call init (defaults to current date and month) or render(month,year);
*/

Calendar=function(params){
	this.cal_days_labels = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
	this.cal_months_labels = ['January', 'February', 'March', 'April','May', 'June', 'July', 'August', 'September','October', 'November', 'December'];
	this.short_cal_months_labels = ['Jan', 'Feb', 'Mar', 'Apr','May', 'Jun', 'Jul', 'Aug', 'Sep','Oct', 'Nov', 'Dec'];
	
	//internal storage of currently shown month+year
	this.date = new Date();
	
	this.year;//currently set year
	this.month;//currently set month
	this.data = new Array();//array of calender items
	
	//create a 2d array to store cells for each day
	this.cells = new Array(7);//columns
	for(var i=0;i<7;i++){
		this.cells[i] = new Array(6);//rows
	}

	//parameter loading
	for(var param in params){
		this[param] = params[param];
	}
	
	//updates internal date based on passed in month and year.
	this.date.setDate(1);//always 1st
	if(null!=this.month){
		this.date.setMonth(this.month);
	}
	if(null!=this.year){
		this.date.setFullYear(this.year);
	}
	
	//html reference elements
	this.canvas;//canvas where the calendar is drawn
	this.table;//table which has <table><thead><th>SUN</th><th>MON</th></thead></table>days
	this.thead;//thead contains monthrow & daysrow
	this.tbody;//contains cells from 1-31
	this.daysrow;//tr containing td's with SUN-SAT
	this.monthrow;//tr containing monthcolleft,monthcolcenter,monthcolright
	this.prevbutton;//prev button
	this.nextbutton;//next button
	this.monthlabel;//month label Jan,Feb,Mar...etc
	this.monthcolleft;//td containing prevbutton
	this.monthcolcenter;//td containing monthlabel
	this.monthcolright;//td containing nextbutton
	
	this.eventclickevent;//custom click event
	this.eventhoverevent;//custom event called when title is hovered
	this.eventoutevent;//
	
	this.prevevent;
	this.nextevent;
}

//quick start
Calendar.prototype.init=function(){
	this.render(this.date.getMonth(),this.date.getFullYear());
}

//visually updates the calendar
Calendar.prototype.render=function(month,year){
	this.date.setDate(1);
	this.date.setMonth(month);
	this.date.setFullYear(year);
	
	if(null!=this.canvas)//has a canvas so we can draw :P
	{
		if(null==this.table){
			this.canvas.innerHTML = "";//crude but works
			this.table = this.createTable();//create new table
			this.canvas.appendChild(this.table);//add to canvas
		}
		
		//reset the content of each cell in table
		for(var row=0;row<6;row++){
			for(var col=0;col<7;col++){
				this.cells[col][row].innerHTML = "";
				Element.setStyle(this.cells[col][row],{
					display:''
				});
			}
		}
		
		//update the monthlabel
		this.monthlabel.innerHTML = this.cal_months_labels[this.date.getMonth()]+ '-' +this.date.getFullYear();
		
		//do padding
		//get first day of month
		var daypadding = this.date.getDay();//0=sunday, padding for first day in week
		var numofdaysinmonth = this.getDaysForMonthAndYear(this.date.getMonth(),this.date.getFullYear());
		//then pad cells
		//then loop through number of days and add to table, assigning a valid date for each cell
		var date = 0;
		for(var row=0;row<6;row++){
			for(var col=0;col<7;col++){
				if(daypadding==0){
					if(numofdaysinmonth!=0){
						date++;
						//date label
						var datelabel = new Element('label');
						datelabel.innerHTML = date;
						this.cells[col][row].appendChild(datelabel);
						//add events
						this.addEventsForDate(this.cells[col][row],date,this.date.getMonth(),this.date.getFullYear());
						numofdaysinmonth--;
					}
					else
					{
						//hide access blocks
						Element.setStyle(this.cells[col][row],{
							display:'none'
						})
					}
				}
				else{
					daypadding--;
				}
			}
		}
	}	
}

//creates the table
Calendar.prototype.createTable=function(){
	this.table = new Element('table',{'class':'calendar-table'});
	this.thead = new Element('thead',{'class':'calendar-thead'});
	this.tbody = new Element('tbody',{'class':'calendar-tbody'});
	this.daysrow = new Element('tr',{'class':'calendar-daysrow'});
	this.monthrow = new Element('tr',{'class':'calendar-monthrow'});
	this.monthcolleft = new Element('td',{'class':'calendar-monthcolleft'});
	this.monthcolcenter = new Element('td',{colspan:'5','class':'calendar-monthcolcenter'});
	this.monthcolright = new Element('td',{'class':'calendar-monthcolright'});
	this.prevbutton = new Element('input',{type:'button',value:'Prev','class':'calendar-prevbutton'});
	this.nextbutton = new Element('input',{type:'button',value:'Next','class':'calendar-nextbutton'});
	this.monthlabel = new Element('label',{'class':'calendar-monthlabel'});
	
	var myobj = new Object();
	myobj['this'] = this;
	
	//attache onclick events to buttons
	Event.observe(this.prevbutton,'click',function(e){
		myobj['this'].prev();
	});
	
	Event.observe(this.nextbutton,'click',function(e){
		myobj['this'].next();
	});
	
	//updates 2d array with references to each cell
	for(var row=0;row<6;row++)
	{	
		var r = new Element('tr');
		for(var col=0;col<7;col++)
		{
			var c = new Element('td');
			r.appendChild(c);
			this.cells[col][row] = c;//updates internal reference
		}
		this.tbody.appendChild(r);
	}
	
	//prev/next btn + month
	this.monthrow.appendChild(this.monthcolleft);
	this.monthrow.appendChild(this.monthcolcenter);
	this.monthrow.appendChild(this.monthcolright);
	
	this.monthcolleft.appendChild(this.prevbutton);
	this.monthcolleft.appendChild(this.nextbutton);
	this.monthlabel.innerHTML = this.cal_months_labels[this.date.getMonth()]+'-'+this.date.getFullYear();
	this.monthcolcenter.appendChild(this.monthlabel);
	
	//days from sun to sat
	for(var i=0;i<7;i++){
		var th = new Element('th');
		th.innerHTML = this.cal_days_labels[i];
		this.daysrow.appendChild(th);
	}
	
	this.thead.appendChild(this.monthrow);
	this.thead.appendChild(this.daysrow);
	this.table.appendChild(this.thead);
	this.table.appendChild(this.tbody);
	
	return this.table;
}

Calendar.prototype.prev=function(){
	this.date.setMonth(this.date.getMonth()-1);
	this.render(this.date.getMonth(),this.date.getFullYear());
	
	var myobj = new Object();
	myobj['this'] = this;
	if(null!=this.prevevent)
	{
		myobj['this'].prevevent();
	}
	
}

Calendar.prototype.next=function(){
	this.date.setMonth(this.date.getMonth()+1);
	this.render(this.date.getMonth(),this.date.getFullYear());
	
	var myobj = new Object();
	myobj['this'] = this;
	if(null!=this.nextevent)
	{
		myobj['this'].nextevent();
	}
}

Calendar.prototype.addEventsForDate=function(cell,date,month,year){
	var date = this.pad('0',date,2,true);
	var month = this.pad('0',month,2,true);
	var year = this.pad('0',year,2,true);
	
	var celldate = year+month+date;
	
	var obj = new Object();
	obj['this'] = this;
	//obj['id'] = 0;
	//obj['counter'] = 0;
	
	//loop throught all events items
	for(var i=0;i<this.data.length;i++)
	{
		var event = this.data[i];
		
		var eventdatetime = this.pad('0',event.dateStart,12,false);
		var eventdatestart = eventdatetime.substring(0,8);
		if(eventdatestart==celldate)
		{	
			//var eventtimestart = eventdatetime.substring(8,12);
			var eventdetails = new Element('span');
			var link = new Element('a',{
				'eventid':event.id,
				'class':'calendar-link'
			});
			
			link.innerHTML = event.title.substring(0,30);
			if(event.title.length>30)
				link.innerHTML+="...";
			
			var eventdescription = new Element('div',{'class':'calendar-eventdescription'});
			
			if(null!=event.location)
			{
				loc = "";
				if(event.location.city)
				{
					loc += event.location.city+", "; 
				}
				
				if(event.location.country)
				{
					loc += event.location.country;
				}
				eventdescription.innerHTML = loc+"<br>";
			}
			
			/*
			if(null!=event.quickVenue)
			{
				eventdescription.innerHTML = event.quickVenue+"<br>";
			}
			*/
			
			if(null!=event.isVirtual && event.isVirtual=="true")
			{
				//clean url
				var url = event.url.toLowerCase();
				url = url.replace('http://','');
				url = "http://"+url;
				eventdescription.innerHTML = "Online: <a target='_blank' href='"+url+"'>Visit</a>";
			}
			
			/*
			if(null!=event.description){
				var description = event.description;
				if(event.description.length > 50)
				{
					description = description.substring(0,50)+"...";
				}
				eventdescription.innerHTML = description;
			}
			*/
			
			eventdetails.appendChild(link);
			eventdetails.appendChild(eventdescription);
			
			cell.appendChild(eventdetails);
			
			//ATTACH EVENTS AFTER ITEMS ARE IN DOM
			if(null!=this.eventclickevent && null != event.id)
			{
				Event.observe(link,'click', function(e){
					Event.stop(e);
					var tmpele = Event.element(e);
					var tmpeventid = tmpele.getAttribute("eventid");
					obj['this'].eventclickevent(tmpeventid);
				});
			}
			//custom hover effect
			if(null!=this.eventhoverevent && null != event.id)
			{
				Event.observe(link,'mouseover', function(e){
					Event.stop(e);
					var tmpele = Event.element(e);
					var tmpeventid = tmpele.getAttribute("eventid");
					obj['this'].eventhoverevent( tmpeventid,e );
				});
			}
			//custom mouse out
			if(null!=this.eventoutevent && null != event.id)
			{
				Event.observe(link,'mouseout', function(e){
					Event.stop(e);
					var tmpele = Event.element(e);
					var tmpeventid = tmpele.getAttribute("eventid");
					obj['this'].eventoutevent( tmpeventid );
				});
			}
		}
	}
}

//gets the number of days for a given month taking into account leap years
Calendar.prototype.getDaysForMonthAndYear=function(month,year)
{
	/*
		The Gregorian calendar, the current standard calendar in most of the world, 
		adds a 29th day to February in all years evenly divisible by 4, 
		except for centennial years (those ending in '00'), 
		which receive the extra day only if they are evenly divisible by 400. 
		Thus 1600, 2000 and 2400 are leap years but 1700, 1800, 1900 and 2100 are not.
	*/
	var daysinmonth = [31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
	var days = 0;
	var date = new Date();
	date.setFullYear(year)
	date.setMonth(month);
	
	if(month==1){ //february
		//check for leap year
		var isleap = false;
		//check if centennial years
		var cenn = year.toString().split('').reverse();//0002
		cenn.pop();//0,0,0
		cenn.pop();//0,0
		cenn = cenn.join('');//00
		
		if(cenn=="00"){//centennial year
			//check if evenly divisible by 400
			if(year % 400 == 0){//evenly divisible by 400
				isleap=true;
			}
			else{
				isleap=false;
			}
		}
		else{//not centennial
			if(year % 4 == 0){
				isleap=true;
			}else{
				isleap=false;
			}
		}
		
		if(isleap){
			days=29;
		}
		else{
			days=28;
		}
	}
	else{
		days = daysinmonth[month];
	}
	return days
}

//pads a variable with given chars of expected length returns string
Calendar.prototype.pad=function(char,value,expectedlength,isprefix){
	var result = '';
	var padding = '';
		
	if(value.toString().length<expectedlength)
	{
		var chardiff = expectedlength-value.toString().length;
		for(var i=0;i<chardiff;i++)
		{
			padding+=char;
		}
	}
	
	if(isprefix)
		result = padding+value.toString();
	else{
		result = value.toString()+padding;
	}
		
	return result; 
}

Calendar.prototype.getDataById=function(id){
	for(var i=0;i<this.data.length;i++)
	{
		var data = this.data[i];
		if(data.id != null && data.id == id)
		{
			return data;
		}
	}
	return null;
}

//function wrapper
var Fwrapper=function(params){
	this.id;
	this.method;
	
	for(var param in params)
	{
		this[param] = params[param];
	}
}
Fwrapper.prototype.execute=function()
{
	this.method(this.id);
}