var kamViewDay;
var spinner;

var kamDay = new Class({	
	Implements: [Events],
	
	// Date object for this day (Defaults to today)
	date: null,
	
	// This day as an object
	dateObj: null,
	
	// This day as a uk string shorthand
	dateString: null,
	
	// Timestamp for this day
	time: null,
	
	// Event indexes taken on this day
	indexsTakenArr: [],
	
	// Dom elements used to construct this day 
	elements: {
		container: null,
		head: null,
		content: null
	},
	
	modalInstance: null,
	
	dayLabels: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'],
	monthLabels: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
	
	// Array of all the events associated with this day
	events: [],
	
	initialize: function(date) {		
		
		//if date is not passed through options set to todays date
		(!date) ? this.date = new Date() : this.date = new Date(date);
		
		//set timestamp 
		this.time = this.date.getTime();
		
		//create a date object
		this.dateObj = this.dateAsObject(this.date);
		
		//create day string xx/xx/xxxx
		this.dateString = this.dateObj.day + '/' + (parseInt(this.dateObj.month) + 1) + '/' + this.dateObj.year;
		
		this.__setDisplayElements();
		
		this.__clickHandler();
	},
	
	// Displays all events associated with the day clicked
	__clickHandler: function(){
				
		this.elements.container.addEvent('click', function(e){	
				
			if(!e.target.hasClass('shortDate')){																
				if(this.events.length > 0){									
					
					var displayEvents = function(){
						var eventInstance = new Element('table',{
							'class': 'kamViewEvent',
							'width': '860',
							'cellpadding': '0',
							'cellspacing':'0'
						});
						
						// 20111202 - attending removed (initials moved to the left of the event)
//						var headers = ["Title","Start date","End date","Attending"];
						var headers = ["Title","Start date","End date"];
						headers.each( function(header,index){
							headers[index] = new Element('th',{ "html": header });
						});
						eventInstance.adopt(headers);
						
						// Find all events associated with this day and build definition 
						var rows = []
						Array.each(this.events, function(dayEvent,index){																						
							
							// create the row and add a click handler
							rows[index] = new Element('tr',{
								styles:{
									color: dayEvent.colourCode
								},
  								events: {
									click: function(e){
										e.preventDefault();
										new kamAjaxContentModal('/diary/edit-entry/?entry=' + dayEvent.id + '&fromCalendar=true', { 
											disablePageScrolling: false,
											title: 'Edit diary entry',
											resizeToContent: true,
											id: 'editDiaryEntry',
											onContentSet: function(element){																	
												initUi(element);												
												datepickers();	
												addDiary();
											}.bind(this)
										}).show();
									}.bind(this)
								}
							});
							
							// create the cells
							var cells = [];
							cells[0] = new Element('td',{ 'html' : (dayEvent.appliesToAll ? 'All' : dayEvent.combinedInitials)+' '+dayEvent.titleWithoutInitials })
							
							
//							var startDateObj = this.dateAsObject(new Date(dayEvent.startDate));
//							cells[1] = new Element('td',{						
//								'html' : startDateObj.day+'/'+(parseInt(this.dateObj.month) + 1)+'/'+startDateObj.year,
//								'width': '80'
//							});
							cells[1] = new Element('td',{						
								'html' : dayEvent.rangeStart,
								'width': '100'
							});

							cells[2] = new Element('td',{						
								'html' : dayEvent.diffEndDate == 'true' ? dayEvent.rangeEnd : '',
								'width': '100'
							});
							
//							
//							var endDateObj = this.dateAsObject(new Date(dayEvent.endDate));
//							cells[2] = new Element('td',{						
//								'html' : endDateObj.day + '/' + (parseInt(this.dateObj.month) + 1) + '/' + endDateObj.year,
//								'width': '80'
//							});
							
							// 20111202 - disabled (initials moved to the left of the event)
//							cells[3] = new Element('td',{						
//								'html' : dayEvent.appliesToAll ? 'All' : dayEvent.combinedInitials,
//								'width': '130',
//								'class': 'last'
//							});
							rows[index].adopt(cells);
							
						}.bind(this));

						eventInstance.adopt(rows);
								
						this.modalInstance = new kamModal({
							id: 'viewEntries',
							title:  this.dateString,
							content: eventInstance,
							disablePageScrolling: false
						}).show();
												
					}.bind(this);
					
					displayEvents();
				}
			}else{				
				this.fireEvent('addEntry',this.dateObj.year + '-' + (parseInt(this.dateObj.month) + 1) + '-' + this.dateObj.day);		
			}
		}.bind(this));
	},
	
	// Setup the display elements for the day
	__setDisplayElements: function(){
		this.elements.container = new Element('div', {
			'class': 'kamDayContainer ' + this.dayLabels[this.dateObj.dayOfWeek]
		});

		this.elements.head = new Element('div', {'class': 'kamDayHead' });
		this.elements.content = new Element('div', {
			'class': 'kamDayContent',
			'html': '&#160;'
		});
		this.elements.clear = new Element('div', {
			'class': 'clear', 
			html: '&#160;',
			styles :{ 
				clear: 'both', 
				float: 'none' 
			}
		});

		var dowEl = new Element('div',{'class':'dow', 'html': this.dayLabels[this.dateObj.dayOfWeek]	});
		var shortDateEl = new Element('div',{'class':'shortDate'	});		
		
		shortDateEl.grab(new Element('span',{'class' : 'shortDateDay',	'html': this.dateObj.day }));		
		shortDateEl.grab(new Element('span',{'class' : 'shortDateMonth', 'html': '/' + (parseInt(this.dateObj.month) + 1)	}));		
		shortDateEl.grab(new Element('span',{'class' : 'shortDateYear',	'html': '/' + this.dateObj.year }));
						
		this.elements.head.grab(dowEl); this.elements.head.grab(shortDateEl);
		this.elements.container.adopt(this.elements.head, this.elements.content, this.elements.clear);
	},
	
	// Accepts a date and returns it as an object
	dateAsObject: function(date){
		return {
			year: date.getFullYear(),
			month: date.getMonth(),
			day: date.getDate(),
			hours: date.getHours(),
			minutes: date.getMinutes(),
			seconds: date.getSeconds(),
			dayOfWeek : date.getDay()
		};
	},
	
	// Accepts a date object and returns it as a Date()
	objectAsDate: function(values) {
		var date = new Date();
		date.setDate(1);
		['year', 'month', 'day', 'hours', 'minutes'].each(function(type) {
			var v = values[type];
			if (!$chk(v)) return;
			switch (type) {
				case 'day': date.setDate(v); break;
				case 'month': date.setMonth(v); break;
				case 'year': date.setFullYear(v); break;
				case 'hours': date.setHours(v); break;
				case 'minutes': date.setMinutes(v); break;
			}
		});
		return date;
	}
	
});

var kamWeek = new Class({
	
	// Start of the week date
	startDate: null,
	
	// End of the week date
	endDate: null,
	
	// Array of day classes in the week
	days: [],
	
	// Container for week elements
	container: null,

	initialize: function(date){
		// set the startDate (First day of the week
		(date) ? this.__setStartDate(new Date(date)) : this.__setStartDate(new Date());
		
		this.__buildWeek();
	},
	
	//  Set the first day of the week
	__setStartDate: function(date){
		var day = date.getDay();		
      	var first = date.getDate() - day + (day == 0 ? -6:1); // adjust when day is sunday		
	  	this.startDate = new Date(date.setDate(first));
	},
	
	// Build a week from the startDate
	__buildWeek: function(){
		if(this.startDate){
			this.container = new Element('div', {'class': 'kamWeekContainer' });
			for(var i = 0; i < 7; i++){
				this.days[i] = new kamDay(this.startDate.getTime() + (i * 86400000));;			
				this.container.grab(this.days[i].elements.container);								
			}		
			this.endDate = this.days[6].date;	
		}						
	}
	
});

var kamMonth = new Class({
	// Start of the month date (display)
	startDate: null,
	
	// The first date in view
	viewStartDate: null,
	
	// end of the month date (display)
	endDate: null,
	
	// Weeks in month
	weeks: [],
	
	// Container for month elements
	container: null,
	
	initialize: function(date){		
		// set the startDate to the first day of the month
		(date) ? this.startDate = new Date(date) : this.startDate = new Date();				
		this.startDate.setDate(1);
	
		this.__buildMonth();	
	},
	
	// Build a calendar month of 6 weeks
	__buildMonth: function(){
		this.container = new Element('div', {'class': 'kamMonthContainer'});
		for(var i = 0; i < 6; i++){
			var newWeek = new Date(this.startDate);
			
			this.weeks[i] = new kamWeek(newWeek.setDate(this.startDate.getDate() + (i * 7)));	
			this.container.grab(this.weeks[i].container);
		}
		this.endDate = this.weeks[5].endDate;	
		this.viewStartDate = this.weeks[0].startDate;		
	}	
	
});

var kamEventsHandler = new Class({
	Implements: [Events],
	// json string
	json: null,
	
	// day class to use functions
	dayFunctions: null,
	
	// events sorted by start times
	sortedEvents: [],
	
	initialize: function(json){
		this.dayFunctions = new kamDay();				
	},
		
	getJson: function(filters){	
		
		// request data
		//alert('/diary/?json=true&startDate='+ filters.firstDay.toISOString() + '&endDate=' + filters.lastDay.toISOString() + '&diary=' + filters.diary + '&office=' + filters.office);
		var request = new Request.JSON({
			url : '/diary/?json=true&startDate='+ filters.firstDay.toISOString() + '&endDate=' + filters.lastDay.toISOString() + '&diary=' + filters.diary + '&office=' + filters.office,			
			onSuccess: function(json){	
				this.json = json; 	
			//	alert(json.events.length);		
				this.sortEvents();
			//	alert("Json request finished: " + (new Date() - timeStart) );
			}.bind(this),
			onError: function(text, error){
				alert(error);	
			}
		}).get();		
	},
	
	sortEvents: function(){
		var startTimeArr = [];	
		this.sortedEvents =[];
		this.json.events.each( function(calendarEvent,key){
			var startTime = new Date().parse(calendarEvent.startDate).getTime();																						
			//build array of unique start times
			if(!startTimeArr.contains(startTime)) startTimeArr[startTimeArr.length] = startTime;
			
			calendarEvent.startDate = new Date().parse(calendarEvent.startDate);
			calendarEvent.endDate = new Date().parse(calendarEvent.endDate);
		});
		
		//sort the start times
		var sortNumber = function(a,b){ return a - b; }
		startTimeArr.sort(sortNumber);
								
		//build array in order of the events start times		
		for(var i=0, end = startTimeArr.length; i < end; i++){			
			var tempArr = [];
			this.json.events.each( function(calendarEvent,key){																
				if(new Date().parse(calendarEvent.startDate).getTime() == startTimeArr[i]){					
					//create a temp array of all the events that start on this day so that they can be sorted by length before
					//being added to the primary sorted array
					tempArr.push(calendarEvent);												 					
				}
			}.bind(this));			
			
			//sort the temp array by length of the events and add it to the primary sorted array
			if(tempArr.length > 0){
				//sort
				var sortedLengthArr = [];
				// loop through each item in the temp array				
				for(var x=0, endx=tempArr.length; x<endx; x++){
					// if the sorted array is empty then just put this item in as the first index
					if(sortedLengthArr.length == 0){
						sortedLengthArr.push(tempArr[x]);
					}else{ 
						//var endTime = new Date().parse(tempArr[x].endDate).getTime();
						var eventLength = new Date().parse(tempArr[x].endDate).getTime() - new Date().parse(tempArr[x].startDate).getTime();
						for(var y=0, endy=sortedLengthArr.length; y<endy; y++){
							//if(endTime >  (new Date().parse(sortedLengthArr[y].endDate).getTime() )){
							if(eventLength >= (new Date().parse(sortedLengthArr[y].endDate).getTime() - new Date().parse(sortedLengthArr[y].startDate).getTime() )){
								sortedLengthArr.unshift(tempArr[x]);
								y = endy;	
							}
						}
					}
				}
			}
			
			// add the length sorted arr to the sorted events array  - now all events should be sorted by start date and length
			sortedLengthArr.each( function(evt){
				this.sortedEvents.push(evt);
			}.bind(this));
		}
		this.fireEvent('sortComplete');
	},
	
	addSortedCustomEvents: function(days){		
		
		var eventIndex = 0; var eventIndexArr = []; var weekDay = 0;
		// loop through each event at a time.
		Array.each(this.sortedEvents, function(sortedEvent,key){		
			//eventIndex = 0; 
			var startDate = new Date(sortedEvent.startDate).setHours(0,0,0,0);
			var endDate = new Date(sortedEvent.endDate).setHours(0,0,0,0);						
			var eventClash = false;
			
			eventIndexArr = [];
			// find if events clash and set their level by loop through all the days and match the days date to within the event date
			Array.each(days, function(day, key){																  	
				var dayDate = new Date(day.date).setHours(0,0,0,0);																	
				var firstDay = new Date(days[0].date).setHours(0,0,0,0);			
				//if this current event does take place on this current day			
				
				if(startDate <= dayDate){
					if(endDate >= dayDate){				
				
						//if this is the first day when the event starts or if the event started on the month previousd						
						if(startDate == dayDate || startDate < firstDay  || (day.dateObj.dayOfWeek == 1 && startDate < dayDate)){
							var dayFull = true;
							//find out which indexs are taken on the start day
							for(var i=0; i < day.indexsTakenArr.length; i++){
								if(!day.indexsTakenArr[i]){
									if(i > eventIndex) eventIndex = i;										
									i = day.indexsTakenArr.length;
									dayFull = false;
								}
							}
							if(dayFull) eventIndex = day.indexsTakenArr.length;
						}
						day.indexsTakenArr[eventIndex] = true;
						day.events.push(sortedEvent);
					}										
				}				
				weekDay++;			
				//if end of a week reset
				if(weekDay == 7){
					 eventIndexArr[eventIndexArr.length] = eventIndex;
					 eventIndex = weekDay = 0; 
				}
			}.bind(this));
			
			var weekIndex = 0;		
			
			//add the events at the correct level			
			Array.each(days, function(day, key){
				var dayDate = new Date(day.date).setHours(0,0,0,0);				
						
				//if a event date falls within the current day of the month				
				if(startDate <= dayDate){
					if(endDate >= dayDate){	
					//	if(startDate == dayDate) 
						var className = 'hasEvent';
						
						//add class depending on the what part of the event the day represents 
						if(dayDate == startDate && dayDate != endDate){ 
							className+= ' first'; 
						}else if(dayDate == endDate && dayDate != startDate){ 
							className+=' last'; 
						}else if(dayDate != endDate && dayDate != startDate){
							className+= ' mid';
						}
				
						//add private class to event
						

						// 20 Jul 2011 - JS : Disabled respect for the "isPrivate" flag in leiu of 
						// changing the text colours

//						if(sortedEvent.isPrivate) className+=' private';
						var eventHolders = day.elements.content.getElements('.kamEvent');			
						if(eventIndexArr[weekIndex] < eventHolders.length){
							var title = '';
							if(sortedEvent.title.length > 18){
								title = sortedEvent.title.substring(0,18) + '...';
							}else{
								title = sortedEvent.title;	
							}
							
							eventHolders[eventIndexArr[weekIndex]].grab(new Element('div', { 'class': 'kamEventInner', 
								html : title,
								styles:{
									'background-color': sortedEvent.colourCode
								}
							}));							
							eventHolders[eventIndexArr[weekIndex]].addClass(className);
						}else{
							day.elements.content.getElement('.kamMoreEvents').addClass('hasEvent').grab(new Element('div', { 'class': 'kamEventInner', 'html' : 'Click to view more events'}));	
						}
					}					
				}
				
				weekDay++;			
				//if end of a week reset
				if(weekDay == 7){
					weekDay = 0;
					weekIndex++;	
				}
			}.bind(this));

		}.bind(this));
		
	},
	
	//adds custom events to a week unordered 
	addCustomEvents: function(days){
		this.json.events.each( function(calendarEvent,key){
			var startDate = new Date(calendarEvent.startDate).setHours(0,0,0,0);
			var endDate = new Date(calendarEvent.endDate).setHours(0,0,0,0);
			for(var i=0, end = days.length; i < end; i++){								
				var dayDate = new Date(days[i].date).setHours(0,0,0,0);

				//if a event date falls within the current day of the month
				if(startDate <= dayDate){
					if(endDate >= dayDate){
						var eventDiv = new Element('div', { 							
							'class' : 'kamEvent'
						});		

						// 20 Jul 2011 - JS : Disabled respect for the "isPrivate" flag in leiu of
						// changing the text colours

//						if(calendarEvent.isPrivate == true) eventDiv.addClass('private');
//						var content = calendarEvent.titleWithoutInitials+"<span class='initials'>"+(calendarEvent.appliesToAll ? 'All': calendarEvent.combinedInitials)+"</span>";
						
						var initials = calendarEvent.appliesToAll ? 'All': calendarEvent.combinedInitials;
						var content = initials + ' ' + calendarEvent.titleWithoutInitials;
						
						var fullStartDate = new Date(calendarEvent.startDate);
						var fullEndDate = new Date(calendarEvent.endDate);
						if ( fullStartDate > dayDate){
							switch ( fullStartDate.get('gmtoffset') ){
								case '+0100':
									fullStartDate.decrement('hour', 1);
									fullEndDate.decrement('hour', 1);
									break;
								case '-0100':
									fullStartDate.increment('hour', 1);
									fullEndDate.increment('hour', 1);
									break;
							}
						
							if ( fullStartDate.format('%H%M').toInt() > 0 ){
								if ( calendarEvent.diffEndDate == 'true' ){
									content = fullStartDate.format('%H:%M') + ' - ' + fullEndDate.format('%H:%M') + ' ' + initials + ' ' + calendarEvent.titleWithoutInitials;	
								} else {
									content = fullStartDate.format('%H:%M') + ' ' + initials + ' ' + calendarEvent.titleWithoutInitials;
								}								
							} 
						}

						eventDiv.grab(new Element('p', {
							html : content,
							styles:{
								color: calendarEvent.colourCode
							}
						}));
						
//						eventDiv.grab(new Element('p', {
//							html : calendarEvent.titleWithoutInitials+"<span class='initials'>"+(calendarEvent.appliesToAll ? 'All': calendarEvent.combinedInitials)+"</span>",
//							styles:{
//								color: calendarEvent.colourCode
//							}
//						}));
																	
						eventDiv.addEvent('click', function(e){				
							new kamAjaxContentModal('/diary/edit-entry/?entry=' + calendarEvent.id + '&fromCalendar=true', {
								resizeToContent: true,
								title: 'Edit diary entry',
								onClose : function(){
									this.fireEvent('eventChange');
								}.bind(this),
								onContentSet: function(element){																	
									initUi(element);												
									datepickers();	
									addDiary();
								}.bind(this),
								id: 'editDiaryEntry'
							}).show();
						});					
						
						var uri = new URI(window.location);						
						uri.setData({'deleteEntry' : 'true', 'entry' : calendarEvent.id },true);
						
						var deleteLink = new Element('a',{
							'html' : 'delete',
							'href' : uri,
							'class': 'delete',
							events: {
								click: function(e){
									e.preventDefault();
									var msg='Are you sure you wish to delete this event?';  
    								if(confirm(msg)){  
										new Request.HTML({
											method: 'get',
											url: uri,
											evalScripts: false,
											onComplete: function(){ //refresh 
												this.fireEvent('refresh');										
											}.bind(this)
										}).send();									
									}
								}.bind(this)
							}
						});
						//eventDiv.grab(editLink);
						eventDiv.grab(deleteLink);
					 	days[i].elements.content.grab(eventDiv);					
						days[i].elements.content.grab(new Element('div', {
							'class' : 'clear',
							html: '&#160;'
						}));
					}
				}																	
			}							
		}.bind(this));			
	}
});
	
var kamCalendarWeekView = new Class({
	Implements: [Options,Events],
	
	// Div element that the calendar should be injected into
	element: null,
	
	// Slider element
	slider: null,
	
	// Todays date
	today: new Date(),
	
	//  All weeks in view and either side
	weeks: [],
	
	// slider moprh
	sliderFx: null,
	
	// slider offset
	offSet: 0,
	
	//last direction the slider moved
	lastSlide: false,
	
	// Adds events to days that are currently shown
	eventHandler: null,
	
	// filters	
	filters: {
		firstDay: null,	
		lastDay: null,
		office: ' ',
		diary: 'myDiary'
	},
	
	options:{
		startDay: 1,
		weeksInView:4,
		json: null
	},
	
	newWeek: null,
	
	// A flag for first load 
	firstLoad: true,
	
	// If animations are on this is the number of weeks that should be rendered either side for the slider to work
	bufferWeeks: 2,
	
	currentDate: null,
	
	initialize: function(element, options, date){
		this.element = document.id(element);
		if(this.element){
			this.setOptions(options);				
			this.__setDisplayElements();
			
			// 30 Jun 2011 - JS : Changed to accept the "date" parameter as the starting date of the 
			// calendar
			
			// Get as many weeks as should be displayed and 2 weeks before and after if animations are on (bufferweeks) else just the weeks in view			
			if(!kamUi.useAnimations) this.bufferWeeks = 0;
			if ( date ) date = date.toString().split('-');
			
			if ( date ){
				this.currentDate = new Date(date[2].toInt(), date[1].toInt() - 1, date[0].toInt());
			} else {
				this.currentDate = new Date();
			}	
			
			for(var i = - this.bufferWeeks, end = this.options.weeksInView + this.bufferWeeks; i < end; i++){	
				if ( date ){
					var weekDate = new Date(date[2].toInt(), date[1].toInt() - 1, date[0].toInt());
				} else {
					var weekDate = new Date();
				}
				this.weeks[i+this.bufferWeeks] = new kamWeek(weekDate.setDate(weekDate.getDate() + (i * 7)));								
			}			
			
			//set Events
			this.eventHandler = new kamEventsHandler();					
						
			this.eventHandler.addEvent('sortComplete', function(){ 																				
				// Loads all the first weeks in 
				Array.each(this.weeks, function(week){ this.__addEvents(week);	}.bind(this));										
				this.__displaySize();
				
				// Reset the slider if animations are on
				if(kamUi.useAnimations) this.__sliderReset();
			}.bind(this));	
			
			this.filters.firstDay = this.weeks[0].days[0].date;
			this.filters.lastDay = this.weeks[this.weeks.length-1].days[this.weeks[this.weeks.length-1].days.length-1].date
			
			// 30 Jun 2011 - JS : Diabled the automatic loading of data in order for the persistent 
			// filter options to apply. You must now call the "filter" method when creating an instance
			
			//this.eventHandler.getJson(this.filters);

			Array.each(this.weeks, function(week){ 
				week.container.inject(this.slider); 										  
			}.bind(this));
			
			this.eventHandler.addEvent('refresh', function(){
																		  
				this.__clearEvents();			
				this.firstLoad = true;										  
				this.eventHandler.getJson(this.filters);				
			}.bind(this));
		
		}else{
			Alert('Kam error');	
		}
	},
	
	__setDisplayElements: function(){
		this.slider = new Element('div', {'class' : 'kamCalendarSlider' });							
		this.element.grab(this.slider);		
		
		this.sliderFx = new Fx.Morph(this.slider, {
			duration : 1000,
			onComplete: function(){ this.__updateCalendar() }.bind(this)	
		});
		this.element.setStyle('overflow','hidden');		
	},

	// Updates the size on the container based on the weeks in the view 
	__displaySize: function(){
		var delayResize = function(){
			var viewAreaSize = 0;
			for(var i = this.bufferWeeks, end = this.options.weeksInView + this.bufferWeeks; i < end; i++) viewAreaSize += this.weeks[i].container.getSize().y

			if ( kamUi.useAnimations ){
				new Fx.Morph(this.element, {
					link:'ignore'
				}).start({'height':viewAreaSize});
			} else {
				this.element.setStyle('height', viewAreaSize);
			}
		}.bind(this);
		var today = new Date();
		this.weeks.each( function(week){
			week.days.each( function(day){
				// add current day class to today
				if( (day.date.getDate()== today.getDate()) && (day.date.getMonth()== today.getMonth()) && (day.date.getFullYear()== today.getFullYear())){
					day.elements.container.addClass('today');
				}
				
				// set day height
				day.elements.head.setStyle('height', day.elements.content.getSize().y);
				
				// add click event
				day.addEvent('addEntry', function(date){
					this.fireEvent('kamAddEntry',date); 
				}.bind(this));
				
			}.bind(this));
		}.bind(this));		
		
		delayResize.delay(200);
	},
	
	__sliderReset: function(){			
		this.offSet = this.weeks[0].container.getSize().y;
		this.offSet += this.weeks[1].container.getSize().y;		
		this.slider.setStyle('margin-top', -this.offSet + 'px');						
	},
	
	__addEvents: function(week){	
		this.eventHandler.addCustomEvents(week.days);
	},
	
	__updateCalendar: function(){
		var newWeek = null;
		if(this.lastSlide){
			newDate = new Date(this.weeks[this.weeks.length-1].endDate);
			newDate.setDate(newDate.getDate() + 1);	
			this.weeks[0].container.destroy();
			this.weeks.splice(0,1);
			newWeek = new kamWeek(newDate);
			this.weeks.push(newWeek);
			this.slider.grab(newWeek.container);
		}else{
			newDate = new Date(this.weeks[0].startDate);
			newDate.setDate(newDate.getDate() - 2);	
			this.weeks[this.weeks.length-1].container.destroy();
			this.weeks.splice(this.weeks.length-1,1);
			newWeek = new kamWeek(newDate);
			this.weeks.unshift(newWeek);
			this.slider.grab(newWeek.container, 'top');
		}
		this.newWeek = newWeek;
		this.__clearEvents();
		this.filters.firstDay = this.weeks[0].startDate;		
		this.filters.lastDay = this.weeks[this.weeks.length-1].endDate;
		this.eventHandler.getJson(this.filters);
		if(kamUi.useAnimations) this.__sliderReset();
	},
	
	__clearEvents: function(){
		this.weeks.each( function(week){
			week.days.each( function(day){
				day.elements.content.empty();							  
			});
		});	
	},
	
	__scroll: function(direction){
		this.lastSlide= direction;
		if(direction){
			if (kamUi.useAnimations){
				this.offSet += this.weeks[2].container.getSize().y;
				this.sliderFx.start({'marginTop': -this.offSet });			
			} else {
				this.__updateCalendar();
			}
		}else{
			if (kamUi.useAnimations){
				this.offSet -= this.weeks[1].container.getSize().y;
				if ( kamUi.useAnimations )	this.sliderFx.start({'marginTop': -this.offSet });			
			} else {
				this.__updateCalendar();
			}
		}				
//		this.__updateCalendar();
	},
	
	filter: function(diary, office, date){
		this.__clearEvents();			
		this.filters.diary = diary;
		this.filters.office = office;
		
		this.eventHandler.getJson(this.filters);
	},
	
	goto: function(date){

		this.currentDate = date;
		
		this.weeks= [];
		this.slider.empty();
		
		var start = new Date(date).decrement('day',(((kamUi.useAnimations)) ? 14 : 0));
		
		var advanceWeeks;
		(kamUi.useAnimations) ? advanceWeeks = this.bufferWeeks + 2 : advanceWeeks = 0;
		for(var i = 0, end = this.options.weeksInView + advanceWeeks; i < end; i++){
			this.weeks[i] = new kamWeek(start.increment('day',(i>0 ? 7 : 0) ));		
		}
		
		this.filters.firstDay = this.weeks[0].days[0].date;
		this.filters.lastDay = this.weeks[this.weeks.length-1].days[this.weeks[this.weeks.length-1].days.length-1].date
		this.eventHandler.getJson(this.filters);
		Array.each(this.weeks, function(week){ 
			week.container.inject(this.slider);
			//this.__addEvents(week);
		}.bind(this));
		this.__displaySize();
		if(kamUi.useAnimations) this.__sliderReset();	
	},
	
	refresh: function(){
		//this.__clearEvents();

		this.goto(this.currentDate);
	},
	
	next: function(){
		this.__scroll(true);	
	},
	
	previous: function(){
		this.__scroll(false);	
	}
	
});
	
var kamCalendarMonthView = new Class({
	Implements: [Options,Events],
	
	// Div element that the calendar should be injected into
	element: null,
	
	// Slider element
	slider: null,
	
	// slider cells
	sliderElements: [],
	
	// Todays date
	today: new Date(),
		
	// All months in view and either side
	months: [],
	
	// slider moprh
	sliderFx: null,
	
	// stores the size of the cell
	cellsSize: null,
	
	// slider offset
	offSet: 0,
	
	//last direction the slider moved
	lastSlide: false,
	
	// Adds events to days that are currently shown
	eventHandler: null,
	
	//  last direction the slider moprhed to
	direction: true,
	
	// size of a day element
	daySize: 0,
	
	// array of event morphs for all the events on display
	eventMorphs: [],
	
	// if kam animations is true then the view index is 1 as the class will render 3 cells of data
	viewIndex: 0,
	
	//
	resizeFlag: false,
	
	periodical: null,
	
	currentMonth: null,
	
	// filters	
	filters: {
		firstDay: null,	
		lastDay: null,
		office: ' ',
		diary: 'myDiary'
	},
	
	options:{
		startDay: 1,
		weeksInView:1,
		noEventsDisplayed:4
	},
	
	initialize: function(element,options, date){
		this.element = document.id(element);

		if(this.element){
			this.setOptions(options);	
			//kamUi.useAnimations = false;
			if(kamUi.useAnimations) this.viewIndex = 1;
			
			this.__setDisplayElements();
			
			this.eventHandler = new kamEventsHandler();
			
			this.eventHandler.addEvent('sortComplete', function(){ 
				this.__addEvents();
				this.__positionAbsolute(15);			
			}.bind(this));
			
			//create mask
			spinner = new Spinner(this.element,{
				'class' : 'kamModalMask'
			});
									
			// 30 Jun 2011 - JS : Changed to accept the "date" parameter as the starting date of the 
			// calendar
				
			if ( date ){
				date = date.toString().split('-');
				this.today = new Date(date[2].toInt(), date[1].toInt() - 1, date[0].toInt());
			} else {
				this.today = new Date();
			}
														
			// Get  3 months if animations are true
			if(kamUi.useAnimations){
				this.__setMonths(new Date(this.today.getFullYear(), this.today.getMonth() - 1, 1));			
			}else{ //else just get a month			
				this.__setMonths(new Date(this.today.getFullYear(), this.today.getMonth(), 1));
			}
			
			// set cell widths and slider width now days have been added												
			//var daySize = this.months[0].weeks[0].days[0].elements.container.getSize();	
			
			var x = 0; var y = 0;
			for(var i = 0; i < 7; i++){
				var size = this.months[0].weeks[0].days[i].elements.container.getSize();							
				x += size.x; 
				if(i < 6) y += size.y;														
			}

			this.daySize = {	x: x,	y: y	};			
			for(var i = 0; i < 3; i++) this.sliderElements[i].setStyles({ width : this.daySize.x, height : this.daySize.y });					
			
			var cellSize = this.sliderElements[0].getSize();
			this.slider.setStyles({
				width : cellSize.x * 3,
				height : cellSize.y	
			});
			
			this.element.setStyles({
				width : cellSize.x,
				height: cellSize.y,
				overflow: 'hidden'				
			});			

			//set the first and last day of the 3 months
			this.filters.firstDay = this.months[0].weeks[0].days[0].date;
			// Get 3 months worth of data if animations are true else just get 1 month
			(kamUi.useAnimations) ? this.filters.lastDay =  this.months[2].weeks[5].days[this.months[2].weeks[5].days.length-1].date : this.filters.lastDay =  this.months[0].weeks[5].days[this.months[0].weeks[5].days.length-1].date;
			
			// 30 Jun 2011 - JS : Diabled the automatic loading of data in order for the persistent 
			// filter options to apply. You must now call the "filter" method when creating an instance
//			this.eventHandler.getJson(this.filters);
			
			this.cellSize = cellSize;						
			this.__resetSlider();	
			
			
			window.addEvent('resize', function(e){ 					
				if(this.resizeFlag == false){								
					this.resizeFlag = true;
					this.__resized();
					var performResize = function(){
						clearInterval(this.periodical);	
						this.__resized();
						this.__positionAbsolute(0);											
						this.resizeFlag = false;						
					}.bind(this);
					this.periodical = performResize.periodical(500);	
					
				}
			}.bind(this));

		}else{
			Alert('Kam error - conatiner Id cannot be found');	
		}
	},
	
	__resized: function(){
		if(kamUi.useAnimations ){	
			Array.each(this.months[this.viewIndex].weeks, function(week){
				Array.each(week.days, function(day){
					day.elements.content.getElements('.hasEvent').each( function(eventEl){			
						eventEl.setStyles({
							'position':'relative',
							'left':0,
							'top':-15
						});
					});
				});
			});
		}
	},
	
	__setMonths: function(prevMonth){
		// Render 3 cells of months if animations are true else just render the current month
		if( kamUi.useAnimations ){
			for(var i = 0; i < 3; i ++){			
				this.months[i] = new kamMonth(prevMonth);	
				prevMonth.setMonth(prevMonth.getMonth() + 1);		
				if(i == 1 ) this.currentDate = prevMonth;
				this.__renderCell(i,i);	
			}	
		}else{			
			this.months[0] = new kamMonth(prevMonth);
			this.__renderCell(1,0);	
		}
		
		//Put the current month in the currentMonthDisplay div if present
		currentMonthDiv = document.id('currentMonthDisplay');
		if(currentMonthDiv){
			// if the animations are true then the current month index is 1 else its 0

			var month = new Date(this.months[this.viewIndex].startDate);
			month = this.months[this.viewIndex].weeks[0].days[0].dateAsObject(month);
			currentMonthDiv.set('html',this.months[this.viewIndex].weeks[0].days[0].monthLabels[month.month] + ' ' + month.year);	
		}
		
		this.currentMonth = new Date(this.months[this.viewIndex].startDate);
	},
	
	__resetSlider: function(){
		this.slider.setStyle('margin-left', -this.cellSize.x + 'px');	
	},
	
	__setDisplayElements: function(){
		this.slider = new Element('div', {'class' : 'kamCalendarSlider' });		
		
		//build 3 slider cells
		for(var i = 0; i < 3; i ++){
			this.slider.grab(this.sliderElements[i] = new Element('div', {
					'class' : 'kamMonthCell',
					'styles' : {
						'float' : 'left'	
					}
				}
			));
		}
							
		this.element.grab(this.slider);	
			
		this.sliderFx = new Fx.Morph(this.slider, {
			duration : 1000,
			onStart: function(){ 
				if(kamViewDay){
					//destroy the event view if there is on visible
					new Fx.Morph(kamViewDay,{
						onComplete: function(){
							kamViewDay.destroy();	
						}
					}).start({'opacity':0});
				}
			},
			onComplete: function(){ this.__update() }.bind(this)	
		});			
	},
	
	__addEventHolders: function(day){		
		for(var i = 0; i <= this.options.noEventsDisplayed; i++){
			if(i < this.options.noEventsDisplayed){				
				day.elements.content.grab(new Element('div', {'class' : 'kamEvent' }));				
				day.indexsTakenArr.push(false);
			}else{ //used as a css flag to show there is more events present on the day that can be shown
				day.elements.content.grab(new Element('div', {'class' : 'kamMoreEvents' }));	
			}
		}
	},
	
	__renderCell: function(cellIndex, monthIndex){
		//this.sliderElements[cellIndex].empty();		
		this.sliderElements[cellIndex].getChildren().each( function(child){
			child.destroy();																				
		});
		var currentMonth = new Date(this.months[monthIndex].startDate);
		var today = new Date();
		Array.each(this.months[monthIndex].weeks, function(week){
			Array.each(week.days, function(day){	
				day.addEvent('addEntry', function(date){
					this.fireEvent('kamAddEntry',date); 
				}.bind(this));											 
				
				// add events holders based on no of events that should be shown [options]
				this.__addEventHolders(day);
				this.sliderElements[cellIndex].grab(day.elements.container);	
				
				// place a class on the day if it is not part of the current month				
				if(currentMonth.getMonth() != day.date.getMonth()){ 
					day.elements.container.addClass('polarMonth');
				} 
				
				// add current day class to today
				if( (day.date.getDate()== today.getDate()) && (day.date.getMonth()== today.getMonth()) && (day.date.getFullYear()== today.getFullYear())){
					day.elements.container.addClass('today');
				}
				
				// addEvent listeners to the day to see if an event has been deleted
				day.addEvent('refresh', function(){
					this.refresh();
				}.bind(this));
				
			}.bind(this));
		}.bind(this));
	},
	
	__update: function(direction){
		(this.direction) ? this.__setMonths(new Date(this.months[0].startDate.getFullYear(), this.months[0].startDate.getMonth() + 1, 1)) :	this.__setMonths(new Date(this.months[0].startDate.getFullYear(), this.months[0].startDate.getMonth() - 1, 1), direction);
		this.filters.firstDay = this.months[0].weeks[0].days[0].date;
		// Get 3 months worth of data if animations are true else just get 1 month
		(kamUi.useAnimations) ? this.filters.lastDay =  this.months[2].weeks[5].days[this.months[2].weeks[5].days.length-1].date : this.filters.lastDay =  this.months[0].weeks[5].days[this.months[0].weeks[5].days.length-1].date;
		this.eventHandler.getJson(this.filters);
		this.__resetSlider();
	},	
	
	__addEvents: function(){
		var days = [];
		Array.each(this.months[this.viewIndex].weeks, function(week){
			Array.each(week.days, function(day){
				days.push(day);	
			});
		}.bind(this));	
		this.eventHandler.addSortedCustomEvents(days);	
	},		
	
	__positionAbsolute: function(offset){
		//Positions all events absolutely
		if(kamUi.useAnimations ){	
			Array.each(this.months[this.viewIndex].weeks, function(week){
				Array.each(week.days, function(day){
					day.elements.content.getElements('.hasEvent').each( function(eventEl){																				  
						var coords = eventEl.getCoordinates();
	
						var set = function(){
							eventEl.getElement('.kamEventInner').setStyles({ 'display':'block' });
							
							eventEl.setStyles({
								opacity: (kamUi.useAnimations)? 0 : 1,
								position: 'absolute',
								width: eventEl.getParent().getSize().x,
								top: coords.top-offset,
								left: coords.left
							});
							
						}.bind(this);
						set.delay(100);													
						this.eventMorphs.push(new Fx.Morph(eventEl));							
					}.bind(this));
					
				}.bind(this));
			}.bind(this));	
	
			Array.each(this.eventMorphs, function(eventMorph){	
				eventMorph.set({'opacity':0});
				eventMorph.start({'opacity':1});	
			});
		
		}
		// hide mask on load complete
		spinner.hide(!kamUi.useAnimations);
		hideLoadingMask();
	},
	
	goto: function(date){	
		showLoadingMask();
		date = new Date(date);	
		if(kamUi.useAnimations){		
			this.__setMonths(new Date(date.getFullYear(), date.getMonth() - 1, 1));			
		}else{ //else just get a month			
			this.__setMonths(new Date(date.getFullYear(), date.getMonth(), 1));
		}
		this.filters.firstDay = this.months[0].weeks[0].days[0].date;
		(kamUi.useAnimations) ? this.filters.lastDay = this.months[2].weeks[5].days[this.months[2].weeks[5].days.length-1].date : this.filters.lastDay =  this.months[0].weeks[5].days[this.months[0].weeks[5].days.length-1].date;
		this.eventHandler.getJson(this.filters);
	},
	
	filter: function(diary, office){	
		showLoadingMask();	
		if( kamUi.useAnimations ){
			date = new Date(this.months[this.viewIndex].startDate.getFullYear(), this.months[this.viewIndex].startDate.getMonth() - 1, 1);
		}else{
			date = new Date(this.months[this.viewIndex].startDate.getFullYear(), this.months[this.viewIndex].startDate.getMonth(), 1);
		}
		this.__setMonths(date);
		this.filters.diary = diary;
		this.filters.office = office;
		this.eventHandler.getJson(this.filters);
	},
	
	previous: function(){
		this.direction = false;
		if(kamUi.useAnimations){
			if(spinner) spinner.show();			
			Array.each(this.eventMorphs, function(eventMorph){	eventMorph.start({'opacity':0});	});
			
			this.sliderFx.start({'marginLeft':0});
			if(kamViewDay){
				//destroy the event view if there is on visible		
				new Fx.Morph(kamViewDay,{
					onComplete: function(){
						kamViewDay.destroy();	
					}
				}).start({'opacity':0});
			
			}
			this.slider.setStyle('marginLeft', 0);
		}else{
			showLoadingMask();
			this.__update();	
		}
	},
	
	next: function(){
		this.direction = true;
		if(kamUi.useAnimations){
			if(spinner)	spinner.show();			
			Array.each(this.eventMorphs, function(eventMorph){	eventMorph.start({'opacity':0});	});
	
			this.sliderFx.start({'marginLeft': -this.cellSize.x * 2 + 'px'});
			if(kamViewDay){
			//destroy the event view if there is on visible
				new Fx.Morph(kamViewDay,{
					onComplete: function(){
						kamViewDay.destroy();	
					}
				}).start({'opacity':0});

			}
			this.slider.setStyle('marginLeft',  -this.cellSize.x * 2 + 'px');	
		}else{
			showLoadingMask();
			this.__update();	
		}	
	},
	
	refresh: function(){			
		this.goto(this.currentMonth);				
	}
	
});
