// required: mootools more with Date, Element.Measure, Element.Position
var Calendar = new Class({
    options: {
		id: null,
		datasource: null,
		container: null,
		months: [ "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" ],
		days_of_week: [ "S", "M", "T", "W", "T", "F", "S" ],
		min_height: 175,
		link_path: null
    },

	initialize: function(options) {
		this.setOptions(options);
		
		this.container = $(this.options.container);
		this.calendar = null;
		this.titlebar = null;
		this.tbody = null;

		this.date = new Date().set("date", 1).clearTime();
		this.today = new Date().clearTime();
		this.range = {
			start_date: null,
			end_date: null
		};
		
		this.events = [];
		
		this.build();
		this.get_events();
	},
	
	build: function() {
		var controller = this;

		this.calendar = new Element("div", {
			"class": "calendar"
		}).inject(this.container);
		
		var header = new Element("div", {
			"class": "calendar-header"
		}).inject(this.calendar);
		
		this.titlebar = new Element("h4").inject(header);
		
		var link_next = new Element("a", {
			"class": "calendar-next",
			"events": {
				"click": function() {
					controller.next_month();
				}
			}
		}).inject(header);
		
		var link_prev = new Element("a", {
			"class": "calendar-prev",
			"events": {
				"click": function() {
					controller.prev_month();
				}
			}
		}).inject(header);
		
		var clear_div = new Element("div", {
			"html": "<!-- // -->",
			"styles": {
				"clear": "both"
			}
		}).inject(header);
		
		var table = new Element("table", {
			"cellpadding": "0",
			"cellspacing": "0"
		}).inject(this.calendar);
		this.tbody = new Element("tbody").inject(table);
		
		var tr = new Element("tr", { "class": "days-of-week" }).inject(this.tbody);
		
		for (var x = 0; x < this.options.days_of_week.length; x++) {
			var th = new Element("th", { "html": this.options.days_of_week[x] }).inject(tr);
		}
	},

	set_range: function() {
		this.range.start_date = new Date(this.date).decrement("day", this.date.getDay());
		
		var end = new Date(this.date);
		var offset = end.set("date", end.get("lastdayofmonth")).getDay();

		if (offset == 6) { // last day of the month is on a Saturday; so the last day of the current month is the end of our range
			this.range.end_date = end;
		} else {
			this.range.end_date = end.increment("day", 6 - offset);
		}
		//alert(this.range.start_date + "\n" + this.range.end_date);
	},
	
	next_month: function() {
		this.date.increment("month");
		this.get_events();
	},
	
	prev_month: function() {
		this.date.decrement("month");
		this.get_events();
	},
	
	get_events: function() {
		var height = this.calendar.getSize().y;
		if (height < this.options.min_height) height = this.options.min_height;
		this.calendar.setStyle("height", height + "px");
		
		$each(this.tbody.getElements("tr"), function(tr) {
			if (!tr.hasClass("days-of-week")) tr.dispose();
		});
		
		this.container.addClass("loading");

		this.set_range();
		
		var pars = "method=calendar&startdate=" + encodeURIComponent(this.range.start_date.format("%x")) + "&enddate=" + encodeURIComponent(this.range.end_date.format("%x"));

		var success_fn = this.got_events.bind(this);
		var req = new Request({
			url: this.options.datasource,
			data: pars,
			onSuccess: success_fn
		}).send();
	},
	
	got_events: function(request) {
		r = JSON.decode(request);
		
		this.calendar.setStyle("height", "auto");
		this.container.removeClass("loading");
		
		this.events = [];
		for (var x = 0; x < r.ROWCOUNT; x++) {
			this.events.push({
				"id": r.DATA.UID[x],
				"title": r.DATA.TITLE[x],
				"datetime": r.DATA.STARTDATETIME[x],
				"time_tbd": r.DATA.TIME_TBD[x],
				"type": r.DATA.HEARING_TYPE[x],
				"location": r.DATA.LOCATION[x]
			});
		}
		
		this.render();
	},

	render: function() {		
		this.titlebar.innerHTML = this.options.months[this.date.getMonth()] + " " + this.date.getFullYear();
		
		var rowcount = 0;
		var current_month = this.date.getMonth();
		var loop_date = new Date(this.range.start_date);
		var tr = new Element("tr").inject(this.tbody);
		var td = null;
		
		while (loop_date <= this.range.end_date) {
			td = new Element("td").inject(tr);
			var date_container = new Element("div", { "class": "date-container", "html": loop_date.getDate() }).inject(td);

			var loop_month = loop_date.getMonth();
			if (loop_month < current_month) { 
				td.addClass("prev-month");
			} else if (loop_month > current_month) { 
				td.addClass("next-month"); 
			}
			
			//if (loop_date.diff(this.today) == 0) {
			if ((loop_date.get("month") == this.today.get("month")) && (loop_date.get("date") == this.today.get("date")) && (loop_date.get("year") == this.today.get("year"))) {
				td.addClass("today");
			}
			
			var events = [];
			for (var x = 0; x < this.events.length; x++) {
				var event_date = new Date(this.events[x].datetime);
				if ((loop_date.get("month") == event_date.get("month")) && (loop_date.get("date") == event_date.get("date")) && (loop_date.get("year") == event_date.get("year"))) {
					events.push(this.events[x]);
				}
			}
			
			if (events.length > 0) {
				//this.do_tip(td, loop_date, events);
				td.store("storage", { date: new Date(loop_date), events: events });
			}
			
			if (loop_date.getDay() == 6 && loop_date < this.range.end_date) {
				td.addClass("last");
				tr = new Element("tr").inject(this.tbody);
				if (++rowcount % 2 != 0) tr.addClass("alt");
			}
			loop_date.increment("day");
		}

		tr.addClass("last");
		td.addClass("last");
		
		this.do_events();
	},
	
	/* moved this to a separate call because the tooltips were mis-positioning when they were being assinged as the table was being built */
	do_events: function() {
		var controller = this;
		$each(this.tbody.getElements("td"), function(td) {
			var storage = td.retrieve("storage");
			if ($chk(storage)) {
				controller.do_tip(td, storage.date, storage.events);
			}
		});
	},
	
	do_tip: function(td, date, events) {
		var controller = this;

		td.addClass("has-events");
		
		var events_string = "<h5>" + date.format("%B %d, %Y") + "</h5>";

		$each(events, function(e, index) {
			var type = "[ No Type Specified ]";
			if (e.type == "full") {
				type = "Full Committee Hearing"
			} else if (e.type == "sub") {
				type = "Subcommittee Hearing";
			} else if (e.type == "field") {
				type = "Field Hearing";
			} else if (e.type == "executive") {
				type = "Executive Session";
			}
			
			events_string += "<h6>" + type + "</h6>";
			events_string += "<p>";
			events_string += "<a href='" + controller.options.link_path + e.id + "'>" + e.title + "</a><br />";
			events_string += "Location: " + e.location + "<br />";
			events_string += "Time: " + (e.time_tbd == 1 ? "TBD" : new Date(e.datetime).format("%I:%M %p"));
			events_string += "</p>";
			
			if (index != events.length - 1) events_string += "<hr />";
		});

		var tip = new Element("div", { "class": "tip" }).inject(td);
		var tip_content = new Element("div", {
			"html": events_string,
			"class": "tip-content"
		}).inject(tip);
		
		var size = tip.measure(function(){ return this.getSize(); });
		var x_offset = Math.ceil(td.getSize().x / 4);
		var y_offset = Math.ceil(size.y / 2);

		tip.position({
			relativeTo: td,
			position: "centerRight",
			offset: { x: -x_offset, y: -y_offset }
		});
		
		td.addEvents({
			"mouseover": function() { this.addClass("over"); },
			"mouseout": function() { this.removeClass("over"); }
		});
	}
});

Calendar.implement(new Options);

