//	Mootools Events Calendar v0.1.0 - [http://dansnetwork.com/mootools/events-calendar]
/*
	Script: mooECal.js
		Class for creating an events calendar with multiple views
	Requires:
		Mootools 1.2 Core
		Mootools 1.2 More
			Tips
			Scroller
	License:
		MIT-style license.
*/
var Calendar = new Class({
	
	Implements: [Options, Events],
	options: {
		calContainer: 'calBody', // id of the element that the calendar will be "injected" into
		calHeight: 300, // calendar height (in pixels)
		newDate: 0, // used to set the initial selected date to one other than the current day
		view: 'month', // options are: month, week, day - sets the default view
		calDate: new Date(), // tracks the selected calendar date
		days: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'],
		months: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
		daysInMonth: 30, // can be set with setDaysInMonth(month,year)
		startingOffset: 0, // determine the offset of the first of the month and Sunday - used for the "month" view
		viewStartDate: new Date(), // used to get events
		viewEndDate: new Date() // used to get events
	},
	initialize: function(options){
		this.setOptions(options);
		this.options.newDate != 0 ? this.options.calDate = new Date(this.options.newDate) : this.options.calDate = new Date();
		this.setCalParams();
		this.extendDate();
		switch(this.options.view){
			case 'month':
				this.showMonth();
				break;
			case 'week':
				this.showWeek();
				break;
			case 'day':
				this.showDay();
				break;
			default:
				this.showMonth;
		}
	},
	setDaysInMonth: function(month, year){ // month: must be an integer (0 - 11) year: used to dertermine if leap year exists
		var daysInMonths = new Array(31,28,31,30,31,30,31,31,30,31,30,31);
		if(new Date(year,1,29).getDate() == 29) // determine if leap year
			daysInMonths[1] = 29;
		this.options.daysInMonth = daysInMonths[month];
	},
	setStartingOffset: function(month,year){ // month: must be an integer (0 - 11)
		this.options.startingOffset = new Date(year,month,1).getDay();
	},
	setDate: function(day){
		this.options.calDate.setDate(day);
	},
	setCalParams: function(){
		this.setDaysInMonth(this.options.calDate.getMonth(), this.options.calDate.getFullYear());
		this.setStartingOffset(this.options.calDate.getMonth(), this.options.calDate.getFullYear());
	},
	showControlsRow: function(calTitle){
		var trC = new Element('tr');
		var thL = new Element('th', {
			'colspan': '2',
			'width':'30%',
			'class':'calHead'
		}).inject(trC);
		var prevCal = new Element('a',{
			'href':'javascript:void(0)',
			'class':'prevCal'
		}).set('html','&larr;').inject(thL);
		new Element('th',{
			'colspan':'3',
			'class':'calHead'
		}).set('html',calTitle).inject(trC);
		var thR = new Element('th',{
			'colspan':'2',
			'class':'calHead'
		}).inject(trC);
		var nextCal = new Element('a',{
			'href':'javascript:void(0)',
			'class':'nextCal'
		}).set('html','&rarr;').inject(thR);
		switch(this.options.view){
			case 'month':
				prevCal.addEvent('click',function(){
					this.showPrevMonth()
				}.bind(this));
				nextCal.addEvent('click',function(){
					this.showNextMonth()
				}.bind(this));
				break;
			case 'week':
				prevCal.addEvent('click',function(){this.showPrevWeek()}.bind(this));
				nextCal.addEvent('click',function(){this.showNextWeek()}.bind(this));
				break;
			case 'day':
				prevCal.addEvent('click',function(){this.showPrevDay()}.bind(this));
				nextCal.addEvent('click',function(){this.showNextDay()}.bind(this));
				break;
		}
		new Element('a',{
			'href':'javascript:void(0)',
			'class':'viewCal',
			'events':{
				'click':function(){
					this.showMonth()
				}.bind(this)
			}
		}).set('text','month').inject(thR);
		new Element('a',{
			'href':'javascript:void(0)',
			'class':'viewCal',
			'events':{
				'click':function(){
					this.showWeek()
				}.bind(this)
			}
		}).set('text','week').inject(thR);
		new Element('a',{
			'href':'javascript:void(0)',
			'class':'viewCal',
			'events':{
				'click':function(){
					this.showDay()
				}.bind(this)
			}
		}).set('text','day').inject(thR);
		return trC;
	},
	showNextMonth: function(){
		this.options.calDate.nextMonth();
		this.setCalParams();
		this.showMonth();
	},
	showPrevMonth: function(){
		this.options.calDate.prevMonth();
		this.setCalParams();
		this.showMonth();
	},
	showMonth: function(){
		$(this.options.calContainer).set('html','');
		this.options.view = 'month';
		var table = new Element('table',{
			'class':'mooECal',
			'id':'monthCal',
			'styles':{
				'height':this.options.calHeight+'px'
			}
		});
		var thead = new Element('thead').inject(table);
		var tbody = new Element('tbody').inject(table);
		
		this.showControlsRow(this.options.months[this.options.calDate.getMonth()]+' '+this.options.calDate.getFullYear()).inject(thead);
		
		var tr = new Element('tr',{
			'class':'dowRow'
		}).inject(thead);
		for (var i = 0; i < 7; i++){
			var th = new Element('th').set('text', this.options.days[i]).inject(tr);
		}
		var calDone = false;
		for (var i = 0; i < 6; i++){
			if(calDone){
				if(i == 5)
					table.set({
						'styles':{
							'height':this.options.calHeight * 0.85 + 'px'
						}
					})
				else if(i==4)
					table.set({
						'styles':{
							'height':this.options.calHeight * 0.70 + 'px'
						}
					})
				break;
			}
			var tr = new Element('tr',{'class':'monthWeek'}).inject(tbody); // create weeks
			for (var j = 0; j < 7; j++) {
				var day = ((j+1) + (i*7)) - this.options.startingOffset;
				var td = new Element('td',{'class':'monthDay','id':'day'+day}).inject(tr); // create days
				if (day > 0 && day <= this.options.daysInMonth){
					td.set({
						events: {
							'mouseover': function(){this.addClass('hover')},
							'mouseout': function(){this.removeClass('hover')},
							'dblclick': function(e){
								this.setDate(e.target.retrieve('date'));
								this.showDay();
							}.bind(this)
						}
					});
					new Element('span',{'text':day}).store('date',day).inject(td);
					td.store('date',day);
					td.addEvent('click', function(){
						$$('td.monthDay').each(function(td){td.removeClass('selected')});
						this.addClass('selected');
					});
					td.addEvent('click',function(e){
						this.setDate(e.target.retrieve('date'))
					}.bind(this));
					new Element('div',{
						'styles':{
							'height':this.options.calHeight * 0.1 + 'px','overflow':'hidden'
						}
					}).store('date',day).inject(td);
					if(day == this.options.calDate.getDate()) //set background color for current day
						td.addClass('selected');
					if(day == this.options.daysInMonth) // comment out for a fixed height calendar
						calDone = true;
				}
				else{
					td.set('html', '&nbsp;'); // IE won't show td borders without something in the cell
				}
				td.fade('hide');
				td.fade('in');
			}
		}
		
		this.options.viewStartDate.setTime(this.options.calDate.valueOf());
		this.options.viewStartDate.setDate(1);
		this.options.viewEndDate.setTime(this.options.calDate.valueOf());
		this.options.viewEndDate.setDate(this.options.daysInMonth);
		this.options.viewStartDate.startOfDay();
		this.options.viewEndDate.endOfDay();
		
		table.inject($(this.options.calContainer));
		this.loadCalEvents();
		
	}, // end of showMonth
	showNextWeek: function(){
		var nWeek = this.options.calDate.getDate();
		this.options.calDate.setDate(nWeek+7)
		this.setCalParams();
		this.showWeek();
	},
	showPrevWeek: function(){
		var pWeek = this.options.calDate.getDate();
		this.options.calDate.setDate(pWeek-7)
		this.setCalParams();
		this.showWeek();
	},
	showWeek: function(){
		var wDate = new Date(this.options.calDate.toLocaleString());
		var dow = wDate.getDay();
		wDate.setDate(wDate.getDate()-dow); //set date to Sunday (for first day of the week
		var lastDay = new Date(wDate.toLocaleString()); // used for header info(last day of the week)
		lastDay.setDate(lastDay.getDate()+6);
		
		$(this.options.calContainer).set('html', '');
		this.options.view = 'week';
		var table = new Element('table', {
			'class':'mooECal',
			'id': 'weekCal',
			'styles':{
				'height':this.options.calHeight+'px'
			}
		});
		var thead = new Element('thead').inject(table);
		var tbody = new Element('tbody').inject(table);
			
		this.showControlsRow(this.options.months[wDate.getMonth()]
			+ ' ' + wDate.getDate() + ', ' + wDate.getFullYear() + '&nbsp; - &nbsp;'
			+ this.options.months[lastDay.getMonth()]
			+ ' ' + lastDay.getDate() + ', ' + lastDay.getFullYear()).inject(thead);
		
		this.options.viewStartDate.setTime(wDate.valueOf());
		this.options.viewEndDate.setTime(lastDay.valueOf());
		this.options.viewStartDate.startOfDay();
		this.options.viewEndDate.endOfDay();
			
		var tr = new Element('tr').inject(thead);
		for (var i = 0; i < 7; i++){
			var th = new Element('th').set('text', this.options.days[i]).inject(tr);
		}
		var trWeek = new Element('tr',{'class':'weekWeek'}).inject(tbody); // create week
		for(var i = 0; i < 7; i++){
			var td = new Element('td',{
				'class':'weekDay',
				'id':'day'+wDate.getDate()
			}).inject(trWeek); // create days
			td.set({
				events: {
					'mouseover': function(){
						this.addClass('hover')
					},
					'mouseout': function(){
						this.removeClass('hover')
					},
					'dblclick': function(e){
						this.setDate(e.target.retrieve('date'));
						this.showDay();
					}.bind(this)
				} 
			});
			new Element('span',{'text':wDate.getDate()}).store('date',wDate.getDate()).inject(td);
			td.store('date',wDate.getDate());
			td.addEvent('click', function(){
				$$('td.weekDay').each(function(td){
					td.removeClass('selected')
				});
				this.addClass('selected');
			});
			td.addEvent('click',function(e){
				this.setDate(e.target.retrieve('date'))
			}.bind(this));
			new Element('div',{
				'styles':{
					'height':this.options.calHeight * 0.80 + 'px','overflow':'hidden'
				}
			}).store('date',wDate.getDate()).inject(td);
			if(wDate.getDate() == this.options.calDate.getDate()) //set background color for current day
				td.addClass('selected');
			wDate.setDate(wDate.getDate()+1);
		}
		trWeek.fade('hide');
		trWeek.fade('in');
		
		table.inject($(this.options.calContainer));
		this.loadCalEvents();
	}, //end of showWeek
	showNextDay: function(){
		var nDay = this.options.calDate.getDate();
		this.options.calDate.setDate(nDay+1)
		this.setCalParams();
		this.showDay();
	},
	showPrevDay: function(){
		var pDay = this.options.calDate.getDate();
		this.options.calDate.setDate(pDay-1)
		this.setCalParams();
		this.showDay();
	},
	showDay: function(){
		$(this.options.calContainer).set('html', '');
		this.options.view = 'day';
		var table = new Element('table', {
			'class':'mooECal',
			'id': 'weekCal',
			'styles':{
				'height':this.options.calHeight+'px'
			}
		});
		var thead = new Element('thead').inject(table);
		var tbody = new Element('tbody').inject(table);
		
		this.showControlsRow(this.options.months[this.options.calDate.getMonth()]
			+ ' ' + this.options.calDate.getDate() + ', ' + this.options.calDate.getFullYear()).inject(thead);
		
		var trDay = new Element('tr',{'class':'weekDay'}).inject(tbody);
		var td = new Element('td',{
			'class':'weekDay',
			'id':'day'+this.options.calDate.getDate()
		}).inject(trDay); // create day
		td.set({
			'text': this.options.calDate.getDate(),
			'class': 'selected',
			'colspan':'7'
		});
		new Element('div',{
			'styles':{
				'height':this.options.calHeight * 0.85 + 'px','overflow':'auto'
			}
		}).inject(td);
		
		table.inject($(this.options.calContainer));
		this.options.viewStartDate.setTime(this.options.calDate.valueOf());
		this.options.viewEndDate.setTime(this.options.calDate.valueOf());
		this.options.viewStartDate.startOfDay();
		this.options.viewEndDate.endOfDay();
		this.loadCalEvents();
	}, //end of showDay
	loadCalEvents: function(){
		cEvents = [ //simulate JSON feed
		
			{
				eventName:'Home(2Units)',
				eventDate:'02/29/2012',
				startTime:'*'
			},
		
			{
				eventName:'Home(13Units)',
				eventDate:'02/22/2012',
				startTime:'*'
			},
		
			{
				eventName:'Home / Satellite 1(31Units)',
				eventDate:'02/17/2012',
				startTime:'*'
			},
		
			{
				eventName:'Home(211Units)',
				eventDate:'02/15/2012',
				startTime:'*'
			},
		
			{
				eventName:'Home / Satellite 1(795Units)',
				eventDate:'02/10/2012',
				startTime:'*'
			},
		
			{
				eventName:'Home(2103Units)',
				eventDate:'02/08/2012',
				startTime:'*'
			},
		
			{
				eventName:'Satellite 4(371Units)',
				eventDate:'02/07/2012',
				startTime:'*'
			},
		
			{
				eventName:'Satellite 3(965Units)',
				eventDate:'02/07/2012',
				startTime:'*'
			},
		
			{
				eventName:'Car(7574Units)',
				eventDate:'02/03/2012',
				startTime:'*'
			},
		
			{
				eventName:'Home / Satellite 1(1421Units)',
				eventDate:'02/03/2012',
				startTime:'*'
			},
		
			{
				eventName:'Car(12115Units)',
				eventDate:'02/02/2012',
				startTime:'*'
			},
		
			{
				eventName:'Home(1665Units)',
				eventDate:'02/01/2012',
				startTime:'*'
			},
		
			{
				eventName:'Car(4152Units)',
				eventDate:'01/31/2012',
				startTime:'*'
			},
		
			{
				eventName:'Satellite 4(777Units)',
				eventDate:'01/31/2012',
				startTime:'*'
			},
		
			{
				eventName:'Satellite 3(994Units)',
				eventDate:'01/31/2012',
				startTime:'*'
			},
		
			{
				eventName:'Car(2112Units)',
				eventDate:'01/30/2012',
				startTime:'*'
			},
		
			{
				eventName:'Car(8920Units)',
				eventDate:'01/27/2012',
				startTime:'*'
			},
		
			{
				eventName:'Home / Satellite 1(1768Units)',
				eventDate:'01/27/2012',
				startTime:'*'
			},
		
			{
				eventName:'Car(13979Units)',
				eventDate:'01/26/2012',
				startTime:'*'
			},
		
			{
				eventName:'Car(1716Units)',
				eventDate:'01/25/2012',
				startTime:'*'
			},
		
			{
				eventName:'Home(2500Units)',
				eventDate:'01/25/2012',
				startTime:'*'
			},
		
			{
				eventName:'Car(3728Units)',
				eventDate:'01/24/2012',
				startTime:'*'
			},
		
			{
				eventName:'Satellite 4(787Units)',
				eventDate:'01/24/2012',
				startTime:'*'
			},
		
			{
				eventName:'Satellite 3(927Units)',
				eventDate:'01/24/2012',
				startTime:'*'
			},
		
			{
				eventName:'Car(0Units)',
				eventDate:'01/23/2012',
				startTime:'*'
			},
		
			{
				eventName:'Home / Satellite 1(1767Units)',
				eventDate:'01/20/2012',
				startTime:'*'
			},
		
			{
				eventName:'Car(1Units)',
				eventDate:'01/19/2012',
				startTime:'*'
			},
		
			{
				eventName:'Home(2329Units)',
				eventDate:'01/18/2012',
				startTime:'*'
			},
		
			{
				eventName:'Car(1Units)',
				eventDate:'01/17/2012',
				startTime:'*'
			},
		
			{
				eventName:'Satellite 4(691Units)',
				eventDate:'01/17/2012',
				startTime:'*'
			},
		
			{
				eventName:'Satellite 3(975Units)',
				eventDate:'01/17/2012',
				startTime:'*'
			},
		
			{
				eventName:'Car(0Units)',
				eventDate:'01/13/2012',
				startTime:'*'
			},
		
			{
				eventName:'Home / Satellite 1(1409Units)',
				eventDate:'01/13/2012',
				startTime:'*'
			},
		
			{
				eventName:'Car(0Units)',
				eventDate:'01/12/2012',
				startTime:'*'
			},
		
			{
				eventName:'Home(1495Units)',
				eventDate:'01/11/2012',
				startTime:'*'
			},
		
			{
				eventName:'Satellite 4(585Units)',
				eventDate:'01/10/2012',
				startTime:'*'
			},
		
			{
				eventName:'Satellite 3(1068Units)',
				eventDate:'01/10/2012',
				startTime:'*'
			},
		
			{
				eventName:'Home / Satellite 1(3119Units)',
				eventDate:'01/06/2012',
				startTime:'*'
			},
		
			{
				eventName:'Home(1892Units)',
				eventDate:'12/28/2011',
				startTime:'*'
			},
		
			{
				eventName:'Satellite 4(740Units)',
				eventDate:'12/27/2011',
				startTime:'*'
			},
		
			{
				eventName:'Satellite 3(857Units)',
				eventDate:'12/27/2011',
				startTime:'*'
			},
		
			{
				eventName:'Car(1Units)',
				eventDate:'12/23/2011',
				startTime:'*'
			},
		
			{
				eventName:'Home / Satellite 1(1522Units)',
				eventDate:'12/23/2011',
				startTime:'*'
			},
		
			{
				eventName:'Car(1Units)',
				eventDate:'12/22/2011',
				startTime:'*'
			},
		
			{
				eventName:'Home(2209Units)',
				eventDate:'12/21/2011',
				startTime:'*'
			},
		
			{
				eventName:'Car(0Units)',
				eventDate:'12/20/2011',
				startTime:'*'
			},
		
			{
				eventName:'Satellite 4(747Units)',
				eventDate:'12/20/2011',
				startTime:'*'
			},
		
			{
				eventName:'Satellite 3(859Units)',
				eventDate:'12/20/2011',
				startTime:'*'
			},
		
			{
				eventName:'Car(0Units)',
				eventDate:'12/19/2011',
				startTime:'*'
			},
		
			{
				eventName:'Car(0Units)',
				eventDate:'12/16/2011',
				startTime:'*'
			},
		
			{
				eventName:'Home / Satellite 1(1664Units)',
				eventDate:'12/16/2011',
				startTime:'*'
			},
		
			{
				eventName:'Car(1Units)',
				eventDate:'12/15/2011',
				startTime:'*'
			},
		
			{
				eventName:'Home(2219Units)',
				eventDate:'12/14/2011',
				startTime:'*'
			},
		
			{
				eventName:'Car(0Units)',
				eventDate:'12/13/2011',
				startTime:'*'
			},
		
			{
				eventName:'Satellite 4(708Units)',
				eventDate:'12/13/2011',
				startTime:'*'
			},
		
			{
				eventName:'Satellite 3(833Units)',
				eventDate:'12/13/2011',
				startTime:'*'
			},
		
			{
				eventName:'Car(1Units)',
				eventDate:'12/12/2011',
				startTime:'*'
			},
		
			{
				eventName:'Car(1Units)',
				eventDate:'12/09/2011',
				startTime:'*'
			},
		
			{
				eventName:'Home / Satellite 1(1696Units)',
				eventDate:'12/09/2011',
				startTime:'*'
			},
		
			{
				eventName:'Car(1Units)',
				eventDate:'12/08/2011',
				startTime:'*'
			},
		
		];
		$$('div.tip').each(function(divs){divs.getParent().destroy();}); // Tips cleanup - tip divs kept building up after switching calendar views
		for(var i = 0; i < cEvents.length; i++){
			cEvents[i].eventDate = new Date(cEvents[i].eventDate);
			if(cEvents[i].eventDate >= this.options.viewStartDate && cEvents[i].eventDate <= this.options.viewEndDate){
				var eventDiv = new Element('div',{
					'text':cEvents[i].startTime+' '+cEvents[i].eventName
				}).store('date',cEvents[i].eventDate.getDate()).inject($('day'+cEvents[i].eventDate.getDate()).getChildren('div')[0]);
				if (this.options.view != 'month') // the month view only shows a portion of the event description
					eventDiv.addClass('fullEvent');
				else {
					new Scroller($('day' + cEvents[i].eventDate.getDate()).getChildren('div')[0]).start(); //add Scroller to month view days
					new Tips(eventDiv, {onShow: function(tip){tip.setStyle('opacity', '0.9');}});
					eventDiv.store('tip:title',cEvents[i].startTime).store('tip:text',cEvents[i].eventName);
				}
			}
		}
	},
	extendDate: function(){ // this section could also be implemented with MooTools::Implement (no pun intended)
		function prevMonth(){
			var thisMonth = this.getMonth();
			this.setMonth(thisMonth-1);
			if(this.getMonth() != thisMonth-1 && this.getMonth() != 11)
				this.setDate(0);
		};
		function nextMonth(){
			var thisMonth = this.getMonth();
			this.setMonth(thisMonth+1);
			if(this.getMonth() != thisMonth+1 && this.getMonth() != 0)
				this.setDate(0);
		};
		function startOfDay(){
			this.setHours(0);
			this.setMinutes(0);
			this.setSeconds(0);
			this.setMilliseconds(0);
		};
		function endOfDay(){
			this.setHours(23);
			this.setMinutes(59);
			this.setSeconds(59);
			this.setMilliseconds(999);
		};

		Date.prototype.nextMonth = nextMonth;
		Date.prototype.prevMonth = prevMonth;
		Date.prototype.startOfDay = startOfDay;
		Date.prototype.endOfDay = endOfDay;
	}
	
});
