// kate: indent-mode cstyle; space-indent false; indent-width 4;

// Course Schedule Creator
// Copyright (C) 2009  Roman Shtylman <shtylman@gmail.com>
//
// Licensed under the GNU Affero General Public License
// http://www.fsf.org/licensing/licenses/agpl-3.0.html

//IE 7 does not define a Node class...shame on them :)
if (!window['Node']) {
    window.Node = new Object();
    Node.ELEMENT_NODE = 1;
    Node.ATTRIBUTE_NODE = 2;
    Node.TEXT_NODE = 3;
    Node.CDATA_SECTION_NODE = 4;
    Node.ENTITY_REFERENCE_NODE = 5;
    Node.ENTITY_NODE = 6;
    Node.PROCESSING_INSTRUCTION_NODE = 7;
    Node.COMMENT_NODE = 8;
    Node.DOCUMENT_NODE = 9;
    Node.DOCUMENT_TYPE_NODE = 10;
    Node.DOCUMENT_FRAGMENT_NODE = 11;
    Node.NOTATION_NODE = 12;
}

var majors = new Array();
var instructors = new Array();

//generic query
function query(data, callback)
{
	$.get("query.php", data, callback, "xml");
}

//initialize the application
//populate initial major stuff and all
function init()
{	
	$("#controls > #major").change(function()
	{
		loadMajor($(this).val(), true);
	});
	
	query({term: termId, action: "majors"}, function(data)
	{
		procMajors(data);
		popMajors();
		
		if ($.browser.msie) $("#controls > #major").hide().show();
		
		//select the first course
		$("#controls > #major").change();
	});
}

function save()
{
	var getVars = "term=" + termId;
	
	var courseList = $("#courses");
	
	//if the course is already in the list, don't add again
	//var newId = course.major.abbr + "_" + course.number;
	courseList.children().each(function()
	{
		id = $(this).attr("id");
		idVar = id.split('_');
		
		var major = majors[idVar[0]];
		for (var m in major.courses)
		{
			if (major.courses[m].number == idVar[1])
			{
				var c = major.courses[m];
		
				courseVars = idVar[0] + "," + idVar[1];
				
				for (var si in c.sections)
				{
					section = c.sections[si];
					if (section.visible || section.checked)
					{
						courseVars += "," + section.srn;
					}
				}
				
				getVars += "&" + escape("courses[]") + "=" + escape(courseVars);
			}
		}
	});
	
	window.location = "fileio.php?" + getVars
}

function load()
{
	$("#dialog").dialog('open');
}

function loadMe(xmlDoc)
{
	$("#courses").empty();
	
    $("#totalCredits").text("0");
    
	$.ajaxSetup({async: false});
	
	$(xmlDoc).find("schedule").children().each(function()
	{
		var major = $(this).attr("major");
		var number = $(this).attr("number");
        
        loadMajor(major, false);
        var c = majors[major].coursesByNumber[number];
        loadCourse(c);
        
		$(this).children().each(function()
		{
			var srn = $(this).attr("srn");
			
			for (var si in c.sections)
			{
				section = c.sections[si];
				if (section.srn == srn)
				{
                    $("#pinCell_" + srn).click();
                        
                    for (var i in section.timeslots)
                    {
                        var ts = section.timeslots[i];
                        
                        var element = ts.displayDiv;
                        if (!element)
                            continue;
                        
                        element.show();
                    }
                    
                    var credits = $("#totalCredits");
                    var cred = parseFloat(credits.text());
                    credits.text(cred + section.credits);                
                }
			}
		});
	});
	
	$.ajaxSetup({async: true});
}

function loadMajor(abbr, changeCombo)
{
	//don't fetch if course already exists
	if (majors[abbr].courses.length > 0)
	{
		popCourses(majors[abbr].courses);
		if ($.browser.msie) $("#controls > #course").hide().show();
		return;
	}
	
	query({term: termId, action: "courses", major: abbr}, function(data)
	{
		procCourses(data, majors[abbr]);
		
		if (changeCombo)
		{
			popCourses(majors[abbr].courses);
			if ($.browser.msie) $("#controls > #course").hide().show();
		}
	});
}

/* blocking fetch of instructor data */
function fetchInstructor(instructorId)
{
	var instr = instructors[instructorId];
	
	if (!instr)
	{
		query({term: termId, id: instructorId, action: "instructor"}, function(data)
		{
			procInstructor(data);
		});
	}
	
	return instructors[instructorId];
}

/* process majors xml file and populate array of majors */
function procMajors(xmlDoc)
{
    $(xmlDoc).find("row").each(function()
    {
        var fields = $(this).children();

        var id = $(fields[0]).text();
        var name = $(fields[1]).text();
        var abbr = $(fields[2]).text();
        
        var major = new Major(id, abbr, "Name");
        majors[major.abbr] = major;
    });
}

/* process a list of courses from the xml file, populate major */
function procCourses(xmlDoc, major)
{
    $(xmlDoc).find("row").each(function()
    {
        var fields = $(this).children();

        var id = $(fields[0]).text();
        var name = $(fields[1]).text();
        var number = $(fields[2]).text();
        
        var course = new Course(id, major, number, name);
        major.courses.push(course);
		major.coursesByNumber[number] = course;
    });
}

/* process sections into a course */
function procSections(xmlDoc, course)
{
    $(xmlDoc).find("row").each(function()
    {
        var fields = $(this).children();

        var id = $(fields[0]).text();
        var srn = $(fields[1]).text();
        var name = $(fields[2]).text();
        var instructorId = $(fields[3]).text();
        var credits = parseFloat($(fields[4]).text());
        var campus = $(fields[5]).text();
        var gpa = parseFloat($(fields[6]).text());
        
        var section = new Section(id, srn, name, credits, campus);
        section.instructor = fetchInstructor(instructorId);
        section.gpa = gpa.toFixed(3);
            
        course.sections.push(section);
    });
}

/* process timeslots into a section */
function procTimeslots(xmlDoc, section)
{
    $(xmlDoc).find("row").each(function()
    {
        var fields = $(this).children();

        var sid = $(fields[0]).text();
        var type = $(fields[1]).text();
        var day = $(fields[2]).text();
        var location = $(fields[3]).text();
        var start = $(fields[4]).text();
        var end = $(fields[5]).text();
        
        var timeslot = new Timeslot(type, day, location, start, end);
        section.timeslots.push(timeslot);
    });
}

function procInstructor(xmlDoc)
{
    $(xmlDoc).find("row").each(function()
    {
        var fields = $(this).children();

        var iid = $(fields[0]).text();
        var fname = $(fields[1]).text();
        var lname = $(fields[2]).text();
        
        var instructor = new Instructor(iid, fname, lname);
        instructors[iid] = instructor;
    });
}

//populate majors combo box
function popMajors()
{
	var majorCombo = $("#controls > #major");
	
	for (key in majors)
	{
		var major = majors[key];
		var item = $(document.createElement("option")).appendTo(majorCombo);
		
		item.attr("value", major.abbr);
		item.text(major.abbr);
	}
}

//populate couse list combo box from a list of courses
function popCourses(courses)
{	
	//clear previous courses
	var courseCombo = $("#controls > #course");
	courseCombo.empty();

	for (i in courses)
	{
		var c = courses[i];
		var item = $(document.createElement("option")).appendTo(courseCombo);
		
		item.attr("value", i);
		item.text(c.toString());
	}
}

//load the sections for a course
function loadCourse(course, noAsync)
{
	var courseList = $("#courses");
	
	//if the course is already in the list, don't add again
	var newId = course.major.abbr + "_" + course.number;
	if (courseList.children("#" + newId).length > 0)
	{
		return;
	}
    
	if (course.sections.length > 0)
	{
		mkTable(course);
		return;
	}

	query({term : termId, course: course.id, courseNum: course.number, action: "sections"}, function(data)
	{
		if (course.sections.length > 0)
		{
			return;
		}
		
		if (noAsync)
		{
			//because we are already async, perform all other queries syncronously
			$.ajaxSetup({async: false});
		}
		
		procSections(data, course);
		
		for (var s in course.sections)
		{
			var section = course.sections[s];
			query({term: termId, course: course.id, section: section.id, action: "timeslots"}, function(data)
			{
				procTimeslots(data, section);
			});
		}
		
		if (noAsync)
		{
			$.ajaxSetup({async: true});
		}
		
		mkTable(course);
	});
}

//fetch course info and add to list of selections
function addCourse()
{
	var major = majors[$("#controls > #major").val()];
	var course = major.courses[$("#controls > #course option:selected").attr("value")];
	loadCourse(course, true);
}

//add the course to the list of selections
function mkTable(course)
{
	//list of courses
	var courseList = $("#courses");
	var newId = course.major.abbr + "_" + course.number;
	
	//display element (week view)
	var display = $("#calendar");

	//create new container for the course info and add it to the list
	var newCourse = $(document.createElement("div"));
	newCourse.appendTo(courseList);
	newCourse.attr("id", newId);
	newCourse.addClass("container round courseContainer");
	
	var courseHeader = $(document.createElement("div"));
	courseHeader.appendTo(newCourse);
	courseHeader.addClass("course_header");
	
	var cName = $(document.createElement("span"));
	cName.appendTo(courseHeader);
	cName.addClass("course_name course_name_expanded");
	cName.text(course.toString() + " - " + course.major.abbr);
	
	var remove = $(document.createElement("div"));
	remove.appendTo(courseHeader);
	remove.attr("title", "Remove Course");
	remove.addClass("course_remove");
	
	//detail example
	//https://oscar.gatech.edu/pls/bprod/bwckschd.p_disp_detail_sched?term_in=200902&crn_in=20850"
	
	var catLink = $(document.createElement("a"));
	catLink.appendTo(courseHeader);
	catLink.attr("href", "https://oscar.gatech.edu/pls/bprod/bwckctlg.p_display_courses?term_in=" + termId + "&one_subj=" + course.major.abbr + "&sel_crse_strt=" + course.number + "&sel_crse_end=" + course.number + "&sel_subj=&sel_levl=&sel_schd=&sel_coll=&sel_divs=&sel_dept=&sel_attr=");
	catLink.attr("target", "_new");
	catLink.attr("title", "Catalog Entry");
	catLink.addClass("course_catalog");
	
	var clearDiv = $(document.createElement("div"));
	clearDiv.appendTo(courseHeader);
	clearDiv.addClass("clear");
	
	remove.click(function ()
	{
		//remove all created display divs
		for (var si in course.sections)
		{
			section = course.sections[si];
			if (section.visible || section.checked)
			{
				var credits = $("#totalCredits");
				var cred = parseFloat(credits.text());
		
				credits.text(cred - section.credits);
			}

			section.visible = section.checked = false;
			
			for (var ti in section.timeslots)
			{
				var ts = course.sections[si].timeslots[ti];
				
				if (ts.displayDiv)
				{
					ts.displayDiv.remove();
					ts.displayDiv = undefined;
				}
			}
		}
		
		//remove course from list
		newCourse.remove();
	});
	
	var cTableContainer = $(document.createElement("div"));
	cTableContainer.appendTo(newCourse);
	cTableContainer.addClass("courseTableContainer");
	
	var cTable = $(document.createElement("table"));
	cTable.appendTo(cTableContainer);
	cTable.addClass("courseTable");
	
	var count = 0;
	for (var i in course.sections)
	{
		var row = mkSection(course, course.sections[i], display);
		row.appendTo(cTable);

		row.addClass("courseTableRow");
		if (count % 2 == 0)
		{
			row.addClass("courseTableRowEven");
		}

		count++;
	}
	
	//toggle display/hide of info table
	cName.click(function ()
	{
		cTableContainer.slideToggle("medium");
		cName.toggleClass("course_name_collapsed");
	});
}

function mkSection(course, section, display)
{
	var row = $(document.createElement("tr"));
	row.attr('id', section.srn);
	
	var pinCell = $(document.createElement("td"));
	pinCell.appendTo(row);
	pinCell.attr("id", "pinCell_" + section.srn);
	pinCell.addClass("pin unpinned");
	pinCell.attr("title", "un-pinned");
	
	pinCell.click(function()
	{
		section.checked = !section.checked;
		pinCell.toggleClass("unpinned");
		
		if (section.checked)
		{
			pinCell.attr("title", "pinned");
		}
		else
		{
			pinCell.attr("title", "un-pinned");
		}
	});
	
	var srnCell = $(document.createElement("td"));
	srnCell.appendTo(row);
	srnCell.text(section.srn);
	srnCell.attr("title", "CRN");
	
	var timesCell = $(document.createElement("td"));
	timesCell.appendTo(row);
	timesCell.attr("title", "Meeting Times");
	
	if (false)
	{
		timesCell.text(section.timesString());
	}
	else
	{
		var color = course.color.toHexString();
		groups = section.timeGroups();
		for (i in groups)
		{
			var group = groups[i];
			var dayS = $(document.createElement("div"));
			dayS.appendTo(timesCell);
			
			var m = $(document.createElement("div"));
			var t = $(document.createElement("div"));
			var w = $(document.createElement("div"));
			var r = $(document.createElement("div"));
			var f = $(document.createElement("div"));
			
			dayS.append(m).append(t).append(w).append(r).append(f);
			dayS.addClass("daySquares");
			m.addClass("daySquare");
			t.addClass("daySquare");
			w.addClass("daySquare");
			r.addClass("daySquare");
			f.addClass("daySquare");
			
			for (ii in group)
			{
				var ts = group[ii];
				switch (ts.day)
				{
					case 'M': m.css('background-color', color); break;
					case 'T': t.css('background-color', color); break;
					case 'W': w.css('background-color', color); break;
					case 'R': r.css('background-color', color); break;
					case 'F': f.css('background-color', color); break;
				}
			}
			
			var timeText = $(document.createElement("span"));
			timeText.appendTo(timesCell);
			timeText.text(group[0].startString() + " - " + group[0].endString());
			
			var clear = $(document.createElement("div"));
			clear.addClass("clear");
			clear.appendTo(timesCell);
		}
	}
	
	var nameCell = $(document.createElement("td"));
	nameCell.appendTo(row);
	nameCell.text(section.name);
	nameCell.attr("title", "Section");
	
	var instructorCell = $(document.createElement("td"));
	instructorCell.appendTo(row)
	instructorCell.text(section.instructor ? section.instructor.lname + ", " + section.instructor.fname.charAt(0) : "TBA");
	instructorCell.attr("title", "Instructor");
	
	var credits = $(document.createElement("td"));
	credits.appendTo(row)
	credits.text(isNaN(section.credits) ? "-" : section.credits);
	credits.attr("title", "Credits");

	var avgGpaCell = $(document.createElement("td"));
	avgGpaCell.appendTo(row)
	avgGpaCell.text(isNaN(section.gpa) ? "-" : section.gpa);
	avgGpaCell.attr("title", "Average GPA");
	
	var seatInfoCell = $(document.createElement("td"));
	seatInfoCell.appendTo(row)
	seatInfoCell.text("-");
	seatInfoCell.attr("title", "Seats Remaining/Capacity");
	
	seatInfoCell.update = function()
	{
		seatInfoCell.load("seatinfo.php", {term: termId, srn: section.srn});
		//setTimeout(seatInfoCell.update, 10 * 60 * 1000); //update every 10 min
	}
    //makes the seat info async to not block the loading of the section
    setTimeout(seatInfoCell.update, 50);
	
	//create calendar display items
	var count = 0;
	for (var index in section.timeslots)
	{
		var ts = section.timeslots[index];
		
		//minute duration
		var duration = ts.end - ts.start;
		//var range = (22 - 8) * 60.0;
		
		//percent per minute
		var pPerMin = (100.0/14.0/60.0);
		
		var cell = $(document.createElement("div"));
		ts.displayDiv = cell;
		
		var day = ts.day;
		var dayCol = null;
		switch (day)
		{
			case 'M':
				dayCol = $("#mon");
				break;
			case 'T':
				dayCol = $("#tue");
				break;
			case 'W':
				dayCol = $("#wed");
				break;
			case 'R':
				dayCol = $("#thu");
				break;
			case 'F':
				dayCol = $("#fri");
				break;
			default:
				dayCol = $("#mon");
				break;
		}
		
		cell.appendTo(dayCol);
		cell.addClass("courseBox");
		
		cell.css('top', pPerMin * (ts.start - 8*60) + "%");
		cell.css('height', pPerMin * duration + "%");
		cell.attr('id', section.srn + count++);
		cell.hide();
		
		var info = $(document.createElement("div"));
		info.appendTo(cell);
		info.addClass("round courseCal");
		//info.attr('id', section.srn + count++);
		info.css('background-color', course.color.toHexString());
		info.css('border-color', course.color.toHexString());
		
		var cell_content = $(document.createElement("div"));
		cell_content.appendTo(info);
		cell_content.addClass("courseContent");
		cell_content.html(course.major.abbr + " " + course.number + "<br />" + ts.location);
	}
	
	//one function for over and out because much of the code is the same
	var func = function(event)
	{
		var type = event.type;
		
		if (!section.checked)
		{
			if (type == "mouseover")
			{
				//avoid showing again if already showing
				if (section.visible)
				{
					return;
				}
				section.visible = true;
			}
			else
			{
				//avoid hiding again if already hiding
				if (!section.visible || section.checked)
				{
					return;
				}
				section.visible = false;
			}
		}
		
		for (var i in section.timeslots)
		{
			var ts = section.timeslots[i];
			
			var element = ts.displayDiv;
			if (!element)
			{
				continue;
			}
			
			if (section.visible || section.checked)
			{
				//$(element).stop(true);
				//$(element).fadeIn("fast");
				element.show();
			}
			else
			{
				element.hide();
			}
		}
		
		var credits = $("#totalCredits");
		var cred = parseFloat(credits.text());
		
		if (type == "mouseover" && !section.checked)
		{
			credits.text(cred + section.credits);
		}
		else if (type == "mouseout" && !section.checked)
		{
			credits.text(cred - section.credits);
		}
	};
	
	row.mouseover(func);
	row.mouseout(func);
	
	return row;
}

function initFilters()
{
	//setup filters...todo move...
	var m = false;
	var t = false;
	var w = false;
	var r = false;
	var f = false;
	
	var ms = $(document.createElement('div'));
	ms.appendTo($("#filter"));
	ms.addClass("daySquare");
	
	ms.click(function()
	{
		m = !m;
		$(this).toggleClass("daySquareOn");
	});
}
