/*
 * Copyright(c) 2009, Soft Idiom Limtied
 * www.softidiom.com and www.4dsites.com
*/

/* Displays a calendar with events.
   Example: Create an instanc, give it some events and render to a div whose id is "caldiv"...
   		var calendar = new SICalendar();
   		calendar.setEvents([
   			{"title":"event1 title","link":"test","date":"2009-03-17","eventType":"MCCA Dinner"},
   			{"title":"event1 title","link":"test","date":"2009-03-18","eventType":"MCCA Dinner"},
   			{"title":"x","link":"","date":"2009-03-18","eventType":"MCCA Group"},
   			{"title":"x","link":"","date":"2009-03-18","eventType":"MCCA Group"},
   			{"title":"event1 title","link":"test","date":"2009-03-19","eventType":"MCCA Dinner"},
   			{"title":"event1 title","link":"test","date":"2009-10-12","eventType":"MCCA Dinner"}
   		]);
   		calendar.render('caldiv);
*/
function SICalendar() {
	this.month = new Date().getMonth(); 
	this.year = new Date().getFullYear();
	this.yearRange = 8;
	this.allEventsName = 'All Events';
	this.type = this.allEventsName;
	this.baseDate = new Date(this.year,this.month,7);
	this.date = new Date();
	this.width = 850;
	this.height = 218;
	this.dayNames = ['Mon','Tue','Wed','Thu','Fri','Sat','Sun'];
	this.monthNames = ['January','February','March','April','May','June','July','August','September','October','November','December'];
	this.events = [
		{
			title: 'Sample event4',
			link: '#',
			date: new Date(2002,9,29,20,5,8,10),
			eventType: 'Dinner'
		},
		{
			title: 'Sample event1',
			link: '#',
			date: new Date(),
			eventType: 'Dinner'
		},
		{
			title: 'Sample event2',
			link: '#',
			date: new Date(),
			eventType: 'Training'
		},
		{
			title: 'Sample event3',
			link: '#',
			date: new Date(),
			eventType: 'Training'
		},{
			title: 'Sample event5',
			link: '#',
			date: new Date(2003,9,29,20,5,8,10),
			eventType: 'Dinner'
		}
	];
	
	this.setEvents = function(eventArray) {
		//set the events
		this.events = [];
		for(i=0;i<eventArray.length; i++) {
			var e = eventArray[i];
			var dateElements = e.date.split('-');
			e.date = new Date(dateElements[0],parseInt(dateElements[1],10)-1,dateElements[2]);
			this.events.push(e);
		}
	}

	this.setYear = function(year) {
		this.year = parseInt(year);
		this.date = new Date(this.year,this.date.getMonth(),this.date.getDate());
		this.baseDate = new Date(this.year,this.month,7);
		this.event = null;
		this.renderCalendar();
	};
	
	this.setMonth = function(month) {
		this.month = parseInt(month);
		this.date = new Date(this.date.getFullYear(),this.month,this.date.getDate());
		this.baseDate = new Date(this.year,this.month,7);
		this.event = null;
		this.renderCalendar();
	};

	this.setDate = function(dateString) {
		this.date = new Date(dateString);
		this.year = this.date.getFullYear();
		this.month = this.date.getMonth();
		this.baseDate = new Date(this.year,this.month,7);
		this.event = null;
		this.renderCalendar();
	};

	this.setType = function(type) {
		this.type = type;
		this.baseDate = new Date(this.year,this.month,7);
		this.event = null;
		this.renderCalendar();
	};

	this.gotoEvent = function(anID) {
		this.event = this.eventWithID(anID);
		this.year = this.event.date.getFullYear();
		this.month = this.event.date.getMonth();
		this.showDate(this.event.date);
	};

	this.showDate = function(aDate) {
		this.date = aDate;
		this.baseDate = new Date(this.date.getFullYear(),this.date.getMonth(),7);
		this.renderCalendar();
	};

	this.idForEvent = function(anEvent) {
		if(!this.autoID) {
			this.autoID = 0;
		}
		if(!anEvent.id) {
			this.autoID += 1;
			anEvent.id = this.autoID;
		}
		return anEvent.id;
	};

	this.eventWithID = function(anID) {
		for(i=0;i<this.events.length; i++) {
			if(this.idForEvent(this.events[i]) == anID) {
				return this.events[i];
			}
		}
	};

	this.eventsForDate = function(aDate) {
		//answer the event for a given day, filtered by the current type
		var events = [];
		for(i=0;i<this.events.length; i++) {
			if(this.events[i] && this.events[i].date.toDateString() == aDate.toDateString()) {
				if(this.type == this.allEventsName || this.events[i].eventType == this.type) {
					events.push(this.events[i]);
				}
			}
		}
		return events;
	};

	this.eventsForType = function(aType) {
		if(aType == this.allEventsName) {
			return this.events;
		}
		var events = [];
		for(i=0;i<this.events.length; i++) {
			if(this.events[i].eventType == aType) {
				events.push(this.events[i]);
			}
		}
		return events;
	};
	
	this.sortedAndFilteredEvents = function() {
		//return an array of events filtered by the type and sorted by their dates
		if(!this.eventsSorted) {
			this.events.sort(function(a,b){return a.date > b.date});
			this.eventsSorted = true;
		}
		return this.eventsForType(this.type);
	}
	
	this.uniqueEventTypes = function() {
		var types = [];
		for(i=0;i<this.events.length; i++) {
			if(this.events[i] && !types.contains(this.events[i].eventType)) {
				types.push(this.events[i].eventType);
			}
		}
		return types;
	};
	
	this.typePlural = function(type) {
		if(type == 'MCCA Dinner') {return 'MCCA Dinners'};
		if(type == 'MCCA Group') {return 'MCCA Groups'};
		if(type == 'MCCA Event') {return 'MCCA Events'};
		return type;
	};

	this.hasEventForYear = function(aYear) {
		var e = this.sortedAndFilteredEvents();
		for(i=0;i<e.length; i++) {
			if(e[i] && e[i].date.getFullYear() == parseInt(aYear)) {
				return true;
			}
		}
		return false;
	};

	this.hasEventForMonth = function(aMonth, aYear) {
		var e = this.sortedAndFilteredEvents();
		for(i=0;i<e.length; i++) {
			if(e[i] && e[i].date.getFullYear() == parseInt(aYear) && e[i].date.getMonth() == parseInt(aMonth)) {
				return true;
			}
		}
		return false;
	};

	this.nextEvent = function(aDate) {
		//answer the next event after the current event or after aDate if there is no current event
		var sortedAndFilteredEvents = this.sortedAndFilteredEvents();
		if(this.event) {
			var index = sortedAndFilteredEvents.indexOf(this.event);
			return sortedAndFilteredEvents[index+1];
		} else {
			for(i=0;i<sortedAndFilteredEvents.length; i++) {
				if(sortedAndFilteredEvents[i] && sortedAndFilteredEvents[i].date > aDate) {
					return sortedAndFilteredEvents[i];
				}
			}
		}
	};

	this.previousEvent = function(aDate) {
		//answer the previous event before the current event or before aDate if there is no current event
		var sortedAndFilteredEvents = this.sortedAndFilteredEvents();
		if(this.event) {
			var index = sortedAndFilteredEvents.indexOf(this.event);
			return sortedAndFilteredEvents[index-1];
		} else {
			for(var i=sortedAndFilteredEvents.length-1; i>=0; i--) {
				if(sortedAndFilteredEvents[i] && sortedAndFilteredEvents[i].date < aDate) {
					return sortedAndFilteredEvents[i];
				}
			}
		}
	};

	this.render = function(containerID){
		this.container = document.getElementById(containerID);
		if(this.container) {
			this.container.width=this.width;
			this.container.height=this.height;
			this.container.setAttribute("class", "calendar");
			this.container.setAttribute("className", "calendar"); //for IE
			this.renderCalendar();
		} else {
			alert('SICalendar could not find container: '+containerID);
		}
	};

	this.renderCalendar = function() {
		//first adjust any type aliases (plurals, case, etc.)
		var type = this.type.toLowerCase();
		if(type == 'training' || type == 'mccatraining' || type == 'mcca training') {this.type = 'Training'}
		if(type == 'mccadinner' || type == 'mcca dinner' || type == 'mccadinners' || type == 'mcca dinners' || type == 'dinner' || type == 'dinners') {this.type = 'MCCA Dinner'}
		if(type == 'mccagroup' || type == 'mcca group' || type == 'mccagroups' || type == 'mcca groups' || type == 'group' || type == 'groups') {this.type = 'MCCA Group'}
		if(type == 'mccaevent' || type == 'mcca event' || type == 'mccaevents' || type == 'mcca events' || type == 'event' || type == 'events' || type == 'other') {this.type = 'MCCA Event'}
		if(type == '') {this.type = this.allEventsName}
		var dateCursor = this.baseDate;
		dateCursor.setDate(dateCursor.getDate()-6-(dateCursor.getDay()||7)); //previous Monday
		//build months select box
		var monthSelect = '<select class="monthSelect" size="1" name="month" onChange="javascript:calendar.setMonth(this.value)">';
		var monthSelected = '';
		for(m=0;m<12; m++) {
			if(m == this.month) {
				monthSelected = ' selected';
			} else {
				monthSelected = '';
			}
			if(this.hasEventForMonth(m,this.year)) {
				var monthClass = 'monthWithEvents';
			} else {
				var monthClass = 'monthWithoutEvents';
			}
			monthSelect+='<option'+monthSelected+' value="'+m+'" class="'+monthClass+'">'+this.monthNames[m]+'</option>';
		}
		monthSelect+='</select>';
		//build types select box
		var typeSelect = '<select class="typeSelect" size="1" name="type" onChange="javascript:calendar.setType(this.value)">';
		if(this.type == this.allEventsName) {
			typeSelect+='<option selected value="'+this.allEventsName+'">'+this.allEventsName+'</option>';
		} else {
			typeSelect+='<option value="'+this.allEventsName+'">'+this.allEventsName+'</option>';
		}
		var eventTypes = this.uniqueEventTypes();
		for (t=0;t<eventTypes.length;t++)  {
			if(eventTypes[t] == this.type) {
				typeSelected = ' selected';
			} else {
				typeSelected = '';
			}
			typeSelect+='<option '+typeSelected+' value="'+eventTypes[t]+'">'+this.typePlural(eventTypes[t])+'</option>';
		}
		typeSelect+='</select>';
		
		//build year select box
		var yearSelect = '<select class="yearSelect" size="1" name="year" onChange="javascript:calendar.setYear(this.value)">';
		for (y=this.year-this.yearRange;y<this.year+this.yearRange;y++)  {
			if(y == this.year) {
				yearSelected = ' selected';
			} else {
				yearSelected = '';
			}
			if(this.hasEventForYear(y)) {
				var yearClass = 'yearWithEvents';
			} else {
				var yearClass = 'yearWithoutEvents';
			}
			yearSelect+='<option '+yearSelected+' value="'+y+'" class="'+yearClass+'">'+y+'</option>';
		}
		yearSelect+='</select>';
		
		//build calendar table
		var h = Math.round(this.height / 5);
		var w = Math.round(this.width / 7);
		var html = '<table border="0" width="'+this.width+'" height="'+this.height+'"><tr>';
		//next Event
		var nextEvent = this.nextEvent(this.date);
		if(nextEvent) {
			var id = this.idForEvent(nextEvent);
			var nextHtml = '<a class="nextEvent" title="Show Next Event ('+nextEvent.date.toDateString()+')" href="javascript:calendar.gotoEvent('+id+')">'+nextEvent.title+' &gt;</a>';
		} else {
			var nextHtml = '';
		}
		//previous Event
		var previousEvent = this.previousEvent(this.date);
		if(previousEvent) {
			var id = this.idForEvent(previousEvent);
			var previousHtml = '<a class="previousEvent"  title="Show Previous Event ('+previousEvent.date.toDateString()+')" href="javascript:calendar.gotoEvent('+id+')">&lt;'+previousEvent.title+'</a>';
		} else {
			var previousHtml = '';
		}
		//title line
		html+='<th colspan="2">'+previousHtml+'</th><th colspan="3" class="monthyear">'+typeSelect+'&nbsp;in&nbsp;'+monthSelect+'&nbsp;'+yearSelect+'</th><th colspan="2">'+nextHtml+'</th></tr><tr>';
		//day headings
		for(d=0;d<this.dayNames.length; d++) {
			html+='<th>'+this.dayNames[d]+'</ht>';
		}
		html+='</tr>';
		//calendar cells
		for (week=0;week<6; week++) {
			//weeks (rows)
			html+='<tr>';
			for (day=0;day<7; day++) {
				//days (cells)
				var cellHTML = '<ul class="events" style="height:'+h+'px;width:'+(w-18)+'px;overflow:auto">';
				//build events for this day
				var eventsForDay = this.eventsForDate(dateCursor);
				for(e=0;e<eventsForDay.length; e++) {
					if(eventsForDay[e] == this.event) {
						var eventClass = 'selectedEvent';
					} else {
						var eventClass = 'event';
					}
					cellHTML+='<li id="event_'+this.idForEvent(eventsForDay[e])+'" class="'+eventClass+'"><a href="'+eventsForDay[e].link+'" title="'+eventsForDay[e].title+' ('+eventsForDay[e].eventType+')">'+eventsForDay[e].title+'</a></li>';
				}
				cellHTML+='</ul>';
				//set class by type of day
				if(dateCursor.getMonth() == this.month) {
					dayClass = 'day';
				} else {
					dayClass = 'dayOutside';
				}
				if(dateCursor.toDateString() == this.date.toDateString()) {
					dayClass = 'currentDate';
				}
				html+='<td class="'+dayClass+'" width="'+w+'" height="'+h+'" valign="top" onClick="javascript:calendar.setDate(\''+dateCursor.toDateString()+'\')"><span class="date">'+dateCursor.getDate()+'</span>'+cellHTML+'</td>';
				dateCursor.setDate(dateCursor.getDate()+1);
			}
			html+='</tr>';
		}
		html+='</table>';
		if(this.container) {
			this.container.innerHTML = html;
		}
	};

}
