var eventObject = Class.create(
/** 
 * @lends eventObject.prototype
 * @example
 * This is an example of the data model expected by the JavaScript
 * 'assetid'=>'12345678900',
 * 'summary'=>'This is the event summary 0',
 * 'description'=>'this 0 is the event description it is a bit longer than the summary',
 * 'category'=>array('category one','category two','category three','category four'),
 * 'start'=>'2010-05-01 08:45:00',
 * 'end'=>'2010-05-01 09:45:00',    // use a full date-time value for "end" so that both recurring and 
 *									   non-recurring events that last for several days may be accomodated, 
 *									   examples:  (recurring) yearly festival, (non-recurring) one-time-only sale
 * 'recurrence'=>'daily',           // once, daily, weekly (by day of week), monthly (by day of week), yearly (by date)
 * 'until'=>'2010-05-10 08:45:00'   // technically optional even for recurring events
 */
 	{
	 /**
	  * @constucts
	  */
	initialize: function(eventData){
		this.selectedDate = Date.today();
	 	this.properties = eventData;
	 	this.properties.visible = true;
	 	
	 	if(typeof this.properties.dtstart!=="undefined"){
	 		this.properties.dtstart = Date.parseExact(this.properties.dtstart,eHA.calendar.dateFormat);
	 	}
	 	if(typeof this.properties.dtend!=="undefined"){
	 		this.properties.dtend = Date.parseExact(this.properties.dtend,eHA.calendar.dateFormat);
	 	}
	 	if(typeof this.properties.rrule!=="undefined" && typeof this.properties.rrule.until!=="undefined"){
	 		this.properties.rrule.until = Date.parseExact(this.properties.rrule.until,eHA.calendar.dateFormat);
	 	}
 	},
 	/**
 	 * returns a string that contains HTML for a view of a single occurrence for this event
 	 * @function
 	 */
 	view: function(currDate){
 		var recurrence = "";
 		if(typeof this.properties.rrule!=="undefined" && typeof this.properties.rrule.freq!=="undefined"){
 			recurrence = this.properties.rrule.freq;
 		}
 		var categoryString = "";
 		$A(this.properties.category).each(function(category){
 			categoryString += "category-"+category.id+" ";
 		});
 		var styleString = "";
 		if(!this.properties.visible){
 			styleString = "style='display:none;'"
 		}
 		// <p class='description'>"+this.properties.description+"</p>
 		var viewString = "<div class='vevent "+recurrence+" "+categoryString+" assetid-"+this.properties.assetid
 			+"' "+styleString+"><h6><a href='"+eHA.calendar.formatURL(this)+"?selected="+currDate+"' class='url summary' title='"
 			+this.properties.description+"'>"+this.properties.summary+"</a></h6></div>";
		var url = eHA.calendar.formatURL(this);
		return {
			'viewString': viewString,
			'url': url
  		  };  
 	},
 	/**
 	 * @function
 	 */
	toggle: function(){
 		if($$(".vevent.assetid-"+this.properties.assetid)[0]){
 			$$(".vevent.assetid-"+this.properties.assetid).invoke("toggle");
 		}
 		// for findEvents
 		if(this.properties.visible){
 			this.properties.visible = false;
 		}else{
 			this.properties.visible = true;
 		}
 	},
 	/**
 	 * sets #properties.visible to true and also uses CSS selector to invoke show
 	 * on all events with this assetid
 	 * @function
 	 */
	show: function(){
 		if($$(".vevent.assetid-"+this.properties.assetid)[0]){
 			$$(".vevent.assetid-"+this.properties.assetid).invoke("show");
 		}
 		// so findEvents won't find it
 		this.properties.visible = true;
 	},
 	/**
 	 * sets #properties.visible to false and also uses CSS selector to invoke hide
 	 * on all events with this assetid
 	 * @function
 	 */
	hide: function(){
 		if($$(".vevent.assetid-"+this.properties.assetid)[0]){
 			$$(".vevent.assetid-"+this.properties.assetid).invoke("hide");
 		}
 		// so findEvents will find it
 		this.properties.visible = false;
 	}
});

var calendarObject = Class.create(
/** 
 * calendarObject contains functions for navigation and population<br />
 * @lends eventObject.prototype
 */
{
 /**
  * 
  * @constructs
  */
	initialize: function(el){
		this.startDateFlag=true;
	 	this.preloader = eHA.calendar.preloader.clone(true);
	 	this.properties = eHA.elementToObjectLiteral(el);
	 	this.loadData(function(){ this.build(); }.bind(this), false);
	 	this.el = $(el);
 	},
 	build: function(){
 		eHA.log.create("beginning to build calendar module",3);
 		try{
 			SWFAddress.setValue(""); // in case user refreshes page on first state of calendar
			this.startDateFlag=false;
 			if(this.el.previous("div.calendarModule")){
 				this.module = {
 						el:this.el.previous("div.calendarModule"),
 						properties: eHA.elementToObjectLiteral(this.el.previous("div.calendarModule"))
 				};
 				this.createForm();
 			}
 			if(typeof this.properties.showDisplayStyleSwitch==="undefined" || this.properties.showDisplayStyleSwitch==="true"){
 				var calendarViewButtons = "<div class='calendarView'><h4>View</h4><ul><li class='month'>"
 					+"<a href=''>by Month</a></li><li class='week'><a href=''>by Week</a></li><li class='day'>"
 					+"<a href=''>by Day</a></li><li class='agenda'><a href=''>as Agenda</a></li></ul></div>";
 				this.el.insert({bottom:calendarViewButtons});
 			}
 			this.waitPanel = new Element("div",{className:"waitPanel",style:"z-index:100;background-color:#fff;"
 				+"display:none;position:absolute;top:0;bottom:0;left:0;right:0;"})
 				.update(this.preloader.hide());
 			this.el.insert({bottom:this.waitPanel});
 			this.assignViewEvents();
 			
 		 	this.monthView.parent = this;
 		 	this.weekView.parent = this;
 		 	this.dayView.parent = this;
 		 	this.agendaView.parent = this;
 			
 			// copy values from object properties
 			if(typeof this.properties.agendaEventLimit!=="undefined"){
 				this.agendaView.eventLimit = parseInt(this.properties.agendaEventLimit,10);
 			}
 			if(typeof this.properties.agendaDaysToSearch!=="undefined"){
 				this.agendaView.daysToSearch = parseInt(this.properties.agendaDaysToSearch,10);
 			}
 			
 			var thisView = this.properties.displayStyle.toLowerCase()+"View";
 			this.viewableDateRange.start = Date.today();
 			
 	 		var offsetFunction = eHA.calendar.offsetFunction(thisView);
 	 		eHA.log.create("calendarModule ("+this.properties.assetid+").");
 			this.viewableDateRange = this[thisView].defineDateRange(Date.today().clone());
 			eHA.log.create("calendarModule ("+this.properties.assetid+").");
 			this.previousDateRange = this[thisView].defineDateRange(Date.today().clone()[offsetFunction](-1));
 			eHA.log.create("calendarModule ("+this.properties.assetid+").");
 			this.nextDateRange = this[thisView].defineDateRange(Date.today().clone()[offsetFunction](1));
 			
 			this.preloadDateRange.start = this.previousDateRange.start.clone();
 			this.preloadDateRange.end = this.nextDateRange.end.clone();
 			
 			this.viewableDateRange.start = Date.today();
 			
 			eHA.log.create("calendarModule ("+this.properties.assetid+"). Setting preload dates to: start="
 					+this.preloadDateRange.start.toString("MMM-dd-yyyy")+" and end="
 					+this.preloadDateRange.end.toString("MMM-dd-yyyy"),eHA.log._DEBUG);
 			
			this.setHash({view:thisView,startdate:this.viewableDateRange.start});
 		}catch(err){
 			eHA.log.create("calendarModule ("+this.properties.assetid+"). build failed! "+err.message,1);
 		}
 	},
 	/*
 	 * traversedDateRange should always be increasing inclusively (that is, there will be no dates
 	 * within the range that have not been checked for events) but must be cleared when AJAX is
 	 * performed
 	 */
 	checkTraversedDates: function(){
 		var needAJAX = false;
 		if(typeof this.traversedDateRange.start!=="undefined" && typeof this.traversedDateRange.end!=="undefined"){
 			if(Date.compare(this.traversedDateRange.start,this.preloadDateRange.start)===1){
 				eHA.log.create("calendarModule ("+this.properties.assetid+"). traversedDateRange.start is greater / later than preload start date",eHA.log._DEBUG);
 				this.traversedDateRange.start = this.preloadDateRange.start.clone();
 				needAJAX = true;
 			}
 			if(Date.compare(this.traversedDateRange.end,this.preloadDateRange.end)===-1){
 				eHA.log.create("calendarModule ("+this.properties.assetid+"). traversedDateRange.end is lesser / earlier than preload end date",eHA.log._DEBUG);
 				this.traversedDateRange.end = this.preloadDateRange.end.clone();
 				needAJAX = true;
 			}
 		}else{
 			eHA.log.create("calendarModule ("+this.properties.assetid+"). traversed date range is undefined, resetting to preload date range",eHA.log._DEBUG);
 			this.traversedDateRange.start = this.preloadDateRange.start.clone();
 			this.traversedDateRange.end = this.preloadDateRange.end.clone();
 			needAJAX = true;
 		}
 		return needAJAX;
 	},
 	/*
 	 * obj properties: view, startdate, queryParams (object)
 	 */
 	readHash: function(obj){
 		try{
 	 		eHA.log.create("calendarModule ("+this.properties.assetid+"). reading hash.  execution number "+this.executions,3);
 	  		var oldFormOptions={};
 	 		if(typeof this.oldFormOptions!=="undefined"){
 	 			oldFormOptions = this.oldFormOptions;
 	 		}
 	 		 
 	 		var thisFormQueryParams = Object.clone(obj.queryParams);
 	 		if(typeof thisFormQueryParams.dtstart!=="undefined"){
 	 			delete thisFormQueryParams.dtstart;
 	 		}
 	 		if(typeof thisFormQueryParams.dtend!=="undefined"){
 	 			delete thisFormQueryParams.dtend;
 	 		}
 	 		
 	 		this.oldFormOptions = Object.clone(thisFormQueryParams);
 	 		
 	 		var buildFunction = function(){
 	 			//this[obj.view+"View"].build(obj.startdate);
 	 			this.buildView(obj.startdate, obj.view+"View");
 	 		}.bind(this);
 	 		
 	 		
 	 		// if queryParams object differs from previous form then ajax is necessary to reload data
 	 		
 	 		if(this.executions!==2){
 	 			if(Object.toQueryString(thisFormQueryParams)!==Object.toQueryString(oldFormOptions)){
 	 				// form options have changed, must throw away data & execute form
 	 				if(typeof this.traversedDateRange!=="undefined"){
 	 					eHA.log.create(this.properties.assetid+": clearing traversedDateRange",2);
 	 					delete this.traversedDateRange;
 	 					this.traversedDateRange = {};
 	 				}
 	 				if(typeof this.events!=="undefined"){
 	 					eHA.log.create(this.properties.assetid+": clearing events",2);
 	 					delete this.events;
 	 					this.events = {};
 	 				}
 	 				
 	 				// populate form with queryParams
 	 				if(typeof this.form!=="undefined"){
 	 					for(option in obj.queryParams){
 	 						if(typeof this.form[option]!=="undefined"){
 	 							this.form[option].setValue(obj.queryParams[option]);
 	 						}
 	 					}
 	 				}
 	 				
 	 				// adding dtstart & dtend to queryParams
 	 				// this is happening outside of hash for security reasons.
 	 				if(typeof this.preloadDateRange.start!=="undefined" && typeof this.preloadDateRange.end!=="undefined"){
 	 					Object.extend(obj.queryParams,{
 	 						dtstart:this.preloadDateRange.start.toString(eHA.calendar.dateFormat),
 	 						dtend:this.preloadDateRange.end.toString(eHA.calendar.dateFormat)
 	 					});
 	 					this.traversedDateRange.start = this.preloadDateRange.start.clone();
 	 					this.traversedDateRange.end = this.preloadDateRange.end.clone();
 	 					
 	 					eHA.log.create("calendarModule ("+this.properties.assetid+"). setting traversed dates",eHA.log._DEBUG);
 	 				}
 	 				
 	 				this.loadData(function(){
 	 					this.clearCalendar(buildFunction);
 	 				}.bind(this), obj.queryParams);
 	 				
 	 			}else{
 	 				if(this.currentView!==obj.view+"View"){
 	 					this.clearCalendar(buildFunction);
 	 				}else{
 	 					buildFunction();
 	 				}
 	 			}
 	 		}
 	 		
 	 		// if there is no form and no navigation, remove hash
 	 		if(this.noHash && this.noHash===true){
 	 			SWFAddress.setValue("");
 	 			eHA.log.create("calendarModule ("+this.properties.assetid+"). clearing hash",3);
 	 		}
 	 		
 		}catch(err){
 			eHA.log.create("calendarModule ("+this.properties.assetid+"). ERROR reading hash! "+err.toString(),1);
 		}
 	},
 	/*
 	 * obj properties: view, startdate
 	 */
 	setHash: function(obj){
		
 		try{
 	 		if((!this.properties.showNavigationLinks || this.properties.showNavigationLinks==="false")
 				&& (!this.properties.showDisplayStyleSwitch || this.properties.showDisplayStyleSwitch==="false")
 				&& (!this.module.el.down("form"))){
 	 			this.noHash = true;
 	 		}else{
 	 			this.noHash = false;
 	 		}
			
 	 		var formOptions = this.form.serialize(true);
 	 		Object.extend(formOptions,{events:'true'});
			
 			if(this.executions===1){ // this function is called once onload, so checking for 1 instead of 0
 	 			// this is the first time the form is being executed, setValue of hash to the default
 	 			// form options.
 	 			eHA.log.create("calendarModule ("+this.properties.assetid+"). setting default form options in hash",eHA.log._DEBUG);
 	 			this.executions++;
 	 			eHA.log.create("calendarModule ("+this.properties.assetid+"). executions set to "+this.executions,eHA.log._DEBUG);
 	 			SWFAddress.setValue("/"+this.properties.assetid+"/"+this.currentView.replace("View","")+"/"
 	 					+this.viewableDateRange.start.toString(eHA.calendar.viewDateFormat(obj.view))+"/?"
 	 					+Object.toQueryString(this.defaultFormOptions));
 	 		}
 	 		this.executions++;
 	 		eHA.log.create("calendarModule ("+this.properties.assetid+"). executions set to "+this.executions,eHA.log._DEBUG);
			SWFAddress.setValue("/"+this.properties.assetid+"/"+obj.view.replace("View","")+"/"
 	 				+obj.startdate.toString(eHA.calendar.viewDateFormat(obj.view))+"/?"
 	 				+Object.toQueryString(formOptions));
 		}catch(err){
			
 			eHA.log.create("calendarModule ("+this.properties.assetid+"). ERROR setting hash! "+err.toString(),1);
 		}
 	},
 	/*
 	 * loads event data into this.events object
 	 */
 	loadEvents: function(){
 		try{
 			if(typeof this.data!=="undefined" && this.data.length>0){
 				var eventObjects = {};
 				for(var i=0; i<this.data.length; i++){
 					if(typeof this.events==="undefined" || typeof this.events[this.data[i].assetid]==="undefined"){
 						var thisEvent = new eventObject(this.data[i]);
 						// this event has not already been loaded
 						if(typeof this.selectedCategory!=="undefined"){
 							thisEvent.properties.category.each(function(thisCategoryObject){
 								if(thisCategoryObject.id==this.selectedCategory.id){
 									thisEvent.show();
 									eHA.log.create("calendarModule ("+this.properties.assetid+"). loading an Event that is visible",3);
 								}else{
 									thisEvent.hide();
 									eHA.log.create("calendarModule ("+this.properties.assetid+"). loading an Event that is not visible",3);
 								}
 							}.bind(this));
 						}else{
 							eHA.log.create("calendarModule ("+this.properties.assetid+"). loading an Event without checking visibility",3);
 						}
 						eventObjects[thisEvent.properties.assetid] = thisEvent;
 					}
 				}
 				if(typeof this.events==="undefined"){
 					this.events = {};
 				}
 				Object.extend(this.events,eventObjects);
 			}
 		}catch(err){
 			eHA.log.create("calendarModule ("+this.properties.assetid+"). "+err.message,1);
 		}
 	},
 	/**
 	 * performs ajax for calendar
 	 * @function
 	 */
 	loadData: function(callback,packedargs){
 		var parameters = {
 			childpagename: eHA.Site+"/eHA_Module_C/"+eHA.Site+"/Calendar/json",
 			site: eHA.Site,
 			c: "eHA_Module_C",
 			cid: this.properties.assetid,
 			pagename: eHA.Site+"_default_Wrapper"
 		};
 		var formPackedargs = {};
 		if(typeof this.form!=="undefined"){
 			formPackedargs = this.form.serialize(true);
 			eHA.log.create("calendarModule ("+this.properties.assetid+"). packedargs from form = "+Object.toQueryString(formPackedargs),3);
 		}
 		if(typeof packedargs!=="undefined" && packedargs){
 			Object.extend(formPackedargs,packedargs);
 			parameters.packedargs = Object.toQueryString(formPackedargs);
 		}
 		var URL = "/cs/Satellite";
		new Ajax.Request(URL,
			{
				method:'get',
				parameters: parameters,
				onCreate: function(){
					eHA.log.create("calendarModule ("+parameters.cid+"): AJAX request for JSON created", 3);
				},
				onSuccess: function(transport){
					eHA.log.create("calendarModule ("+parameters.cid+"): AJAX request for JSON succeeded", 3);
				},
				onComplete: function(transport){
					// add transport.responseText to this.properties
					eHA.log.create("calendarModule ("+this.properties.assetid+"): AJAX request for JSON completed", 3);
					if(transport.responseText){
						eHA.log.create("calendarModule ("+this.properties.assetid+"): attempting to evaluate JSON and add to calendarObject", 3);
						try{
							var metaData = transport.responseText.evalJSON(true);
							Object.extend(this.properties,metaData.configuration);
							this.properties.complete = true;
							if(typeof metaData.events!=="undefined"){
								this.data = metaData.events;
								this.loadEvents();
							}
							if(typeof metaData.events!=="undefined"){
								if(metaData.events.size()> 0){
									//alert('events lees then 1');
									this.loadEvents();
								}
							}
						}catch(err){
							eHA.log.create("calendarModule ("+this.properties.assetid+"):"+err.name+" - "+err.message, 1);
						}
					}else{
						eHA.log.create("calendarModule ("+this.properties.assetid+"): problem with transport.responseText onComplete", 1);
					}
					if(typeof callback!=="undefined" && callback){
						callback();
					}
				}.bind(this),
				onFailure: function(){
					eHA.log.create("calendarModule ("+parameters.cid+"): AJAX request for JSON resulted in failure", 1);
				}
			});
 	},
	createForm: function(){
 		try{
 			this.form = new Element("form",{method:"",action:"",name:"assetid-"+this.properties.assetid,
 				id:"assetid-"+this.properties.assetid});
 			
 			var formContents = "";
 			
 			if(this.properties.showCategoryDropdown && this.properties.showCategoryDropdown!=="false"){
 				formContents += "<div class='categoryDropdown'>";
 				formContents += "<label for='categoryDropdown-"+this.properties.assetid+"'>Category:</label>";
 				formContents += "<select id='categoryDropdown-"+this.properties.assetid+"' name='category'>";
 				formContents += "<option value='null'>All</option>";
 				for(var i=0;i<this.properties.category.length;i++){
 					formContents += "<option value='"+this.properties.category[i].id+"'>"
 									+this.properties.category[i].name+"</option>";
 				}
 				formContents += "</select>";
 				formContents += "</div>";
 			}
 			if(this.properties.showKeywordSearch && this.properties.showKeywordSearch!=="false"){
 				formContents += "<div class='keywordSearch'>";
 				formContents += "<label for='keywordSearch-"+this.properties.assetid+"'>Keywords:</label>"
 								+"<input type='text' id='keywordSearch-"+this.properties.assetid+"' name='keyword' />";
 				formContents += "</div>";
 			}
 			if(this.properties.showDateRangeFilter && this.properties.showDateRangeFilter!=="false"){
 				var startInput = new Element("input",{type:"text",value:this.properties.dtstart,
 					id:"startDate"+this.properties.assetid,name:"dtstart"});
 				var endInput = new Element("input",{type:"text",value:this.properties.dtend,
 					id:"endDate"+this.properties.assetid,name:"dtend"});
 				
 				var startDateDiv = new Element("div",{className:"startDate"})
 					.update("<label for='startDate"+this.properties.assetid+"'>Start Date</label>").insert({bottom:startInput});
 				var endDateDiv = new Element("div",{className:"endDate"})
 					.update("<label for='endDate"+this.properties.assetid+"'>End Date</label>").insert({bottom:endInput});
 				
 				var dateRangeFilterHeader = new Element("h4").update("Filter results by date range");
 				var dateRangeFilterDiv = new Element("div",{className:"dateRangeFilter"})
 					.insert({bottom:dateRangeFilterHeader}).insert({bottom:startDateDiv}).insert({bottom:endDateDiv});
 			}
 			
 			if(formContents.length>0 || (this.properties.showDateRangeFilter && this.properties.showDateRangeFilter!=="false")){
 				formContents += "<div class='submit'>";
 				formContents += "<input type='submit' class='submit' name='submit' id='submit-"
 								+this.properties.assetid+"' value='Submit' />";
 				formContents += "<input type='reset' class='reset' name='reset' id='reset-"
 								+this.properties.assetid+"' value='Reset' />";
 				formContents += "</div>";
 				
 				this.form.update(formContents);
 				
 				$$("div.calendarModule.assetid-"+this.properties.assetid+" h3")[0].insert({after:this.form});
 				
 				if(this.properties.showDateRangeFilter && this.properties.showDateRangeFilter!=="false"){
 	 				this.form.down("div.submit").insert({before:dateRangeFilterDiv});
 	 				var dateSliderOptions = {
 	 						dragHandles:       true,
 	 						dayWidth:          1,
 	 						dateFormat:        eHA.news.dateFormat,
 	 						zoom:              true,
 	 						handleFinder:      true,
 	 						appearOnFocus:     true,
 	 						lowerLimitYear:    Date.parse(this.properties.dtstart).getFullYear(),
 	 						upperLimitYear:    Date.parse(this.properties.dtend).getFullYear(),
 	 						startDate:         this.properties.dtstart,
 	 						endDate:           this.properties.dtend,
 	 						inputStartField:   startInput,
 	 						inputEndField:     endInput,
 	 						insertLocation:    'after',
 	 						insertElement:     endInput
 	 				};
 		 			try{
 		 				var dateRangeSlider = new DateSlider(dateSliderOptions);
 		 			}catch(err){
 		 				eHA.log.create("calendarModule ("+this.properties.assetid+"). "+err.name+" - "+err.message,1);
 		 			}
 				}
 				
 				if(this.properties.showGoToDate && this.properties.showGoToDate!=="false"){
 	 				var goToDateDiv = new Element("div",{className:"goToDate"});
 	 				var goToDateForm = new Element("form",
 	 						{method:"",action:"",name:"goToDateForm-"+this.properties.assetid,
 	 							id:"goToDateForm-"+this.properties.assetid});
 	 				var goToDateLabel = new Element("label",{'for':"goToDate"+this.properties.assetid}).update("Go to date:");
 	 				var goToDate = new Element("input",{type:"text",name:"goToDate",id:"goToDate"+this.properties.assetid});
 	 				var goToDateSubmit = new Element("input",{type:'submit',value:'Go'});
 	 				goToDateForm.insert({bottom:goToDateLabel}).insert({bottom:goToDate}).insert({bottom:goToDateSubmit});
 	 				goToDateDiv.update(goToDateForm);

 					this.form.insert({after:goToDateDiv});
 					
 					var datePickerOptions = {
 							relative:		goToDate,
 							keepFieldEmpty:	true
 					};
 	 				var dpck_fieldname = new DatePicker(datePickerOptions);
 	 				
 	 				goToDateForm.observe("submit",function(event){
 	 					event.stop();
 	 					this.viewableDateRange.start = Date.parse($F(goToDate));
						this.assignViewEvents();
						//this.setDate(this.viewableDateRange.start);
						//this.current(this.viewableDateRange.start);
						//this.selectedDate = this.viewableDateRange.start;
 	 					eHA.log.create("calendarModule ("+this.properties.assetid+"). going to date: "+this.viewableDateRange.start,3);
 	 					this.setHash({view:this.currentView,startdate:this.viewableDateRange.start});
 	 				}.bind(this));
 	 				
 				}
 				
 		 		this.defaultFormOptions = this.form.serialize(true);
 				this.defaultFormOptions.events = 'true';
 				this.executions = new Number(0);

 				
 				this.form.observe("submit",function(event){
 					event.stop();
					this.assignViewEvents();
					this.current(Date.today());
					this.setHash({view:this.currentView,startdate:Date.today()});
 				}.bind(this));
 				
 			}
 			
 		}catch(err){
 			eHA.log.create("problem creating news module form, "+this.properties.assetid+".  "+err.message,1);
 		}
 	},
 	assignViewEvents: function(){
 		if(this.el.down("div.calendarView")){
 			this.el.down("div.calendarView").down("li.month a").observe("click",function(event){
 				event.stop();
 				if(this.currentView!=="monthView"){
 					this.setHash({view:"monthView",startdate:this.viewableDateRange.start});
 				}else{
 					eHA.log.create("calendarModule ("+this.properties.assetid+"). already on monthView",2);
 				}
 			}.bind(this));
 			this.el.down("div.calendarView").down("li.week a").observe("click",function(event){
 				event.stop();
 				if(this.currentView!=="weekView"){
 					this.setHash({view:"weekView",startdate:this.viewableDateRange.start});
 				}else{
 					eHA.log.create("calendarModule ("+this.properties.assetid+"). already on weekView",2);
 				}
 			}.bind(this));
 			this.el.down("div.calendarView").down("li.day a").observe("click",function(event){
 				event.stop();
 				if(this.currentView!=="dayView"){
 					this.setHash({view:"dayView",startdate:this.viewableDateRange.start});
 				}else{
 					eHA.log.create("calendarModule ("+this.properties.assetid+"). already on dayView",2);
 				}
 			}.bind(this));
 			this.el.down("div.calendarView").down("li.agenda a").observe("click",function(event){
 				event.stop();
 				if(this.currentView!=="agendaView"){
 					this.setHash({view:"agendaView",startdate:this.viewableDateRange.start});
 				}else{
 					eHA.log.create("calendarModule ("+this.properties.assetid+"). already on agendaView",2);
 				}
 			}.bind(this));
 		}
 	},
	/**
	 * find all events that fall between the viewableDateRange.start & .end values<br />
	 * loop through events first, days next<br />
	 * if event has recurrence value of "once", check directly if event can fit on current page<br />
	 * 
	 * @function
	 * @returns {Array} Array of objects {timestamp,event}
	 */
	findEvents: function(dateRange){
		eHA.log.create("calendarModule ("+this.properties.assetid+"). finding events",3);
		try{
			var eventArray = new Array();
 			for(eventID in this.events){
 				var thisEvent = this.events[eventID];
 				if(typeof thisEvent.properties.rrule!=="undefined" 
 					&& typeof thisEvent.properties.rrule.freq!=="undefined" && thisEvent.properties.rrule.freq==="Once"){
 					// don't need dateIterator for single event
 					if(thisEvent.properties.dtstart.clone().clearTime().between(dateRange.start,dateRange.end)){
 						eventArray.push({date:thisEvent.properties.dtstart.clone().clearTime(),event:thisEvent});
 					}
 				}else{
 					// proceed with dateIterator check
 					var dateIterator = dateRange.start.clone();
 					while(dateIterator.between(dateRange.start,dateRange.end)){
 						var showEvent = false;
 						if(dateIterator.between(thisEvent.properties.dtstart,thisEvent.properties.dtend) 
 								|| dateIterator.equals(thisEvent.properties.dtstart.clone().clearTime()) 
 								|| dateIterator.equals(thisEvent.properties.dtend.clone().clearTime())){
 							// date is between start & end for this event, proceed to insert occurrence
 							showEvent = true;
 						}else{
 							// check recurrence pattern of thisEvent
 							if(typeof thisEvent.properties.rrule!=="undefined" 
 								&& typeof thisEvent.properties.rrule.freq!=="undefined" 
 									&& typeof thisEvent.properties.rrule.until!=="undefined"){
 								if(thisEvent.properties.rrule.freq==="Daily"){
 									// must check w/ another between
 									if(dateIterator.between(thisEvent.properties.dtstart,thisEvent.properties.rrule.until) 
 											|| dateIterator.equals(thisEvent.properties.rrule.until.clone().clearTime())){
 										showEvent = true;
 									}
 								}
 								if(thisEvent.properties.rrule.freq==="Weekly"){
 									// weekly is done by day of week (of dtstart). check range, then check day
 									if(dateIterator.between(thisEvent.properties.dtstart,thisEvent.properties.rrule.until) 
 											|| dateIterator.equals(thisEvent.properties.rrule.until.clone().clearTime())){
 										if(dateIterator.toString('dddd')===thisEvent.properties.dtstart.toString('dddd')){
 											showEvent = true;
 										}
 									}
 								}
 								if(thisEvent.properties.rrule.freq==="Monthly"){
 									// monthly is done by day of week (of dtstart). check range, then check day
 									// can be either first, second, third, fourth, or final [day of week] of month
 									if(dateIterator.between(thisEvent.properties.dtstart,thisEvent.properties.rrule.until) 
 											|| dateIterator.equals(thisEvent.properties.rrule.until.clone().clearTime())){
 										if(dateIterator.toString('dddd')===thisEvent.properties.dtstart.toString('dddd')){
 											var dateIterator2 = thisEvent.properties.dtstart.clone();
 											var dateIterator3 = dateIterator.clone();
 											var dayOfWeek = thisEvent.properties.dtstart.toString('dddd').toLowerCase();
 											if(eval("thisEvent.properties.dtstart.equals(dateIterator2.first()."+dayOfWeek+"())")){
 												if(eval("dateIterator.equals(dateIterator3.first()."+dayOfWeek+"())")){
 													showEvent = true;
 												}
 											}
 											if(eval("thisEvent.properties.dtstart.equals(dateIterator2.second()."+dayOfWeek+"())")){
 												if(eval("dateIterator.equals(dateIterator3.second()."+dayOfWeek+"())")){
 													showEvent = true;
 												}
 											}
 											if(eval("thisEvent.properties.dtstart.equals(dateIterator2.third()."+dayOfWeek+"())")){
 												if(eval("dateIterator.equals(dateIterator3.third()."+dayOfWeek+"())")){
 													showEvent = true;
 												}
 											}
 											if(eval("thisEvent.properties.dtstart.equals(dateIterator2.fourth()."+dayOfWeek+"())")){
 												if(eval("dateIterator.equals(dateIterator3.fourth()."+dayOfWeek+"())")){
 													showEvent = true;
 												}
 											}
 											if(eval("thisEvent.properties.dtstart.equals(dateIterator2.final()."+dayOfWeek+"())")){
 												if(eval("dateIterator.equals(dateIterator3.final()."+dayOfWeek+"())")){
 													showEvent = true;
 												}
 											}
 										}
 									}
 								}
 								if(thisEvent.properties.rrule.freq==="Yearly"){
 									// yearly is by date of month. check range, then check date of month
 									if(dateIterator.between(thisEvent.properties.dtstart,thisEvent.properties.rrule.until) 
 											|| dateIterator.equals(thisEvent.properties.rrule.until.clone().clearTime())){
 										if(dateIterator.toString("MMMM dd")===thisEvent.properties.dtstart.toString("MMMM dd")){
 											showEvent = true;
 										}
 									}
 								}
 							}
 						}
 						
 						if(showEvent){
 							// assemble event array here
 							eventArray.push({date:dateIterator.clone(),event:thisEvent});
 						}
 						
 						dateIterator.addDays(1);
 					}
 				}
 			}
 			// sort by date before returning
 			eventArray = $A(eventArray).sortBy(function(event){
 				return event.date.getTime();
 			});
 			//console.log(eventArray.inspect());
 			return eventArray;
 		}catch(err){
			eHA.log.create("calendarModule ("+this.properties.assetid+"). "+err.message,3);
 			return false;
		}
	},
	populate: function(eventArray,className){
		eHA.log.create("calendarModule ("+this.properties.assetid+"). populating calendar page "
				+className+" with events found",3);
		if(typeof className==="undefined"){
			var className = "active";
		}
		try{
			var totalEvents = eventArray.length;
			//weekDifference corrects array counting from one to zero
			var weekDifference=0;
			for(var i=0;i<totalEvents;i++){
				weekDifference++;
				if(this.el.down("div.tableWrapper."+className).down("td.time-"+eventArray[i].date.getTime())){
					this.el.down("div.tableWrapper."+className)
					.down("td.time-"+eventArray[i].date.getTime()).insert({bottom:eventArray[i].event.view(eventArray[i].date.toString("MMMM d, yyyy")).viewString});
				}
			}
			this.setMore(className);
		}catch(err){
			eHA.log.create("calendarModule ("+this.properties.assetid+"). "+err.message,3);
		}
	},
	setMore: function(className){
		eHA.log.create("calendarModule ("+this.properties.assetid+"). setting more links for table "+className,3);
		try{
			if(this.el.down("div.tableWrapper."+className+" tbody").select("a.more")[0]){
				this.el.down("div.tableWrapper."+className+" tbody").select("a.more").invoke("remove");
			}
			this.el.down("div.tableWrapper."+className+" tbody").select("tr").each(function(tableRow){
				tableRow.childElements().each(function(day){
					if(day.select(".vevent").length>eHA.calendar.maxEventsShown){
						eHA.log.create("calendarModule ("+this.properties.assetid+"). found a day with more events than the limit, "+eHA.calendar.maxEventsShown,2);
						var iterator = 0;
						day.select(".vevent").each(function(element){
							iterator++;
							if(iterator>eHA.calendar.maxEventsShown){
								eHA.log.create("calendarModule ("+this.properties.assetid+"). hiding event",3);
								element.hide();
							}
						}.bind(this));
						if(iterator>eHA.calendar.maxEventsShown){
							eHA.log.create("calendarModule ("+this.properties.assetid+"). creating more link",3);
							try{
								// more than eHA.calendar.maxEventsShown Events are in this day
								var moreLink = new Element("a",{'href':'#',className:'more','title':'more events'}).update("more");
								day.insert({bottom:moreLink});
								moreLink.observe("click",function(event){
									event.stop();
									this.showMore(event.element());
								}.bind(this));
							}catch(err){
								eHA.log.create("calendarModule ("+this.properties.assetid+"). "+err.toString(),1);
							}
						}
					}
				}.bind(this));
			}.bind(this));
		}catch(err){
			eHA.log.create("calendarModule ("+this.properties.assetid+"). setMore failure! "+err.toString(),1);
		}
	},
	showMore: function(el){
		var thisDay = $(el).up("td");
		if(thisDay.select(".vevent")[0]){
			thisDay.select(".vevent").each(function(element){
				element.show();
			}.bind(this));
			thisDay.down("a.more").update("less").stopObserving("click").observe("click",function(event){
				event.stop();
				this.showLess(event.element());
			}.bind(this));
		}
		this.adjustWrapper();
	},
	showLess: function(el){
		var thisDay = $(el).up("td");
		if(thisDay.select(".vevent")[0]){
			var iterator = 1;
			thisDay.select(".vevent").each(function(element){
				if(iterator>eHA.calendar.maxEventsShown){
					element.hide();
				}
				iterator++;
			}.bind(this));
			thisDay.down("a.more").update("more").stopObserving("click").observe("click",function(event){
				event.stop();
				this.showMore(event.element());
			}.bind(this));
		}
		this.adjustWrapper();
	},
 	viewableDateRange: {},
 	nextDateRange: {},
 	previousDateRange: {},
 	preloadDateRange: {},
 	traversedDateRange: {},
 	adjustWrapper: function(){
 		try{
 			var wrapperDimensions = this.el.down("div.tableWrapper.active").getDimensions();
 			var headerHeight = 0;
 			var headerBottomMargin = 0;
 			var moreLinkHeight = 0;
 			if(this.el.down("h4.datesHeader")){
 				var headerH4 = this.el.down("h4.datesHeader");
 				headerHeight = headerH4.getHeight();
 				headerBottomMargin = headerH4.getStyle('margin-bottom');
 			}
 			if(this.el.down("span.more")){
 				moreLinkHeight = this.el.down("span.more").getHeight();
 			}
 			var wrapperHeight = wrapperDimensions.height + (3*parseInt(headerHeight,10))+parseInt(moreLinkHeight,10);
 			new Effect.Morph(this.el,{style:"height:"+wrapperHeight+"px;",duration:eHA.calendar.duration});
 			this.topOffset = parseInt(headerHeight,10)+parseInt(headerBottomMargin,10);
 		}catch(err){
 			eHA.log.create("calendarModule ("+this.properties.assetid+"). adjustWrapper error! "+err.toString(),eHA.log._ERROR);
 		}
 	},
 	clearCalendar: function(afterFinish){
 		eHA.log.create("calendarModule ("+this.properties.assetid+"). clearing calendar");
 		if(this.el.down("div.tableWrapper.active")){
 			var thisTable = this.el.down("div.tableWrapper.active");
 		}
 		if(this.el.down("div.viewNavigation")){
 			var thisViewNav = this.el.down("div.viewNavigation");
 		}
 		if(this.el.down("h4.datesHeader")){
 			var thisDatesHeader = this.el.down("h4.datesHeader");
 		}
 		
 		new Effect.Appear(this.waitPanel,{duration:eHA.calendar.duration,afterFinish:function(obj){
 			obj.element.down("img.preloader").show();
	 		if(typeof thisTable!=="undefined"){
	 			thisTable.remove();
	 			eHA.log.create("calendarModule ("+this.properties.assetid+"). removing thisTable");
	 		}
	 		if(typeof thisViewNav!=="undefined"){
	 			thisViewNav.remove();
	 			eHA.log.create("calendarModule ("+this.properties.assetid+"). removing thisViewNav");
	 		}
	 		if(typeof thisDatesHeader!=="undefined"){
	 			thisDatesHeader.remove();
	 			eHA.log.create("calendarModule ("+this.properties.assetid+"). removing thisDatesHeader");
	 		}
			if(this.el.down("div.calendarView")){
				this.el.down("div.calendarView").down("ul").childElements().invoke("removeClassName","sel");
			}
 			if(typeof afterFinish!=="undefined"){
 				afterFinish();
 			}
 		}.bind(this)});
 	},
	clearCalendarPage: function(className,afterFinish){
 		try{
 			if(typeof className==="undefined"){
 				var className = "active";
 			}
 	 		new Effect.Appear(this.waitPanel,{duration:eHA.calendar.duration,afterFinish:function(obj){
 	 			obj.element.down("img.preloader").show();
 	 			if(typeof afterFinish!=="undefined"){
 	 				if(this.el.down("div.tableWrapper."+className)){
 	 					this.el.down("div.tableWrapper."+className).hide();
 	 				}
 	 				afterFinish();
 	 			}
 	 		}.bind(this)});
 		}catch(err){
 			eHA.log.create("calendarModule ("+this.properties.assetid+"). clearCalendarPage failed! "+err.toString(),1);
 		}
	},
	showCalendarPage: function(className,afterFinish){
		try{
			if(typeof className==="undefined"){
				var className = "active";
			}
			if(this.el.down("div.tableWrapper."+className)){
				this.el.down("div.tableWrapper."+className).show();
			}
			new Effect.Fade(this.waitPanel,{duration:eHA.calendar.duration,afterFinish:function(obj){
				obj.element.down("img.preloader").hide();
	 			if(typeof afterFinish!=="undefined"){
	 				eHA.log.create("calendarModule ("+this.properties.assetid+"). executing afterFinish",3);
	 				afterFinish();
	 			}
			}.bind(this)});
		}catch(err){
			eHA.log.create("calendarModule ("+this.properties.assetid+"). showCalendarPage failed! "+err.toString(),1);
		}
	},
 	assignDateLabelEvents: function(className){
		if(typeof this.properties.showDisplayStyleSwitch==="undefined" || this.properties.showDisplayStyleSwitch==="true"){
			this.el.select("div.tableWrapper."+className+" h5.dateLabel a").each(function(element){
				element.stopObserving("click");
				var thisDate = new Date(parseInt(eHA.elementToObjectLiteral(element.up("td")).time,10));
				element.writeAttribute({"title":thisDate.toString("MMMM dS, yyyy")})
				element.observe("click",function(event){
					event.stop();
					this.viewableDateRange.start = thisDate;
					this.setHash({view:"dayView",startdate:this.viewableDateRange.start});
					eHA.log.create("calendarModule ("+this.properties.assetid+"). selecting dayView directly - "+this.viewableDateRange.start.toString(),3);
				}.bind(this));
			}.bind(this));
		}else{
			// make anchors into non-links
			this.el.select("div.tableWrapper."+className+" h5.dateLabel a").each(function(element){
				element.stopObserving("click");
				element.setStyle({
					"cursor":"default"
				});
				element.observe("click",function(event){
					event.stop();
				});
			});
		}
 	},
 	next: function(startDate){
 		eHA.log.create("calendarModule ("+this.properties.assetid+"). next",3);
		this.setDate(startDate);
		this.el.down("div.tableWrapper.previous").remove();
		this.clearCalendarPage("active",function(){
			try{
				var previousPage = this.el.down("div.tableWrapper.active");
				previousPage.hide();
				previousPage.className = "tableWrapper previous";
				var nextPage = this.el.down("div.tableWrapper.next");
				nextPage.show();
				nextPage.className = "tableWrapper active";
				this[this.currentView].updateHeader();
				this.adjustWrapper();
				this.showCalendarPage("active",function(){
					this[this.currentView].populate("next",this.nextDateRange,false);
				}.bind(this));
			}catch(err){
				eHA.log.create("calendarModule ("+this.properties.assetid+"). error in #next() "+err.toString(),1);
			}
		}.bind(this));
 	},
 	current: function(startDate){
 		eHA.log.create("calendarModule ("+this.properties.assetid+"). current",3);
 		try{
 			this.setDate(startDate,function(){
 				this.clearCalendarPage("active",function(){
 					this[this.currentView].populate("active",this.viewableDateRange,true);
 					this[this.currentView].updateHeader();
 					this.adjustWrapper();
 					this.showCalendarPage("active",function(){
 						this[this.currentView].populate("previous",this.previousDateRange,false);
 						this[this.currentView].populate("next",this.nextDateRange,false);
 					}.bind(this));
 				}.bind(this));
 			}.bind(this));
 		}catch(err){
 			eHA.log.create("calendarModule ("+this.properties.assetid+"). current fail! "+err.toString(),eHA.log._ERROR);
 		}
 	},
 	previous: function(startDate){
 		eHA.log.create("calendarModule ("+this.properties.assetid+"). previous",3);
		this.setDate(startDate);
		this.el.down("div.tableWrapper.next").remove()
		this.clearCalendarPage("active",function(){
			try{
				var nextPage = this.el.down("div.tableWrapper.active");
				if(nextPage) nextPage.hide();
				if(nextPage) nextPage.className = "tableWrapper next";
				var previousPage = this.el.down("div.tableWrapper.previous");
				previousPage.show();
				previousPage.className = "tableWrapper active";
				this[this.currentView].updateHeader();
				this.adjustWrapper();
				this.showCalendarPage("active",function(){
					this[this.currentView].populate("previous",this.previousDateRange,false);
				}.bind(this));
			}catch(err){
				eHA.log.create("calendarModule ("+this.properties.assetid+"). error in #previous() "+err.toString(),1);
			}
		}.bind(this));
 	},
	/**
	 * sets this.viewableDateRange start & end to correct values 
	 * @function
	 */
	setDate: function(startDate,callback){
 		var offsetFunction = eHA.calendar.offsetFunction(this.currentView);
		this.viewableDateRange = this[this.currentView].defineDateRange(startDate);
		this.previousDateRange = this[this.currentView].defineDateRange(startDate.clone()[offsetFunction](-1));
		this.nextDateRange = this[this.currentView].defineDateRange(startDate.clone()[offsetFunction](1));
		
		this.preloadDateRange.start = this.previousDateRange.start.clone();
		this.preloadDateRange.end = this.nextDateRange.end.clone();
		
		eHA.log.create("calendarModule ("+this.properties.assetid+"). setting preload dates to: start="+this.preloadDateRange.start.toString("MMM-dd-yyyy")
				+" and end="+this.preloadDateRange.end.toString("MMM-dd-yyyy"),3);
		
		var needAJAX = this.checkTraversedDates();
		
		if(needAJAX){
			eHA.log.create("calendarModule ("+this.properties.assetid+"). need to make an AJAX request",2);
			this.loadData(function(){
				this.loadEvents();
				if(typeof callback!=="undefined"){
					callback();
				}
			}.bind(this), {
				events:true,
				dtstart:this.preloadDateRange.start.toString(eHA.calendar.dateFormat),
				dtend:this.preloadDateRange.end.toString(eHA.calendar.dateFormat)
			});
		}else{
			if(typeof callback!=="undefined"){
				callback();
			}
		}
		
	},
	buildView: function(startDate,view){
		// 
		try{
			if(typeof startDate==="undefined"){
				startDate = this.viewableDateRange.start;
			}else{
				eHA.log.create("calendarModule ("+this.properties.assetid+"). building "+view+" with startDate="+startDate,3);
				startDate = Date.parse(startDate);
			}
			
	 		if(!this.el.down("div.viewNavigation") && !this.el.down("h4.datesHeader")){
	 			eHA.calendar.addNavigationAndHeader(this,view);
	 		}
			if(typeof this.currentView==="undefined" || this.currentView!==view){
				eHA.log.create("calendarModule ("+this.properties.assetid+"). setting currentView to "+view);
				var startDate=Date.today();//CALENDAR PRODUCT FIX :: BUBG:: crashing search results
				this.currentView = view;
				this.current(startDate);
			}else{
				try{
					var previousStartDate = new Date(parseInt(eHA.elementToObjectLiteral(
							this.el.down("div.tableWrapper.previous tbody td")).time,10));
					var nextStartDate = new Date(parseInt(eHA.elementToObjectLiteral(
							this.el.down("div.tableWrapper.next tbody td")).time,10));
					
					eHA.log.create("calendarModule ("+this.properties.assetid+"). startDate = "+startDate.toString(),3);
					
					if(nextStartDate.equals(startDate)){
						this.next(startDate);
					}else{
						if(previousStartDate.equals(startDate)){
							this.previous(startDate);
						}else{
							this.current(startDate);
						}
					}
				}catch(err){
					eHA.log.create("calendarModule ("+this.properties.assetid+"). el problem? "+err.toString());
				}
			}
		}catch(err){
			eHA.log.create("calendarModule ("+this.properties.assetid+"). buildView failed! "+err.toString(),1);
		}
	},
 	monthView: {
		populate: function(className,dateRange,visible){
			this.createTable(className,dateRange,visible);
			this.updateDateLabels(dateRange,className);
			this.parent.populate(this.parent.findEvents(dateRange),className);
		},
		createTable: function(className,dateRange,visible){
			try{
				eHA.log.create("creating table for month "+className,3);
				if(this.parent.el.down("div.tableWrapper."+className)){
					// remove old table
					this.parent.el.down("div.tableWrapper."+className).remove();
				}
				var displayProperty = "display:none;";
				if(visible){
					displayProperty = "display:block;";
				}
				var tableWrapper = new Element("div",
						{className:"tableWrapper "+className,style:"width:100%;position:absolute;top:"+this.topOffset+"px;"+displayProperty});
	 			var table = new Element("table",{className:"monthView "+className})
	 				.update("<thead><tr><th class='sunday weekend'>Sun</th><th class='monday'>Mon</th>"
	 						+"<th class='tuesday'>Tue</th><th class='wednesday'>Wed</th><th class='thursday'>Thu</th>"
	 						+"<th class='friday'>Fri</th><th class='saturday weekend'>Sat</th></tr></thead><tbody></tbody>");
	 			tableWrapper.update(table);
		 		this.parent.el.insert({bottom:tableWrapper});
		 		
		 		var weekSpan = Math.ceil((dateRange.end.getDaysSinceEpoch() - dateRange.start.getDaysSinceEpoch())/7);
		 		for(var i=0;i<weekSpan;i++){
		 			var weekHTML = "<tr class='week"+i+"'><td class='sunday weekend'><h5 class='dateLabel'>"
		 				+"<a href=''></a></h5></td><td class='monday'><h5 class='dateLabel'><a href=''></a></h5></td>"
		 				+"<td class='tuesday'><h5 class='dateLabel'><a href=''></a></h5></td>"
		 				+"<td class='wednesday'><h5 class='dateLabel'><a href=''></a></h5></td>"
		 				+"<td class='thursday'><h5 class='dateLabel'><a href=''></a></h5></td>"
		 				+"<td class='friday'><h5 class='dateLabel'><a href=''></a></h5></td>"
		 				+"<td class='saturday weekend'><h5 class='dateLabel'><a href=''></a></h5></td></tr>";
		 			table.down("tbody").insert({bottom:weekHTML});
		 		}
			}catch(err){
				eHA.log.create(err.message,3);
			}
		},
		defineDateRange: function(startDate){
			var dateRange = {};
			dateRange.start = startDate.clone();
			dateRange.start.moveToFirstDayOfMonth();
			dateRange.end = dateRange.start.clone().moveToLastDayOfMonth();
			if(!dateRange.end.is().saturday()){
				dateRange.end.next().saturday();
			}
			if(!dateRange.start.is().sunday()){
				dateRange.start.last().sunday();
			}
			eHA.log.create("calendarModule ("+this.parent.properties.assetid+"). created date range for "+startDate.toString("MMMM"),3);
			return dateRange;
		},
		updateHeader: function(){
			var labelDate = this.parent.viewableDateRange.start.clone();
			if(labelDate.getDate()>1){
				// add month because first calendar day shown is from previous month
				labelDate.addMonths(1);
			}
			if(this.parent.el.down("h4.datesHeader")){
				eHA.log.create("writing header "+labelDate.toString("MMMM yyyy"),3);
				this.parent.el.down("h4.datesHeader").update(labelDate.toString("MMMM yyyy"));
			}
		},
		/**
		 * updates H5s with date number, also adds IDs to each table Cell
		 * @function
		 */
		updateDateLabels: function(dateRange,className){
			var labelDate = dateRange.start.clone();
			if(labelDate.getDate()>1){
				// add month because first calendar day shown is from previous month
				labelDate.addMonths(1);
			}
			
			this.parent.el.down("div.tableWrapper."+className).down("table").select("tbody tr td").each(function(dayCell,iteration){
				var curDate = dateRange.start.clone().addDays(iteration);
				dayCell.down("h5.dateLabel a").update(curDate.getDate());
				dayCell.addClassName("time-"+curDate.getTime());
				if(curDate.getMonth()<labelDate.getMonth()){
					dayCell.addClassName("previous-month");
				}
				if(curDate.getMonth()>labelDate.getMonth()){
					dayCell.addClassName("next-month");
				}
				if(curDate.equals(Date.today())){
					dayCell.addClassName("today");
				}
			}.bind(this));
			this.parent.assignDateLabelEvents(className);
		}
 	},
 	weekView: {
 		populate: function(className,dateRange,visible){
			this.createTable(className,dateRange,visible);
			this.updateDateLabels(dateRange,className);
			this.parent.populate(this.parent.findEvents(dateRange),className);
 		},
 		createTable: function(className,dateRange,visible){
			try{
				if(this.parent.el.down("div.tableWrapper."+className)){
					// remove table if it already exists
					this.parent.el.down("div.tableWrapper."+className).remove();
				}
				var displayProperty = "display:none;";
				if(visible){
					displayProperty = "display:block;";
				}
				var tableWrapper = new Element("div",
						{className:"tableWrapper "+className,style:"width:100%;position:absolute;top:"+this.topOffset+"px;"+displayProperty});
	 			var table = new Element("table",{className:"weekView "+className}).update("<thead><tr>"
	 					+"<th class='sunday weekend'>Sun</th><th class='monday'>Mon</th>"
	 					+"<th class='tuesday'>Tue</th><th class='wednesday'>Wed</th><th class='thursday'>Thu</th>"
	 					+"<th class='friday'>Fri</th><th class='saturday weekend'>Sat</th></tr></thead><tbody></tbody>");
	 			tableWrapper.update(table);
	 			this.parent.el.insert({bottom:tableWrapper});
		 		
				if(table.down("tbody").childElements()[0]){
					table.down("tbody").childElements().invoke("remove");
				}
				var weekHTML = "<tr><td class='sunday weekend'><h5 class='dateLabel'><a href=''></a>"
					+"</h5></td><td class='monday'><h5 class='dateLabel'><a href=''></a></h5></td>"
					+"<td class='tuesday'><h5 class='dateLabel'><a href=''></a></h5></td><td class='wednesday'>"
					+"<h5 class='dateLabel'><a href=''></a></h5></td><td class='thursday'><h5 class='dateLabel'>"
					+"<a href=''></a></h5></td><td class='friday'><h5 class='dateLabel'><a href=''></a></h5></td>"
					+"<td class='weekend saturday'><h5 class='dateLabel'><a href=''></a></h5></td></tr>";
	 			table.down("tbody").insert({bottom:weekHTML});
			}catch(err){
				eHA.log.create(err.message,3);
			}
 		},
		defineDateRange: function(startDate){
			var dateRange = {};
			dateRange.start = startDate.clone()
			if(!dateRange.start.is().sunday()){
				dateRange.start.last().sunday();
			}
			dateRange.end = dateRange.start.clone().addDays(6);
			eHA.log.create("calendarModule ("+this.parent.properties.assetid+"). created date range for "+dateRange.start.toString("MMM dd, yyyy"),3);
			return dateRange;
		},
		updateHeader: function(){
 			var calendarDatesHeader = this.parent.viewableDateRange.start.toString('MMMM d')
 				+" - "+this.parent.viewableDateRange.end.toString('MMMM d, yyyy');
 			if(this.parent.el.down("h4.datesHeader")){
 				eHA.log.create("writing header "+calendarDatesHeader,3);
 				this.parent.el.down("h4.datesHeader").update(calendarDatesHeader);
 			}
		},
 		/**
 		 * updates H5s with date number, also adds IDs to each table Cell
 		 * @function
 		 */
 		updateDateLabels: function(dateRange,className){
			this.parent.el.down("div.tableWrapper."+className).down("table").select("tbody tr td").each(function(dayCell,iteration){
 				var curDate = dateRange.start.clone().addDays(iteration);
 				dayCell.down("h5.dateLabel a").update(curDate.getDate());
 				dayCell.addClassName("time-"+curDate.getTime());
				if(curDate.equals(Date.today())){
					dayCell.addClassName("today");
				}else{
					dayCell.removeClassName("today");
				}
			}.bind(this));
 			this.parent.assignDateLabelEvents(className);
 		}
 	},
 	dayView: {
 		createTable: function(className,dateRange,visible){
			try{
				if(this.parent.el.down("div.tableWrapper."+className)){
					this.parent.el.down("div.tableWrapper."+className).remove();
				}
				var displayProperty = "display:none;";
				if(visible){
					displayProperty = "display:block;";
				}
				var tableWrapper = new Element("div",
						{className:"tableWrapper "+className,style:"width:100%;position:absolute;top:"+this.topOffset+"px;"+displayProperty});
				var table = new Element("table",{className:"dayView "+className}).update("<thead><tr><th></th></tr></thead><tbody></tbody>");
		 		tableWrapper.update(table);
				this.parent.el.insert({bottom:tableWrapper});
				
				if(table.down("tbody").childElements()[0]){
					table.down("tbody").childElements().invoke("remove");
				}
				
				var dayHTML = "<tr><td><h5 class='dateLabel'><a href=''></a></h5></td></tr>";
	 			table.down("tbody").insert({bottom:dayHTML});
			}catch(err){
				eHA.log.create(err.message,3);
			}
 		},
		populate: function(className,dateRange,visible){
			this.createTable(className,dateRange,visible);
			this.updateDateLabels(dateRange,className);
			this.parent.populate(this.parent.findEvents(dateRange),className);
		},
		defineDateRange: function(startDate){
			var dateRange = {};
			dateRange.start = startDate.clone();
			dateRange.end = startDate.clone();
			eHA.log.create("calendarModule ("+this.parent.properties.assetid+"). created date range for "+dateRange.start.toString("MMM dd, yyyy"),3);
			return dateRange;
		},
		updateHeader: function(){
			var calendarDatesHeader = this.parent.viewableDateRange.start.toString('dddd, MMMM d, yyyy');
 			if(this.parent.el.down("h4.datesHeader")){
 				eHA.log.create("writing header "+calendarDatesHeader,3);
 				this.parent.el.down("h4.datesHeader").update(calendarDatesHeader);
 			}
		},
		/**
		 * updates H5s with date number, also adds IDs to each table Cell
		 * @function
		 */
		updateDateLabels: function(dateRange,className){
			var curDate = dateRange.start;
			var table = this.parent.el.down("div.tableWrapper."+className).down("table");
			table.down("tbody tr td").down("h5.dateLabel a").update(curDate.getDate());
			var classNameString = curDate.toString("dddd").toLowerCase()+" "+"time-"+curDate.getTime();
			if(!curDate.is().weekday()){
				classNameString += " weekend";
			}
			if(curDate.equals(Date.today())){
				classNameString += " today";
			}
			table.down("tbody tr td").className = classNameString;
			table.down("thead tr th").className = classNameString;
			table.down("thead tr th").update(curDate.toString("dddd"));
			this.parent.assignDateLabelEvents(className);
		}
	},
	// displays first 10 events that occur.  only checks time for the next 90 days
	// both numbers are configurable below
	agendaView: {
		homepageEventlimit:3,
		eventLimit: 10,
		daysToSearch: 90,
		createTable: function(className,dateRange,visible){
			eHA.log.create("calendarModule ("+this.parent.properties.assetid+"). creating agendaView table: "+className);
			if(this.parent.el.down("div.tableWrapper."+className)){
				this.parent.el.down("div.tableWrapper."+className).remove();
			}
			var displayProperty = "display:none;";
			if(visible){
				displayProperty = "display:block;";
			}
			var tableWrapper = new Element("div",{className:"tableWrapper "+className,
				style:"width:100%;position:absolute;top:"+this.topOffset+"px;"+displayProperty});
			var table = new Element("table",{className:"agendaView "+className}).update("<tbody></tbody>");
	 		tableWrapper.update(table);
			this.parent.el.insert({bottom:tableWrapper});
			
	 		var emptyRowHTML = new Template("<tr#{cssClass}><td class='day'>#{day}</td><td class='time'>#{time}</td>"
	 				+"<td class='event'>#{event}</td><td class='location'>#{location}</td></tr>");
	 		var eventArray = this.parent.findEvents(dateRange);
	 		var totalEvents;
	 		if(eventArray){
	 			if(table.down("tbody").childElements()[0]){
	 				table.down("tbody").childElements().invoke("remove");
	 			}
				if($$("body")[0].hasClassName('.eHA_LandingPage_C')){ //if is event from home page  
					totalEvents=this.homepageEventlimit;
				}else{
	 				totalEvents = (eventArray.length>this.eventLimit)?this.eventLimit:eventArray.length;
				}
	 			var previousDay;
				//alert("homepageEventlimit"+this.homepageEventlimit)
				//alert("parseInt(this.properties.agendaEventLimit,3)="+parseInt(this.properties.agendaEventLimit,3))
	 			// populating events during table creation because the size of the table is
	 			// dependent on the number of events returned
	 			for(var i=0;i<totalEvents;i++){
					if(eventArray[i]){
						var thisDay = "<h5 class='dateLabel'><a href=''>"+eventArray[i].date.toString("ddd MMM d")+"</a></h5>";
						var cssClass = "";
						if(previousDay===eventArray[i].date.toString("ddd MMM d")){
							//thisDay = "";
						}else{
							cssClass = "newDay";
						}
						if(i+1===totalEvents){
							cssClass += " last";
							dateRange.end = eventArray[i].date.clone().clearTime();
						}
						previousDay = eventArray[i].date.toString("ddd MMM d");
				
						var thisEvent = {
							cssClass:(cssClass!=="")?" class='"+cssClass+"'":"",
							day:thisDay,
							time:eventArray[i].event.properties.dtstart.toString("h:mm tt")
								+" to "+eventArray[i].event.properties.dtend.toString("h:mm tt"),
							event:eventArray[i].event.view(eventArray[i].date.toString("MMMM d, yyyy")).viewString,
							location:eventArray[i].event.properties.location
						};	
					}//if eventArray[i]
	 				table.down("tbody").insert({bottom:emptyRowHTML.evaluate(thisEvent)});
					//alert(eventArray[i].event.view().url)
	 			}
	 		}
		},
		populate: function(className,dateRange,visible){
			this.createTable(className,dateRange,visible);
	 		this.updateDateLabels(dateRange,className);
		},
		defineDateRange: function(startDate){
			var dateRange = {};
			dateRange.start = startDate.clone();
			dateRange.end = startDate.clone().addDays(this.daysToSearch);
			eHA.log.create("calendarModule ("+this.parent.properties.assetid+"). created date range for "
					+dateRange.start.toString("MMM dd, yyyy")+" to "+dateRange.end.toString("MMM dd, yyyy"));
			return dateRange;
		},
		updateHeader: function(){
			var calendarDatesHeader = this.parent.viewableDateRange.start.toString('ddd MMM d')
				+" to "+this.parent.viewableDateRange.end.toString('ddd MMM d');
 			if(this.parent.el.down("h4.datesHeader")){
 				eHA.log.create("writing header "+calendarDatesHeader,3);
 				this.parent.el.down("h4.datesHeader").update(calendarDatesHeader);
 			}
		},
		/**
		 * updates H5s with date number, also adds IDs to each table Cell
		 * @function
		 */
		updateDateLabels: function(dateRange,className){
			this.parent.el.down("div.tableWrapper."+className).down("table").select("tbody tr td").each(function(dayCell,iteration){
 				if(dayCell.down("h5.dateLabel a")){
 					var curDate = Date.parse(dayCell.down("h5.dateLabel a").innerHTML);
 	 				//dayCell.down("h5.dateLabel a").update(curDate.getDate());
 	 				dayCell.addClassName("time-"+curDate.getTime());
 					if(curDate.equals(Date.today())){
 						dayCell.addClassName("today");
 					}else{
 						dayCell.removeClassName("today");
 					}
 				}
			}.bind(this));
 			this.parent.assignDateLabelEvents(className);
		}
	}
});

/**
 * returns days since epoch as an integer
 * @extends {@link Date}
 * @function
 */
Date.prototype.getDaysSinceEpoch = function(){
	var days = Math.ceil((this.getTime())/(1000*60*60*24));
	return days;
};

/**
 * eHA.calendar object namespace.  Most functions are a part of {@link calendarObject} because
 * multiple calendars on one page must be supported
 * @namespace
 */
eHA.calendar = {
	/**
	 * finds calendars based on selector, declares new {@link calendarObject} per calendar found<br />
	 * calendarObjects are saved as children of this namespace in #calendarObjects object with name=calendarID
	 * gathered from calendar class "assetid-12312312331"
	 * @function
	 */
	init: function(){
		if($$("div.vcalendar")[0]){
			this.preloader = new Element("img",{src:eHA.resourcepath+"images/wide-preloader.gif",alt:"please wait",className:"preloader"});
			this.calendarObjects = {};
			if($$("body")[0].hasClassName('.eHA_LandingPage_C')){ //if is event from home page  
					$$("div.vcalendar").each(function(element){
					element.setStyle({overflow:"visible"});
					var calendarID = eHA.elementToObjectLiteral(element).assetid;
					this.calendarObjects[calendarID] = new calendarObject(element);
				}.bind(this));	
					if($$('waitPanel')){
						$$('waitPanel').each(function(element){
							element.setStyle({display:"none"});
						}.bind(this));	
					}
			}
			else {
				//if is event on any page but Home
				$$("div.vcalendar").each(function(element){
					element.setStyle({overflow:"hidden"});
					var calendarID = eHA.elementToObjectLiteral(element).assetid;
					this.calendarObjects[calendarID] = new calendarObject(element);
				}.bind(this));
			}
			// add SWFAddress listeners
			
			 // EXTERNAL_CHANGE is used for back button
			 SWFAddress.addEventListener(SWFAddressEvent.EXTERNAL_CHANGE, function(event){
					eHA.log.create("SWFAddress external change: "+Object.toJSON(event), 3);
					if(typeof event.pathNames!=="undefined"){
						if(typeof this.calendarObjects[event.pathNames[0]]!=="undefined" && typeof event.parameters!=="undefined"){
							this.calendarObjects[event.pathNames[0]]
							     .readHash({view:event.pathNames[1],startdate:event.pathNames[2],queryParams:event.parameters});
						}
					}
				 }.bind(this));

			 SWFAddress.addEventListener(SWFAddressEvent.INTERNAL_CHANGE, function(event){
					eHA.log.create("SWFAddress internal change: "+Object.toJSON(event), 3);
					if(typeof event.pathNames!=="undefined"){
						if(typeof this.calendarObjects[event.pathNames[0]]!=="undefined" && typeof event.parameters!=="undefined"){
							this.calendarObjects[event.pathNames[0]]
							      .readHash({view:event.pathNames[1],startdate:event.pathNames[2],queryParams:event.parameters});
						}
					}
				 }.bind(this));

			 
			
			 if(typeof SWFAddress.getPathNames()!=="undefined" && typeof SWFAddress.getPathNames()[0]!=="undefined"){
				 //alert('loading...developer working on this section')
				 // explicitly listen for INIT event (this is not necessary if the hash is empty onload)
				 SWFAddress.addEventListener(SWFAddressEvent.INIT, function(event){
						eHA.log.create("SWFAddress init: "+Object.toJSON(event), 3);
						if(typeof event.pathNames!=="undefined"){
							if(typeof this.calendarObjects[event.pathNames[0]]!=="undefined" && typeof event.parameters!=="undefined"){
								this.calendarObjects[event.pathNames[0]]
								    .readHash({view:event.pathNames[1],startdate:event.pathNames[2],queryParams:event.parameters});
							}
						}
					 }.bind(this));
			 }
			 
		}
	},
	maxEventsShown:2,
	dateFormat: "yyyy-MM-dd HH:mm:ss",
	/**
	 * makes sure that rendermode is added to URL
	 * @function
	 * @returns theURL
	 */
	formatURL: function(obj){
		var theURL = obj.properties.url;
		var pageQueryParams = window.location.href.toQueryParams();
		if(typeof pageQueryParams.rendermode!=="undefined"){
			if(theURL.indexOf("?")!==-1){
				var urlQueryParams = theURL.toQueryParams();
				Object.extend(urlQueryParams,{rendermode:pageQueryParams.rendermode});
				theURL = theURL.split("?")[0] +"?"+ Object.toQueryString(urlQueryParams);
			}
			theURL = theURL +"?"+ Object.toQueryString({rendermode:pageQueryParams.rendermode});
		}
		return theURL;
	},
	offsetFunction: function(view){
		var offsetFunction;
		switch(view){
			case "monthView":
				offsetFunction="addMonths";
			break;
			case "weekView":
				offsetFunction="addWeeks";
			break;
			case "dayView":
				offsetFunction="addDays";
			break;
			case "agendaView":
				offsetFunction="addDays";
			break;
		}
		return offsetFunction;
	},
	viewDateFormat: function(view){
		var viewDateFormat;
		switch(view){
			case "monthView":
				viewDateFormat="MMM-yyyy";
			break;
			case "weekView":
				viewDateFormat="MMM-dd-yyyy";
			break;
			case "dayView":
				viewDateFormat="MMM-dd-yyyy";
			break;
			case "agendaView":
				viewDateFormat="MMM-dd-yyyy";
			break;
		}
		return viewDateFormat;
	},
	viewHeaderLabel: function(view){
		var viewDateFormat;
		switch(view){
			case "monthView":
				viewHeaderLabel="Month";
			break;
			case "weekView":
				viewHeaderLabel="Week";
			break;
			case "dayView":
				viewHeaderLabel="Day";
			break;
			case "agendaView":
				viewHeaderLabel="Day";
			break;
		}
		return viewHeaderLabel;
	},
	addNavigationAndHeader: function(obj,view){
		var label = this.viewHeaderLabel(view);
		
		if(typeof obj.properties.showDatesHeader==="undefined" || obj.properties.showDatesHeader==="true"){
			eHA.log.create("calendarModule ("+obj.properties.assetid+").  creating header",3);
			obj.el.insert({top:"<h4 class='datesHeader'></h4>"});
		}
		
		if(typeof obj.properties.showNavigationLinks==="undefined" || obj.properties.showNavigationLinks==="true"){
			eHA.log.create("calendarModule ("+obj.properties.assetid+").  creating navigation",3);
			var previousLink = new Element("a",{'href':''}).update("Previous "+label).observe("click",function(event){
				event.stop();
				var startDate = obj.viewableDateRange.start.clone()[eHA.calendar.offsetFunction(obj.currentView)](-1);
				if(obj.currentView==="monthView"){
					if(obj.viewableDateRange.start.getDate()>1){
						startDate.addMonths(1);
					}
					startDate.moveToFirstDayOfMonth();
				}
				obj.setHash({view:obj.currentView,startdate:startDate});
			}.bind(obj));
			var currentLink = new Element("a",{'href':''}).update("Current "+label).observe("click",function(event){
				event.stop();
				var startDate = Date.today();
				obj.setHash({view:obj.currentView,startdate:startDate});
			}.bind(obj));
			var nextLink = new Element("a",{'href':''}).update("Next "+label).observe("click",function(event){
				event.stop();
				var startDate = obj.viewableDateRange.start.clone()[eHA.calendar.offsetFunction(obj.currentView)](1);
				if(obj.currentView==="monthView"){
					if(obj.viewableDateRange.start.getDate()>1){
						startDate.addMonths(1);
					}
					startDate.moveToFirstDayOfMonth();
				}
				obj.setHash({view:obj.currentView,startdate:startDate});
			}.bind(obj)); 
			
			var previousLI = new Element("li").addClassName("previous").update(previousLink);
			var currentLI = new Element("li").addClassName("current").update(currentLink);
			var nextLI = new Element("li").addClassName("next").update(nextLink);
			
			var navUL = new Element("ul").insert({bottom:previousLI}).insert({bottom:currentLI}).insert({bottom:nextLI});
			var navDiv = new Element("div").addClassName("viewNavigation").update(navUL);
			
			obj.el.insert({top:navDiv});
		}
		
 		return obj;
	},
	duration: 0.2
};
