/***************************************************************************
 * mootools-embedded-calendar.js
 * ---------------
 *   author		-> Tyson Cox
 *   started	-> Wednesday, May 13th, 2009
 *   modified	-> Wednesday, May 13th, 2009
 *   copyright	-> 
 *   email     	-> tyson@imagin8.com
 *   version    -> 1.0
 *
 * file description
 * ------------------
 * 
 *
 *
 * change log
 * ------------------
 * 1.0			Initial development
 *
 ***************************************************************************/

embeddedMooCalendar = new Class({
	
	                /*--------------------------------------------------------o
	----------------\                     Member Variables                    |
	    variables    \-------------------------------------------------------*/

	daysInWeek: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'],
	monthsInYear: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
	daysInMonth: [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31],
	minYear: (new Date().getFullYear() - 10),
	maxYear: (new Date().getFullYear() + 10),
	curDate: 0,
	labelChars: 1,
	itemBuffer: 40,
	dateFormat: 'd/m/y',
	triggerElement: null,
	insertElement: null,
	created: false,
	active: false,
	FX: null,
	docBody: null,
	hasFocus: false,
	container: null,
	events: null,
	hourStart: 0,
	hourEnd: 23,
	blockMins: 60,
	
	
	                /*--------------------------------------------------------o
	----------------\                    Internal Functions                   |
	     internal    \-------------------------------------------------------*/
	
	initialize: function(container, options) {
		this.setOptions(options);
		
		this.container = container;
		this.cookieName = (options.cookieName) ? options.cookieName : null;
		this.cookieDomain = (options.cookieDomain) ? options.cookieDomain : null;
		this.recurseChildren = (options.recurseChildren) ? true : false;
		this.defaultState = (options.defaultState) ? options.defaultState : 'collapsed';
		
		if ( this.cookieDomain && this.cookieName ) {
			this.saveState = new Hash.Cookie(this.cookieName, {		duration: 60,
																	domain: this.cookieDomain,
																	path: '/'
																});
			container.setProperty('cookieName', this.cookieName);
		}
		
		if ( !options.delayCreate ) {
			this.create();
		}
	},
	

	                /*--------------------------------------------------------o
	----------------\                    Calendar Functionality                   |
	      lists      \-------------------------------------------------------*/
	
	create: function() {
		this.created = true;
		this.display();
	},
	
	
	display: function(y, m, d) {
		var date = new Date();
		
		if ( !y ) {		var y = date.getFullYear();		}
		if ( !m ) {		var m = date.getMonth() + 1;	}
		if ( !d ) {		var d = date.getDate();			}
		
		var layoutDate = new Date();
		layoutDate.setFullYear(y);
		layoutDate.setMonth(m - 1);
		layoutDate.setDate(1);
		var startDay = layoutDate.getDay();
		
		if ( m == 2 ) {
			if ( y % 4 == 0 ) {
				var daysInMonth = 28;
			} else {
				var daysInMonth = this.daysInMonth[m-1];
			}
		} else {
			var daysInMonth = this.daysInMonth[m-1];
		}
		
		// Clear all the contents from the frame for redisplay
		this.container.empty();
		
		this.createDateDropdowns(y, m);
		this.createWeekHeaders();
		this.createMonthFrame(y, m, d, startDay, daysInMonth);
	},
	
	
	reDisplay: function(y, m) {
		var layoutDate = new Date();
		layoutDate.setFullYear(y);
		layoutDate.setMonth(m - 1);
		layoutDate.setDate(1);
		var startDay = layoutDate.getDay();
		
		if ( m == 2 ) {
			if ( y % 4 == 0 ) {
				var daysInMonth = 28;
			} else {
				var daysInMonth = this.daysInMonth[m-1];
			}
		} else {
			var daysInMonth = this.daysInMonth[m-1];
		}
		
		// Remove the current month display
		if ( $('calMonthFrame') )			$('calMonthFrame').dispose();
		if ( $('calWeekdayHeader') ) 		$('calWeekdayHeader').dispose();
		if ( $('calWeekViewHeader') ) 		$('calWeekViewHeader').dispose();
		if ( $('calWeekFrame') ) 		$('calWeekFrame').dispose();
		
		this.createWeekHeaders();
		this.createMonthFrame(y, m, 1, startDay, daysInMonth);
	},
	
	
	createDateDropdowns: function(y, m) {
		var ddContain = new Element('div', {'class': 'calDropdownContainer'});
		var ddYear = new Element('select', {id: 'calYear', 'class': 'calYear'});
		var ddMonth = new Element('select', {id: 'calMonth', 'class': 'calMonth'});
		
		for ( var x = this.minYear; x < this.maxYear; x++ ) {
			ddYear.adopt(new Element('option', {value: x, text: x, selected: ((y == x) ? true : false)}));
		}
		
		// Add onChange update event
		mooCal = this;
		ddYear.addEvent('click', function() {		mooCal.reDisplay($('calYear').value, $('calMonth').value);	});
		
		for ( var x = 0; x < 12; x++ ) {
			ddMonth.adopt(new Element('option', {value: (x+1), text: this.monthsInYear[x], selected: ((m - 1 == x) ? true : false)}));
		}
		
		// Add onChange update event
		ddMonth.addEvent('click', function() {		mooCal.reDisplay($('calYear').value, $('calMonth').value);	});
		
		ddContain.adopt(ddMonth, ddYear);
		this.container.adopt(ddContain);
	},
	
	
	createWeekHeaders: function() {
		var weekdayContain = new Element('div', {'class': 'calWeekdayHeader', 'id': 'calWeekdayHeader'});
		var weekdayList = new Element('ul', {'class': 'calWeekdayList'});
		
		for ( var x = 0; x < 7; x++ ) {
			weekdayList.adopt(new Element('li', {text: this.daysInWeek[x].substr(0, this.labelChars), 'class': 'calDayHeader calDayCell calDay' + x}));
		}
		
		weekdayContain.adopt(weekdayList);
		this.container.adopt(weekdayContain);
	},
	
	
	createMonthFrame: function(y, m, d, start, days) {
		var calUL = new Element('ul', {'class': 'calMonthFrame',	id: 'calMonthFrame'});
		var cellCount = 0;
		
		// Pad the start of the month as necessary
		for ( var x = 0; x < start; x++ ) {
			calUL.adopt(new Element('li', {'class': 'calDayBlank calDayCell'}));
			cellCount++;
		}
		
		today = new Date();
		var tY = today.getFullYear();
		var tM = today.getMonth() + 1;
		var tD = today.getDate();
		
		
		// Fill in the days
		for ( var x = 1; x <= days; x++ ) {
			// See if there are events for the currently rendering day
			var eventCount = 0;
			
			if ( this.events ) {
				if ( this.events[y] ) {
					if ( this.events[y][m] ) {
						if ( this.events[y][m][x] ) {
							//eventCount = this.countObjects(this.events[y][m][x]);
							eventCount = this.events[y][m][x].length;
						}
					}
				}
			}
			
			
			// Selected Class
			if ( this.curDate.y == y && this.curDate.m == m && this.curDate.d == x ) {
				var selectedClass = ' selected';
			} else {
				var selectedClass = '';
			}
			
			// Today Class
			if ( tY == y && tM == m && tD == x ) {
				var todayClass = ' today';
			} else {
				var todayClass = '';
			}
			
			// Events Class
			var eventClass = (eventCount) ? ' hasEvents' : '';
			
			
			var li = new Element('li', {	'class': 'calDayFilled calDayCell calDay' + (cellCount%7) + ((d == x) ? ' calDaySelected' : '') + selectedClass + todayClass + eventClass, 
											'dayNum': x});
			li.adopt(new Element('span', {	'class': 'calDate',		'text': x	})	);
			
			if ( eventCount ) {
				//li.adopt(new Element('span', {	'class': 'eventInfo',	'text': eventCount + ' event' + ((eventCount > 1) ? 's' : '')})	);
			}
			
			var mooCal = this;
			li.addEvent('click', function() {		mooCal.doWeekDisplay(y, m, this.getProperty('dayNum'));	 });
			
			calUL.adopt(li);
			cellCount++;
		}
		
		// Pad the end of the month as necessary
		while ( cellCount % 7 != 0 || cellCount < 42 ) {
			calUL.adopt(new Element('li', {'class': 'calDayBlank calDayCell'}));
			cellCount++;
		}
		
		
		// Attach it to the calendar
		this.container.adopt(calUL, new Element('div', {'class': 'clear'}));
	},
	
	
	addEvent: function(y, m, d, h, i, dur, title) {
		// Add stuff properly
		if ( !this.events ) 					this.events = {};
		if ( !this.events[y] ) 					this.events[y] = {};
		if ( !this.events[y][m] )				this.events[y][m] = {};
		if ( !this.events[y][m][d] ) 			this.events[y][m][d] = new Array();
		
		var count = (this.events[y][m][d].length) ? this.events[y][m][d].length : 0;
		
		this.events[y][m][d][count] = {'title': title, 'startHour': h, 'startMin': i, 'duration': dur,
										'endHour': h + (Math.floor(dur / 3600)),
										'endMin': i + (Math.floor(Math.floor(dur / 60) % 60))};
	},
	
	
	countObjects: function(obj) {
		var count = 0;
		
		for ( k in obj ) {
			count++;
		}
		
		return count;
	},
	
	
	doWeekDisplay: function(y, m, d) {
		// Need to calculate the start of the week
		date = new Date();
		date.setFullYear(y, m - 1, d);
		date.setFullYear(y, m - 1, d - date.getDay());
//		alert("Week display: " + date.getFullYear() + "-" + (date.getMonth() + 1) + "-" + date.getDate());
		
		this.createWeekViewHeaders(date.getFullYear(), date.getMonth() + 1, date.getDate());
		this.createWeekFrame(date.getFullYear(), date.getMonth() + 1, date.getDate());
	},
	
	
	createWeekViewHeaders: function(y, m, d) {
		var weekdayContain = new Element('div', {'class': 'calWeekViewHeader', 'id': 'calWeekViewHeader'});
		var weekdayList = new Element('ul', {'class': 'calWeekViewList'});
		
		weekdayList.adopt(new Element('li', {html: '&nbsp;', 'class': 'calWeekHeader calWeekCell'}));
		
		
		curDate = new Date();
		
		for ( var x = 0; x < 7; x++ ) {
			// Update date value for searching stuff
			curDate.setFullYear(y, m - 1, d + x);
			
			weekdayList.adopt(new Element('li', {text: this.daysInWeek[x].substr(0, this.labelChars) + ' ' + curDate.getDate() + '/' + (curDate.getMonth() + 1), 'class': 'calWeekHeader calWeekCell calWeek' + x}));
		}
		
		if ( $('calMonthFrame') )			$('calMonthFrame').dispose();
		if ( $('calWeekdayHeader') ) 		$('calWeekdayHeader').dispose();
		
		weekdayContain.adopt(weekdayList);
		this.container.adopt(weekdayContain);
	},
	
	
	
	
	createWeekFrame: function(y, m, d, start, days) {
		var calUL = new Element('ul', {'class': 'calWeekFrame',	id: 'calWeekFrame'});
				
		today = new Date();
		var tY = today.getFullYear();
		var tM = today.getMonth() + 1;
		var tD = today.getDate();
		
		curDate = new Date();
		
		
		// Fill in the days
		for ( var hour = this.hourStart; hour <= this.hourEnd; hour += (this.blockMins / 60) ) {
			curDate.setHours(parseInt(Math.floor(hour)), parseInt(((hour - Math.floor(hour)) * 60)));
			var li = new Element('li', {	'text': curDate.getHours() + ':' + ((curDate.getMinutes() < 10) ? '0' : '') + curDate.getMinutes(), 	
											'class': 'calWeekViewFilled calWeekViewCell calWeekView calTimeCell' });
			calUL.adopt(li);

			// Add stuff for the days
			for ( var x = 0; x < 7; x++ ) {
				// Update date value for searching stuff
				curDate.setFullYear(y, m - 1, d + x);
				
				var hasEvent = false;
				var isFuture = false;
				
				isFuture = ( (y >= tY && m >= tM && (d+x) >= tD) || (y >= tY && m > tM) || (y > tY) );
				
				if ( this.events ) {
					if ( this.events[curDate.getFullYear()] ) {
						if ( this.events[curDate.getFullYear()][curDate.getMonth() + 1] ) {
							if ( this.events[curDate.getFullYear()][curDate.getMonth() + 1][curDate.getDate()] ) {
								for ( z = 0; z < this.events[curDate.getFullYear()][curDate.getMonth() + 1][curDate.getDate()].length; z++ ) {
									if ( 
										( curDate.getHours() >= this.events[curDate.getFullYear()][curDate.getMonth() + 1][curDate.getDate()][z].startHour && curDate.getMinutes() >= this.events[curDate.getFullYear()][curDate.getMonth() + 1][curDate.getDate()][z].startMin ) &&
										( 
											( curDate.getHours() < this.events[curDate.getFullYear()][curDate.getMonth() + 1][curDate.getDate()][z].endHour ) ||
											( curDate.getHours() <= this.events[curDate.getFullYear()][curDate.getMonth() + 1][curDate.getDate()][z].endHour && curDate.getMinutes() < this.events[curDate.getFullYear()][curDate.getMonth() + 1][curDate.getDate()][z].endMin ) 
										)
									 ) {
										hasEvent = true;
									}
								}
							}
						}
					}
				}
				
				
				
				var li = new Element('li', {	'html': (hasEvent) ? 'Unavailable' : '&nbsp;',
												'class': 'calWeekViewFilled calWeekViewCell calWeekView calDay' + x,
												'date': curDate.getFullYear() + '-' + (curDate.getMonth() + 1) + '-' + curDate.getDate(),
												'time': curDate.getHours() + ':' + curDate.getMinutes() });
				
				if ( !hasEvent && isFuture && curDate.getDay() != 0 && curDate.getDay() != 6 ) {
					li.addClass('available');
					li.addEvent('click', function() { 	window.location = '/googlecal/f/Google/Calendar/AddEvent/' + this.getProperty('date') + '/' + this.getProperty('time') + '/' } );
				}
				
				if ( hasEvent ) {
					li.addClass('unavailable');
				}
				
				calUL.adopt(li);
			}
		}
		
		
		// Attach it to the calendar
		this.container.adopt(calUL, new Element('div', {'class': 'clear'}));
	},
	
	
	setOptions: function(options) {
		if ( options.minYear ) {			this.minYear = parseInt(options.minYear);			}
		if ( options.maxYear ) {			this.maxYear = parseInt(options.maxYear);			}
		if ( options.curDate ) {			this.curDate = parseInt(options.curDate);			}
		if ( options.labelChars ) {			this.labelChars = parseInt(options.labelChars);		}
		if ( options.dateFormat ) {			this.dateFormat = parseInt(options.dateFormat);		}
		if ( options.hourStart ) {			this.hourStart = parseInt(options.hourStart);		}
		if ( options.hourEnd ) {			this.hourEnd = parseInt(options.hourEnd);			}
		if ( options.blockMins ) {			this.blockMins = parseInt(options.blockMins);		}
	}
	
});