if (!Array.prototype.indexOf)
{
	Array.prototype.indexOf = function(elt /*, from*/)
	{
		var len = this.length;
		
		var from = Number(arguments[1]) || 0;
		from = (from < 0)
			? Math.ceil(from)
			: Math.floor(from);
		if (from < 0)
		from += len;
		
		for (; from < len; from++)
		{
			if (from in this &&
				this[from] === elt)
			return from;
		}
		return -1;
	};
}

if (!Array.prototype.remove)
{
	Array.prototype.remove = function(value)
	{
		var retval = new Array();
		for(var i = 0; i < this.length; i++)
			if(this[i] != value)
				retval.push(this[i]);
				
		return retval;
	};
}

// Associative "array" linking day codes to their ordinal number
var dayarray = Object();
dayarray['M'] = 0;
dayarray['T'] = 1;
dayarray['W'] = 2;
dayarray['R'] = 3;
dayarray['F'] = 4;
dayarray['S'] = 5;
dayarray['U'] = 6;

// array of currently existing courses
var currentCourses = [];

// course constructor
function Course(courseinfo)
{
	this.Saved = false;
	this.Focused = false;
	this.CourseInfo = courseinfo;
	this.Meetings = [];
	
	this.Call = courseinfo.getAttribute("CallNumber");
	this.Code = courseinfo.getAttribute("Section");
	this.Name = courseinfo.getAttribute("Title");
	this.Term = courseinfo.getAttribute("Term");
	this.Instructor = courseinfo.getAttribute("Instructor1");	

	// build session objects based on the sessions included in the xml
	var meetings = courseinfo.getElementsByTagName("Meeting");
	for(var meeting = 0; meeting < meetings.length; ++meeting)
	{
		days = meetings[meeting].getAttribute('Day');
		
		for(var day = 0; day < days.length; ++day)
		{
			var daychar = days.charAt(day);
			var daynum = dayarray[daychar];
			
			var begins = meetings[meeting].getAttribute('StartTime');
			if(begins == null)
				continue;
			begins = begins.split(':');
			var ends = meetings[meeting].getAttribute('EndTime').split(':');
			
			// TODO: Create a drop box of TBA items.
			if(isNaN(begins[0]) || isNaN(ends[0]) || begins[0] == "" || ends[0] == "")
				continue;
				
			// correct for UTC
			begins[0] = begins[0]*1 + (new Date()).getTimezoneOffset() / 60;
			begins[1] = begins[1]*1 + (new Date()).getTimezoneOffset() % 60;
			ends[0] = ends[0]*1 + (new Date()).getTimezoneOffset() / 60;
			ends[1] = ends[1]*1 + (new Date()).getTimezoneOffset() % 60;
			
			var length = (ends[0] * 60 + ends[1]*1) - (begins[0] * 60 + begins[1]*1);
			
			var building = meetings[meeting].getAttribute('Building');
			var room = meetings[meeting].getAttribute('Room');
									
			var new_session = new Session(this, daynum, begins, length, building, room);
			this.Meetings.push(new_session);
		}
	}
	
	this.Render = function()
	{
		// don't lose track of this course, so put it on the stack if its not already
		if(currentCourses.indexOf(this) < 0)
			currentCourses.push(this);
		
		for(var i = 0; i < this.Meetings.length; i++)
			this.Meetings[i].Render();
	}
	
	this.Save = function()
	{	
		this.Saved = true;
		this.Focused = false;
		this.Render();
		Persist.Add(this);
	}
	
	this.Focus = function()
	{
		this.Focused = true;
		this.Render();
	}
	
	this.Blur = function()
	{
		this.Focused = false;
		this.Render();
	}
	
	this.Destroy = function()
	{
		for(var i = 0; i < this.Meetings.length; i++)
			this.Meetings[i].Destroy();
			
		/*
		var new_currentCourses = Array();
		for(var i = 0; i < currentCourses.length; i++)
			if(currentCourses[i] != this)
				new_currentCourses.push(currentCourses[i]);
		
		currentCourses = new_currentCourses;
		*/
		currentCourses = currentCourses.remove(this);
		Persist.Remove(this);
	}
}

// ***************************************************
// ***************************************************
// ***************************************************

var currentOrder = 0;

// session constructor
function Session(course, day, start_time, length, building, room)
{
	this.Course = course;
	this.Day = day;
	this.StartTime = start_time;
	this.Length = length;
	this.Room = room;
	this.Building = building;
	
	// leave a spot for storing a reference to the rendered div
	this.Block = null;
	
	// generates the text for the session box
	this.GetText = function()
	{
		var text = this.Course.Code + "<br/>\n";
		if(this.Course.Name)
			text += this.Course.Name + "<br/>\n";
		if(this.Course.Instructor)
			text += this.Course.Instructor + "<br/>\n";
		if(this.Building)
			text += this.Building + " " + this.Room + "<br/>\n";
		text += this.Course.Call;
		
		return text;
	}
	
	this.Destroy = function()
	{
		if(this.Block == null)
			return;
		else if(this.Block.parentNode == null)
			return;
		
		this.Block.parentNode.removeChild(this.Block);
	}
	
	// render function for session
	this.Render = function()
	{
		if(this.Block == null)
			this.Block = document.createElement("div");
		else
			this.Block.parentNode.removeChild(this.Block);
		
		this.Block.Session = this;
		this.Block.style["zIndex"] = currentOrder++;
		
		this.Block.innerHTML = this.GetText();
		this.Block.title = this.GetText().replace(/(<([^>]+)>)/ig, ", \n");
		
		this.Block.className = "session";
		if(this.Course.Focused)
			this.Block.className += " focused";
		else if(this.Course.Saved)
			this.Block.className += " saved";

		// Adjusts for the header rowspan, which makes a class on an hour boundary have a
		// different index for the same day as one starting after > 15 mins
		var day = this.Day;
		if(this.StartTime[1]*1 / 15)
			--day;
				
		// Determine the new location of the block and insert it into the DOM there	
		var pn = timeblocks[this.StartTime[0]*1].rows[parseInt(this.StartTime[1]*1 / 15)].cells[day+1]; // Day+1 accounts for the heading row
		this.Block.style["top"] = findPos(pn)[1] + (this.StartTime[1]*1 % 15) + 1 + "px";
		this.Block.style["width"] = pn.offsetWidth - 11 + "px";
		pn.appendChild(this.Block);
		
		// calculate the height of a minute -- pixels per minute for a 15 min block == pixels / 15
		var minute_height = pn.offsetHeight / 15e0;
		
		// subtract 1 for the 1px padding + 3 for each 1px border + 2*1px paddings crossed
		//Dave, I changed (this.Length/15)*3 to (this.Length/15e0)*1e0, this seems to "fix" the problem but I am sure it is just a bandaid.
		//It causes midday classes to be slightly longer then they should be (like 1 pixel) and night class to be short (like 3 pixels).
		this.Block.style["height"] = (this.Length*minute_height - 1 - (this.Length/15e0)*1e0) + 'px';
		
		// set up events
		if(this.Course.Saved)
			this.Block.ondblclick_sim = deleteCourse;
		else
			this.Block.ondblclick_sim = saveCourse;
			
		this.Block.onmouseup = focusCourse;
	}
}

// ***************************************************
// ***************************************************
// ***************************************************

function findPos(obj) {
	var curleft = curtop = 0;
	if (obj.offsetParent) {
		curleft = obj.offsetLeft
		curtop = obj.offsetTop
		while (obj = obj.offsetParent) {
			curleft += obj.offsetLeft
			curtop += obj.offsetTop
		}
	}
	return [curleft, curtop];
}

// ***************************************************
// ***************************************************
// ***************************************************

// event functions
var last_trigger = new Date();
var last_trigger_course = null;

function focusCourse(e)
{
	var course = this.Session.Course;
	var now = new Date();

	if((now.getTime() - last_trigger.getTime() <= 1000) && (last_trigger_course == course))
		return this.ondblclick_sim(e);
		
	last_trigger_course = course;	
	last_trigger = now;
	
	if (!e) var e = window.event;
	
	for(var i = 0; i < currentCourses.length; i++)
	{
		if(currentCourses[i] == course)
		{
			if(currentCourses[i].Focused)
				currentCourses[i].Blur();
			else
				currentCourses[i].Focus();
		}
		else
			currentCourses[i].Blur();				
	}
}

function saveCourse(e)
{
	var course = this.Session.Course;
	course.Save();
}

function deleteCourse(e)
{
	var course = this.Session.Course;
	course.Destroy();
}

window.onresize = function()
{
	for(var i = 0; i < currentCourses.length; i++)
		currentCourses[i].Render();
}

function DestroyUnsaved()
{
	temp_currentCourses = currentCourses.slice();
	
	for(var i = 0; i < temp_currentCourses.length; i++)
		if(temp_currentCourses[i].Saved == false)
			temp_currentCourses[i].Destroy();
}