/*
trumputilities.js
Ben Mueller
May 6, 2008

Mootools-based site-wite utilities

Classes:
TrumpAjax
TrumpUtilities
TrumpFormValidation
TrumpMentors
TrumpCalendar
TrumpSlideshow

*/

/****************** TRUMP AJAX *************************/
var TrumpAjax = new Class({
						  
	options: {
		posturl: null,
		complexeditor: null
	},
	
	
	initialize: function(options) {
		this.setOptions(options); // can be null or undefined
		this.posturl = this.options.posturl;
		this.complexeditor = this.options.complexeditor;
	},
	
	
	send: function(data,obj) {
		if(!obj) { obj = {} }
		if(!obj.onRequest) { obj.onRequest = null; }
	
		var a = new Request ({
				url: this.posturl,
			 	data: data,
			 	method: 'post', 
				onComplete: this.returnhandler.bind(this),
				onRequest: obj.onRequest
			}).send();			
	},
	
	
	formsubmitbasic: function(id,callback,disablep,posturl,submitbtn,submitmsg) {
		
		var ev,e,that,thiscallback;
		
		if(!disablep) {disablep = false;}
		if(!submitbtn) {submitbtn = 'submitbutton';}
		if(!submitmsg) {submitmsg = 'submitmessage';}
		
		this.disablep = disablep;
		this.submitbtn = $(submitbtn);
		this.submitmsg = $(submitmsg);
		this.formid = id;
		
		that = this;

		$(id).addEvent('submit', function (e){
			
			ev = new Event(e).stop();  //stop the actual submit

			if(posturl) {this.setProperty('action',posturl);} //change form action if needed
			
			thiscallback = this.injectInside(setcallback(callback));
			
			if(this.XHRmethod && this.XHRmethod.value !== ''){ //this.XHRmethod should be defined as a field in the form
				this.send({ onRequest: that.disableformbasic.bind(that), onComplete: that.returnhandler.bind(that) });
			}else{
				e = this.errorhandler('','','No XHRmethod defined in form "id"; send aborted');
			}
		});		
	},	
	
	//hmm...not sure this will properly handle multiple periodical requests on a single page
	periodical: function(interval,callback,posturl,formid,complexfields,disablep,submitbtn,submitmsg) {
		
		var a,req, i, thiscallback;

		if(!disablep) {disablep = false;}
		if(!submitbtn) {submitbtn = 'submitbutton';}
		if(!submitmsg) {submitmsg = 'submitmessage';}

		//this.callback = callback;
		this.disablep = disablep;
		this.submitbtn = $(submitbtn);
		this.submitmsg = $(submitmsg);

		if(posturl) {this.posturl = posturl;}

		req = function (){
			var obj = {}; 
			if(formid){ 
				obj = $(formid); 
			}else{
				this.disablep = false; //If there's no form, there's nothing to disable?
			}
			
			thiscallback = obj.injectInside(setcallback(callback));
			
			//set complex form elements
			for(i = 0; i<complexfields.length;i++){
				obj[complexfields[i]].value = this.complexeditor.GetInstance(complexfields[i]).GetXHTML();
			}

			data = obj.toQueryString();

			a = new Request ({
			 	url: this.posturl,
			 	data: data,
			 	method: 'post', 
				onComplete: this.returnhandler.bind(this)
			}).send();		
			
		};
		
		this.currentperiodical = req.periodical(interval,this);
	},
	
	
	disableformbasic: function(){
		if(this.disablep){
			this.submitbtn.disable = true;
			if(this.submitbtn.value === ''){ this.submitbtn.value = 'Submit'; }
			this.submitbtnvalue = this.submitbtn.value;
			this.submitbtn.value = "Submitting...";
			this.submitmsg.innerHTML = "Submitting.  Please wait.";
		}
	},
	
	
	setcallback: function(callback) {
		var el = document.createElement('input');
		el.setProperties({
			type: 'hidden',
			name: 'callback',
			value: callback
		});
		
		return el;
	},
	

	returnhandler: function(responsetext,responsexml) {
	
		//for now, assume we just have text coming back, and verify that it's legal JSON
		var response = this.validateresponse(responsetext,responsexml,true,false), e;

		//this case handles errors at the client level (e.g. JSON validation, etc).  For now, just kill processing, since error handling is in validatereponse()
		if(response.errorp) {
			return false;
		}else{

			//Kill periodical request on error (don't need to call error handler here, since server records its own errors)
			if(response.data.errorp && this.currentperiodical) {$clear(this.currentperiodical);}

			//invoke callback function, even in error state, so that callback can display error message
			if(this[response.data.callback]) {
				this[response.data.callback](response.data);
			
			//general error handler
			}else{
				e = this.errorhandler(responsetext,responsexml,"callback function (" + this.callback + ") not found on client");
			}
		}	
	},
	
	
	/* Validation and Error Handling */
	validateresponse: function(responsetext,responsexml,jsonp,requirecallbackp) {
		var res = {}, e;
		if(requirecallbackp === null) {requirecallbackp = false;}
		res.errorp = false;
		res.errorstring = "";
		res.data = {};
		
		//for now, JSON is the only thing getting validated here
		if(!jsonp){
			res.errorp = true;
			res.errorstring = "validateresponse() expects JSON";
			e = this.errorhandler(responsetext,responsexml,res.errorstring);	
			return res;
		}
		
		if(!responsetext) {
			res.errorp = true;
			res.errorstring = 'responsetext not defined when returned from server.  a timing error?';
			
			if(!responsexml) {
				res.errorstring += 'Responsexml not defined, either.';
				resxml = '';
			} else {
				resxml = responsexml;
			}
			
			e = this.errorhandler('',resxml,res.errorstring);	
			return res;
		}
		
		responsetext = responsetext.trim();
		
		if(responsetext.length === 0){
			res.errorp = true;
			res.errorstring = 'No data returned from server';
			e = this.errorhandler(responsetext,responsexml,res.errorstring);	
			return res;		
		}
		
		res.data = JSON.decode(responsetext,true);
		
		if(res.data === null){
			res.errorp = true;
			res.errorstring = 'Invalid JSON returned';
			e = this.errorhandler(responsetext,responsexml,res.errorstring);
			return res;
		}		
		
		return res;
	},
	
	
	errorhandler: function(responsetext,responsexml,message,posturl) {

		var obj = $H();
		if(!posturl) {posturl = this.posturl;}
		obj.XHRmethod = "errorhandler";
		obj.message = message;
		obj.responsetext = responsetext;
		obj.responsexml = responsexml;
		
		//Stop any running periodical requests
		if(this.currentperiodical) { $clear(this.currentperiodical); }

		//ignore any feedback from the server for this	
		var a = new Request ({
				url: posturl,
			 	data: obj,
			 	method: 'post'
			}).send();			
	},
	
	
	createformelement: function(el,type,name,value){
		return new Element(el, {
			'type': type,
			'name': name,
			'value': value
		});
	},
  
  
	/* Callback functions */
  	formsavedcallbackbasic: function(data) {

		if(this.disablep){
			this.submitbtn.value = this.submitbtnvalue;
			this.submitbtn.disabled = false;
			this.submitmsg.innerHTML = "Success!";
		}
	}

});

TrumpAjax.implement(new Options, new Events);



/****************** TRUMP UTILITIES *************************/
var TrumpUtilities = new Class({

	options: {},
	
	initialize: function(options) {
		this.setOptions(options); // can be null or undefined
		this.rollover();
		this.numbersonly();
		this.clearinputdefault();
	},
	

	rollover: function(){
		$$('img.mooroll, input.mooroll').each(function(img) {
			var src = img.getProperty('src');
			var extension = src.substring(src.lastIndexOf('.'),src.length)
			img.addEvent('mouseenter', function() { img.setProperty('src',src.replace(extension,'_ro' + extension)); });
			img.addEvent('mouseleave', function() { img.setProperty('src',src); });
		});
	},


	numbersonly: function(){

		$$('input.numbersonly').each(function(obj) {
			obj.addEvent('keypress', function(e) {
				var ev = new Event(e);
				if (  ("0123456789").indexOf(ev.key) > -1  ) { 
					//numbers
				} else if ( (ev.code === null) || (ev.code === 0) || (ev.code === 8) || (ev.code === 9) || (ev.code === 13) || (ev.code === 27) ) { 
					//control keys, these are okay
				} else {
					ev.stop();
					alert('Numbers only, please.');
				}
			});
		});
	},
	
	
	clearinputdefault: function(){
		// For now, assume a handful of standard default values
		$$('input.clearinput').each(function(obj) {
			obj.addEvent('focus', clear.bind(obj));
			obj.addEvent('blur', clear.bind(obj));
		});
		
		function clear(){
			if (this.value === "Enter zip code"
			 || this.value === "Enter Zip"
			 || this.value === "Enter your email"
			 || this.value === "REQUIRED") { 
				this.value = ''
				this.setStyle('color','black');
			};
		}
	}

});

TrumpUtilities.implement(new Options, new Events);



/****************** TRUMP FORM VALIDATION  *************************/
// Very loosely based on cnet.com's form.validator.js routines
var TrumpFormValidate = new Class({

	options: {},
	
	initialize: function(options) {
		var that = this;
		this.setOptions(options); // can be null or undefined
		
		$$('form.validate').each(function(obj){

			obj.addEvent('submit',that.onsubmit.bind(obj));
		});
		
	},

	onsubmit: function(e){
		var ev = new Event(e);
		var submitbtn = this.getElement('input.submit');
		var label,that=this;
		submitbtn.setProperty('disabled','true');
		
		this.getElements('input.required').each(function(el){
			if(el.value === '' || el.value === 'REQUIRED' || el.value === 'Enter your email' || el.value === 'Enter zip code') {
				ev.stop();
				el.value = 'REQUIRED';
				el.setStyle('color','red');
				label = that.getElement('label[for=' + el.id + ']');
				if(label){
					label.setStyle('color','red');
				}
				submitbtn.removeProperty('disabled');
			}
		});
	}
});

TrumpFormValidate.implement(new Options, new Events);



/************************* TRUMP PEOPLE GALLERY ************************/
var TrumpPeopleGallery = new Class({

	options: {
		people: [],  //required elements for each person: pos (numeric), firstname, lastname, bio
		instructions: 'instructions',
		profilecontainer: 'profilecontainer',
		activeperson: 'activeperson',
		gallerythumb: 'gallerythumb',
		peoplegallery: 'peoplegallery',
		imgbasepath: ''
	},
	
	initialize: function(options) {
		var personimg,ev,personimgname,that = this;
		
		this.setOptions(options); // can be null or undefined
		this.profilecontainer = $(this.options.profilecontainer);
		this.activeperson = $(this.options.activeperson);
		this.instructions = $(this.options.instructions);
		this.peoplegallery = $(this.options.peoplegallery);
		
		this.buildgallery();
		
		this.activategallery();
		
	},
	
	buildgallery: function() {
		var gcontainer,a,img,thumbtitle,clearer,that=this;
		this.options.people.each( function(person) {
			gcontainer = new Element('div', {'class': 'thumbcontainer'});
			a = new Element('a', {'href': '#', 'id': 'gallerythumb' + person.pos}).inject(gcontainer);
			img = new Element('img', { 'class': 'gallerythumb', 'src': that.options.imgbasepath + person.image, 'alt': person.firstname + ' ' + person.lastname}).inject(a);
			thumbtitle = new Element ('div', {'class': 'thumbtitle'}).set('html',person.firstname + ' ' + person.lastname).inject(a,'after');
			gcontainer.inject(that.peoplegallery);
		},this);
		
		clearer = new Element('div',{'class': 'clearer'}).inject(this.peoplegallery);
		
	},
	
	activategallery: function() {
		var gallerythumb,that=this;
		this.options.people.each (function(person){
			gallerythumb = $(that.options.gallerythumb + person.pos);
			if(gallerythumb){
				gallerythumb.addEvent('click',function(e){
					var ev = new Event(e).stop();
					that.profilecontainer.set( 'html',person.bio.clean() );
					that.activeperson.src = that.options.imgbasepath + person.image;
					that.instructions.set('html',person.firstname + ' ' + person.lastname);
				},this);	
			}		
		});
	}
});

TrumpPeopleGallery.implement(new Options, new Events);



/************************* TRUMP CALENDAR ************************/
var TrumpCalendar = new Class({

	options: {
		container: 'calendarcontainer',
		calendarclass: 'cal',
		calendartitle: '',
		showtimeinsubjectp: true,
		showlegend: true,
		events: [],
		labels: [{keyword: 'default',name: 'Default', color: 'blue'},
 			         {keyword: 'label1',name: 'Label 1', color: 'blue'},
 			         {keyword: 'label2',name: 'Label 2', color: 'red'},
 			         {keyword: 'label3',name: 'Label 3', color: 'green'},
 			         {keyword: 'label4',name: 'Label 4', color: 'purple'},
 			         {keyword: 'label5',name: 'Label 5', color: 'orange'}
 			        ],
		maxcharstodisplay: {'eventsubject_month' : 16}
	},
	
	
	initialize: function(options) {
		this.setOptions(options);
		this.constants = {
			daysperweek: 7,
			days: ['Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday'],
			months: [
				{name: 'January', days: 31, leapmonthp: false},
				{name: 'February', days: 28, leapmonthp: true, leapdays:29},
				{name: 'March', days: 31, leapmonthp: false},
				{name: 'April', days: 30, leapmonthp: false},
				{name: 'May', days: 31, leapmonthp: false},
				{name: 'June', days: 30, leapmonthp: false},
				{name: 'July', days: 31, leapmonthp: false},
				{name: 'August', days: 31, leapmonthp: false},
				{name: 'September', days: 30, leapmonthp: false},
				{name: 'October', days: 31, leapmonthp: false},
				{name: 'November', days: 30, leapmonthp: false},
				{name: 'December', days: 31, leapmonthp: false}
			]
		};
		
		this.container = $(this.options.container);
		
		this.today = this.setdateinfo(new Date());
		this.current = this.today;
		this.nextmonth = this.setnextmonth();
		this.prevmonth = this.setprevmonth();
		
		this.visible = {
			years: $H()
		}
		
		
		this.events =  $H();
		this.events.set(this.today.year,$H());
		if(this.options.events.length) {
			this.addevents(this.options.events,false);
		}		
				
		this.writecal = {
			currentmonthstartp: false,
			currentmonthendp: false
		};
			
		//write out the initial display
		if(this.container) {
			this.writemonth(this.current);
		}
	},
	
	
	setdateinfo: function (d){
		return {
			date: d,
			hourmilitary: d.getHours(),
			hour: d.getHours() % 12 || 12,
			meridium: d.getHours() < 12 ? 'a' : 'p',
			dayofweek: d.getDay(),
			dayofmonth: d.getDate(),
			dayofyear: d.getdayofyear(),
			dayasstring: this.constants.days[d.getDay()],
			daysinmonth: this.daysinmonth(d),
			month: d.getMonth(),
			monthasstring: this.constants.months[d.getMonth()].name,
			leapmonthp: this.constants.months[d.getMonth()].leapmonthp,
			year: d.getFullYear(),
			leapyearp: this.isleapyear(d.getFullYear())
		};
	},
	
	
	daysinmonth: function(d){
		if( this.isleapyear(d.getFullYear()) && this.constants.months[d.getMonth()].leapmonthp ){
			return this.constants.months[d.getMonth()].leapdays;
		} else {
			return this.constants.months[d.getMonth()].days;
		}
	},
	
	
	
	isleapyear: function(year) { //swiped from moodate.js Roland Poulter, <dnalorATmoomonthDOTcom>
	  var is_leap = year % 4, is_century = year % 1000;
	  return (is_leap === 0 && is_century !== 0) ? true : false;
	},	
	
	
	writemonth: function(current){
		var wk,i,first,month,monthheader,monthbody,monthfooter,writeweekp=true,that = this,numdays,tmp,tmp1,tmp2,tmp3,tmp4,tmp5,tmp6;
		
		first = this.setdateinfo(new Date(current.year,current.month,1));
		
		month = new Element('table', {'class': this.options.calendarclass + ' month', 'id': 'month'});
		
		this.visible.years.empty();

		// write month header
		monthheader = new Element('thead').injectInside(month);
		tmp = new Element("tr", {"class": 'monthheader'}).injectInside(monthheader);
		tmp1 = new Element('th', {'colspan': '3'}).injectInside(tmp); 	
		tmp2 = new Element('h2').injectInside(tmp1);
		tmp3 = new Element('a', {href: '#', id: 'goto-prev-month'}).set('html','&laquo;').injectInside(tmp2);
		tmp4 = new Element('a', {href: '#', id: 'goto-next-month'}).set('html','&raquo;').injectInside(tmp2);		
		tmp5 = new Element('a', {href: '#', id: 'goto-today'}).set('text','today').injectInside(tmp2);		
		tmp6 = new Element('span').set('text',current.monthasstring + ' ' + current.year).injectInside(tmp2);		
		
		if (this.options.calendartitle.length > 0) {
			tmp1 = new Element('th', {'colspan': '4','style': 'text-align:right;'}).injectInside(tmp);
			tmp2 = new Element('h1').set('html',this.options.calendartitle).injectInside(tmp1);
		}
		weekheader = new Element('tr', {'class': 'weekheader'} ).injectInside(monthheader);
		for(i=0;i<this.constants.days.length;i++){
			tmp = new Element('td',{'class': 'weekheaderday ' + this.constants.days[i].toLowerCase()}).set('html',this.constants.days[i]).injectInside(weekheader);	
		}
				
		/* write month body */
		monthbody = new Element('tbody').injectInside(month);

		while(writeweekp) {
			wk = this.writeweek(first);
			wk.obj.injectInside(monthbody);
			
			if(wk.nextstartday <= current.daysinmonth){
				writeweekp = true;
				first = this.setdateinfo(new Date(current.year,current.month,wk.nextstartday));	
			}else{
				writeweekp = false;
			}			
		}
		
		//write month footer		
		monthfooter = new Element('tfoot').injectInside(month)
		tmp = new Element('tr', {'class': 'monthfooter'}).injectInside(monthfooter);
		tmp1 = new Element('th', {'colspan': '7'}).injectInside(tmp);
		
		if (this.options.showlegendp) {
			legend = new Element('div', {'class': 'legend'}).injectInside(tmp1);
			tmp2 = new Element('div', {'style': "font-weight:bold;color:#000000;text-align:right;"}).set('text','Legend').injectInside(legend);
			for(i=0;i<this.options.labels.length;i++){
				tmp = new Element('div', {'class': this.options.labels[i].keyword.toLowerCase()}).set('text',this.options.labels[i].name).injectInside(legend);	
			}
		}
		
		//Set dates
		this.current = current;
		this.setnextmonth();
		this.setprevmonth();		

		
		//Write out month
		this.container.empty();
		month.injectInside(this.container);


		// Activate nav links
		$('goto-next-month').addEvent('click',function(e){
			var ev = new Event(e).stop();
			that.writemonth(that.nextmonth);
		});
		
		$('goto-prev-month').addEvent('click',function(e){
			var ev = new Event(e).stop();
			that.writemonth(that.prevmonth);
		});

		$('goto-today').addEvent('click',function(e){
			var ev = new Event(e).stop();
			that.writemonth(that.today);
		});

		//Write out events to month calendar		
		this.displayevents();
	},
	

	
	writeweek: function(start) {
		var a,b,i,day,week,currentday;
		var d = 0;
		
		week = new Element("tr", {"class": "week"});
		
		for(i=0;i<this.constants.days.length;i++) {
			if ( start.dayofmonth === 1 ) {
				if ( start.dayofweek > i ) {
					currentday = this.setdateinfo(new Date(start.year,start.month,1-start.dayofweek+i));
					day = this.writeday(currentday,'prevmonth').injectInside(week);
				} else {
					currentday = this.setdateinfo(new Date(start.year,start.month,start.dayofmonth + d));
					day = this.writeday(currentday).injectInside(week);
					d++;				
				}
			} else {
				currentday = this.setdateinfo(new Date(start.year,start.month,start.dayofmonth + d));
				if (start.dayofmonth + d > start.daysinmonth) {
					day = this.writeday(currentday,'nextmonth').injectInside(week);
				} else {
					day = this.writeday(currentday).injectInside(week);
				}
				
				d++;					
			}
		}
		
		return {obj: week, nextstartday: start.dayofmonth + d};
		
	},

	
	writeday: function(d,cssclass){
		
		if(!$defined(cssclass)) {cssclass = '';}
		if ( (this.today.year === d.year) && (this.today.dayofyear === d.dayofyear)) {
			cssclass += ' today';
		}
		
		var day = new Element('td', { 'id': 'day-' + d.year + '-' + d.dayofyear, 'class': 'day ' + this.constants.days[d.dayofweek].toLowerCase() + ' ' + cssclass});
		var dayhead = new Element('div', { 'class': 'dayhead'}).set('html',d.dayofmonth).injectInside(day); 
		var daybody = new Element('div', { 'class': 'daybody'}).injectInside(day); 
		var eventdivider = new Element('div', {'class': 'eventdivider'}).injectInside(daybody);
		
		//update visible days
		if(!this.visible.years.has(d.year)){ this.visible.years.set(d.year,[]); }
		this.visible.years.get(d.year).include(d.dayofyear);
		
		return day;
	},
	
	
	setnextmonth: function(){
		this.nextmonth = this.setdateinfo(new Date(this.current.year,this.current.month+1,1));
	},
	
	
	setprevmonth: function(){
		this.prevmonth = this.setdateinfo(new Date(this.current.year,this.current.month-1,1));	
	},
	
	
	/******************* Calendar Events ************************/
	
	// Adds a single event to the "this.events" object (technically, a Mootools hash), and optionally displays
	addevent: function(d,displayp){

		var eventcontainer,day,daybody,daysapart,i;
		var eventdata = {
			'data': d,
			'startdatetime': this.setdateinfo(new Date(d.startdatetime)),
			'enddatetime': this.setdateinfo(new Date(d.enddatetime)),
			'id': this.generateuniqueid(),
			'multidayp': false,
			'daysofyear': []
		}

		if(displayp === null) { displayp = true; }
		
		if (eventdata.startdatetime.dayofyear != eventdata.enddatetime.dayofyear) {
			eventdata.multidayp = true;
			var daysapart = Math.abs(Math.round((eventdata.startdatetime.date-eventdata.enddatetime.date)/86400000));
			for (i=0;i<=daysapart;i++) {
				eventdata.daysofyear[eventdata.daysofyear.length] = eventdata.startdatetime.dayofyear + i;	
			}
		} else {
			eventdata.daysofyear[eventdata.daysofyear.length] = eventdata.startdatetime.dayofyear;
		}
		
			
		if(!this.events.has(eventdata.startdatetime.year)) { this.events.set(eventdata.startdatetime.year,$H()); }
		if(!this.events.get(eventdata.startdatetime.year).has(eventdata.startdatetime.dayofyear)) { this.events.get(eventdata.startdatetime.year).set(eventdata.startdatetime.dayofyear,[]); }

		this.events.get(eventdata.startdatetime.year).get(eventdata.startdatetime.dayofyear)[this.events.get(eventdata.startdatetime.year).get(eventdata.startdatetime.dayofyear).length] = eventdata;
		
		if (displayp) {
			this.displayevent(eventdata);
		}
	
	},
	
	
	
	// Adds an array of events to the "this.events" object, and optionally displays
	addevents: function (a,displayp) {
		var i;
		if(displayp === null) { displayp = true; }
		for(i=0;i<a.length;i++) {
			this.addevent(a[i],displayp);
		}
	},
	
	
	// Displays the given event on the calendar, assuming the associated day is currently shown
	displayevent: function(eventdata) {
		var i,day, daybody,eventdivider,label,subject,eventbody,a,e,el,tmp,tmp1,that=this;

		// Compile event data for display
		label = (eventdata.data['label']) ? eventdata.data['label'] : 'default';
		label = (eventdata.multidayp) ? label + ' multiday' : label;
		subject = (this.options.showtimeinsubjectp) ? eventdata.startdatetime.hour + eventdata.startdatetime.meridium + '-' + eventdata.enddatetime.hour + eventdata.enddatetime.meridium + ': ' + eventdata.data.subject : eventdata.data.subject;
		if (subject.length > this.options.maxcharstodisplay.eventsubject_month){
			subject = subject.substring(0,this.options.maxcharstodisplay.eventsubject_month) + '...';
		}
		
		//write out event; for multi-day events, write it out on all the days on which it appears
		for(i=0;i<eventdata.daysofyear.length;i++) {
			day = $('day-' + eventdata.startdatetime.year + '-' + eventdata.daysofyear[i]);
			if (day) {
				eventbody = new Element('div', { 'class': 'event ' + label});
				a = new Element("a", {'href': '#', 'class': eventdata.id + ' eventdetail eventlink', 'rel': eventdata.id}).set('html',subject).injectInside(eventbody);	
				daybody = day.getElement('div[class=daybody]');
				eventdivider = daybody.getElement('div[class=eventdivider]');
				if(eventdivider){ 
					if(eventdata.multidayp) {
						eventbody.injectBefore(eventdivider);
					} else {
						eventbody.injectAfter(eventdivider);
					}
				}
			}	
		}
		

		/* activate links */
		$$('a.' + eventdata.id).each(function(a) {
			a.addEvent('click', function(e) {
				var ev = new Event(e).stop();
				that.showeventdetails(this.getProperty('rel'));
			});
		});
	},
	
	
	// Displays events from the "this.events" object
	displayevents: function () {
		var d,i,y,that=this,years,currentyeardate,currentyeardata,days,dayevents;
		
		years = this.events.getKeys().sort ( function(a,b) {return a-b} );
		
		for(y=0;y<years.length;y++){
			currentyeardate = years[y] * 1;
			if (this.visible.years.has(currentyeardate)) {
				currentyeardata = this.events.get(currentyeardate);
				days = this.events.get(currentyeardate).getKeys().sort( function(a,b) {return a-b; } );
				for(d=0;d<days.length;d++) {
					if (this.visible.years.get(currentyeardate).contains(days[d] * 1)) {
						dayevents = currentyeardata.get(days[d]);
						for(i=0;i<dayevents.length;i++) {
							that.displayevent(dayevents[i]);
						}
					}	
				}
			}
		}
		

		
		//change style of multi-day events
		$$('div.multiday a').each(function(el) {
			tmp = el.getStyle('color');
			el.setStyles({'color': '#ffffff', 'background-color': tmp,'margin-left':'0px','margin-right':'0px'});
		});	
		
	},
	
	
	showeventdetails: function(id) {
		
		var i,j,el,lab,ev,evt,head,controls,tmp,subject,that=this;

		this.events.each(function(year) {
			
			year.each( function(dayofyear) {
				
				for (i=0;i<dayofyear.length;i++) {
					ev = dayofyear[i];
					if(ev.id === id) {
						el = new Element('div', { 'id': 'eventdetail_' + id, 'class': 'eventdetail'});
						lab = new Element('div', {'class': ev.data.label}).injectInside(el);
						if (that.options.showtimeinsubjectp) {
							subject = ev.startdatetime.hour + ev.startdatetime.meridium + '-' + ev.enddatetime.hour + ev.enddatetime.meridium + ': ' + ev.data.subject;
						} else {
							subject = ev.data.subject;
						}						
						head = new Element('h3', {'class': 'eventheader'}).set('html','Event Detail: ' + subject).injectInside(lab); 
						controls = new Element('div', {'class': 'eventcontrols'}).injectInside(lab);
						tmp = new Element('a', {'href': '#'}).set('html','&laquo; back to calendar').injectInside(controls);
						tmp.addEvent('click', function(e) {
							evt = new Event(e).stop();
							that.writemonth(that.current);
						});	

						if(ev.data.controls) {
							for(j=0;j<ev.data.controls.length;j++){
								tmp = new Element('a', {'href': ev.data.controls[j].link}).set('html',ev.data.controls[j].text).injectInside(controls);
							}
						}
						
						tmp = new Element('div', {'class': 'eventbody'}).set('html',ev.data.description).injectInside(lab);
						
						that.container.empty()
						el.injectInside(that.container);
					}
				}
			});
		});
	},
	
	
	/*********** Calendar Utilities *********/
	/* Generate a number that's close enough to unique for our purposes (it tries to create a GUID) */
	generateuniqueid: function () {
		var result, i, j;
		result = 'id_';
		for (j=0; j<32; j++) {
			if( j == 8 || j == 12|| j == 16|| j == 20)
			result = result + '-';
			i = Math.floor(Math.random()*16).toString(16).toUpperCase();
			result = result + i;
		}
		return result;
	}

	
	
});

TrumpCalendar.implement(new Options, new Events);



// http://davidwalsh.name/array-shuffling-mootools
Array.implement({
	shuffle: function() {
		for (var j, x, i = this.length; i; j = parseInt(Math.random() * i), x = this[--i], this[i] = this[j], this[j] = x);
		return this;
	}
});



/************************************** TRUMP SLIDESHOW ****************************************/

var TrumpSlideshow = new Class({
						  
	options: {
		container: null,
		slides: [],
		randomizep: false,
		iterations: 3, // 0 for continuous loop
		delay: 2000,
		fxduration: 500,
		fxmin: 0,
		fxmax: 1
	},
	
	
	initialize: function(options) {
		
		var that = this;
		
		this.setOptions(options); // can be null or undefined
		this.slides = [];
		this.fxs = [];
		this.currentslideindex = 0;
		this.iteration = 1;  //1-based index
		this.container = $(this.options.container);
		this.endp = false;
		this.runningp = true;
		this.fadingp = false;
		this.mode;
		if (!this.container) {return false;}  // if container can't be found, abort
		
		window.addEvent('unload', function (){ //not sure I really need this, but maybe it's safest?
			that.container.destroy();
		})
	
	
		if (this.options.randomizep) {
			this.options.slides.shuffle();
		}
		
		this.addslides(this.options.slides);
		
		this.mode = 'show';
		this.fxs[0].set('opacity',this.options.fxmax); //IE seems to need this explicitly set here
		this.fxs[0].set('display','block');		
		
		this.controller();	

	},

	
	addslides: function(slides) {
		
		var that = this;
		
		slides.each( function(slide) {
			
			var fx = new Fx.Tween(slide, {
				property: 'opacity',
				duration: that.options.fxduration
			});
			
			fx.addEvent('onStart', that.startlistener.bind(that));
			fx.addEvent('onComplete', that.controller.bind(that));
			
			that.slides[that.slides.length] = slide;
			that.fxs[that.fxs.length] = fx;
			
			slide.inject(that.container);
			
		});
	},
	
	
	showslide: function (index) {

		if (this.slides[index]) {
			
			this.mode = 'show';
			
			// really "hide" the previous slide to ensure display works correctly (maybe there's a better way to handle this?)
			if(this.slides[index-1]) {
				this.fxs[index-1].set('display','none');
			}
			
			this.fxs[index].set('opacity',this.options.fxmin); //IE seems to need this explicitly set here
			this.fxs[index].set('display','block');
			this.fxs[index].start(this.options.fxmin,this.options.fxmax);
		}
	},
	
	
	hideslide: function(index) {	
		
		if ( this.slides[index] ) {
			this.mode = 'hide';
			this.fxs[index].start(this.options.fxmax,this.options.fxmin);
		}
	},
	
	
	startlistener: function(e) {
		this.fading = true;
	},
	
	
	controller: function () {

		this.fading = false;		
		
		//handle counter; only increment when hide is done, or on show of very last slide
		if (this.mode === 'hide') {
			if(this.slides.length-1 === this.currentslideindex) { // last slide (not sure if I need this here now)
				if ( (this.options.iterations === 0) || this.iteration < this.options.iterations) {
					this.currentslideindex = 0;
					this.iteration ++;
				} else {
					this.endp = true;
					this.currentslideindex++; // count past the array	
				}
			} else {
				this.currentslideindex++;
			}
		} else if (this.mode === 'show') {
			if(this.slides.length-1 === this.currentslideindex) { // last slide
				if ( (this.options.iterations > 0) && this.iteration === this.options.iterations) {
					this.endp = true;
				}
			}
		}
		
		//determine whether to show or hide
		if(this.currentslideindex < this.slides.length ) {
			if (this.mode == 'show') {
				if(this.endp === false) { //don't hide the last slide
					this.hideslide.delay(this.options.delay,this,this.currentslideindex);
				}
			} else if (this.mode == 'hide') {
				this.showslide (this.currentslideindex);
			} else {
				this.showslide (this.currentslideindex);			
			}
		}
	}
	
	
});

TrumpSlideshow.implement(new Options, new Events);





/************************* Date function ***************************************/

Date.prototype.getdayofyear = function()
{
    var year = this.getFullYear();
    var dayOfYear = this.getDate()-1;
    var month = this.getMonth();
    
    while(month>0)
    {
        var lastDayOfPreviousMonth = new Date(year,month,0);
        dayOfYear += lastDayOfPreviousMonth.getDate();
        month--;
    }
    return dayOfYear;
};




// Activate some of these classes here (so they're always on)
window.addEvent('domready', function() {
	var UTILS = new TrumpUtilities();
	var FORMVALIDATE = new TrumpFormValidate();
});