
/*
 * This set of Javascript functions provides general utilities for the system. None
 * of the functions in this file are directly related to look and feel. It is strongly
 * recommended NOT to modify these functions.
 */

/*
 * Variable to hold page submission counter. 
 */
var clickCounter; 

/*
* Variable to hold assignment window instance reference.
*/
 var edu_window;

/*
 * Hook to be called whenever a page is loaded. 
 * Override this to provide functionality.
 */
function onLoad() {
  // Do nothing
}
/*
 * Hook to be called whenever a page is resized. 
 * Override this to provide functionality.
 */
function onResize() {
  // Do nothing
}
/*
 * Hook to be called whenever a page is left. 
 * Override this to provide functionality.
 */
function onUnload() {
  // Do nothing
}
/*
 * Hook to be called whenever a form is submitted.
 * Override this to provide functionality.
 */
function onSubmit() {
	return true;
}

/*
 * This is the basic action-delegation method called to submit forms to EDU.
 * Most button clicks result in a call to this function.
 */
function doAction(action) {
	var frm = document.forms["edu_form"];
	frm.elements.actionID.value = action;
	if (onSubmit()) {
		if (firstClick(action))
		{
			frm.submit();
		} 
	}
}
/*
 * This handles action's performed from the menu so as not to clobber
 * the edu_form
 */
function doMenuAction(action) {
	var frm = document.forms["menu_form"];
	frm.elements.actionID.value = action;
	if (onSubmit()) {
		frm.submit();
	}
}
/*
 * Read a question response from a Java applet that conforms to the contract of
 * Java question type.
 */
function readAppletItems() {
	var form = document.edu_form;
	var elts = form.elements;
	var pattern = /ans\.(\d+)\.(\d+)/;
	for (var i = 0; i < elts.length; i++) {
		var name = elts[i].name;
		if (name.match(pattern) != null) {
			var appl = document[name + ".sro"];
			var resp = null;
			if (appl != null) {
				resp = new String(appl.getResponse());
			} else {
				if ((appl = document[name + ".swf"]) != null) {
					resp = new String(appl.GetVariable("response"));
				}
			}
			if (resp != null) {
				form.elements[i].value = resp;
				if (resp.indexOf("error:") == 0) {
					var errm = resp.substring(6, resp.length);
					if (!confirm(errm)) {
						appl.requestFocus();
						return false;
					}
				}
			}
		}
	}
	return true;
}

/*
 * Redirect the window to the home page for the ambient class.
 */
function toClassPage() {
	var w = window;
	if (window.parent.frames.controlbar != null) {
		w = window.parent.opener;
	}
	if (w != null) {
		if (className != "") {
			w.location = getBaseURL() + "registration.Redirect?className=" + className;
		} else {
			w.location = getBaseURL();
		}
		w.focus();
	}
	if (window.parent.frames.controlbar != null) {
		window.parent.close();
	}
}
/*
 * Draw the content of a popup hints window.
 */

/*
* this code was added in an attempt to show what hints have been seen.  It did not work so is commented out
* until we can get back to this feature.


function showHint(hintIndex) {

	if (hintIndex == -1) return;
		
	// Update the list of hints that we've seen...
	var objHintsSeen = document.getElementById("hintsSeen");
	var hintsSeen = objHintsSeen.value;
	if (hintsSeen.indexOf(hintIndex) == -1) {
		var arrayHints = hintsSeen.split(',');
		arrayHints[arrayHints.length] = hintIndex;
		arrayHints.sort();
		hintsSeen = arrayHints.join(',');
		objHintsSeen.value = hintsSeen;
	}
*/
	
function showHint(hint, hintRef) {	

	var w = window.open("", "hints", "width=500,height=300,resizable,scrollbars");
	var d = w.document;
	d.open("text/html");
	d.writeln("<HTML>");
	d.writeln("  <BODY>");
	d.writeln("    <FORM ACTION=\"" + getBaseURL() + "modules/proctoredTest.ShowHint\" METHOD=\"post\">");

  	d.writeln("      <INPUT TYPE=\"hidden\" NAME=\"hint\" VALUE=\"" + hint + "\">");
  	d.writeln("      <INPUT TYPE=\"hidden\" NAME=\"hintRef\" VALUE=\"" + hintRef + "\">");

// see above comment
//	d.writeln("      <INPUT TYPE=\"hidden\" NAME=\"hint\" VALUE=\"" + hintIndex + "\">");

	d.writeln("    </FORM>");
	d.writeln("  </BODY>");
	d.writeln("</HTML>");
	d.close();
	d.forms[0].submit();
	w.focus();
}
/*
 * Provide help for a user in one of the system roles of instructor, student, administrator, or proctor.
 */
function getHelp(what,where) {
	var winspec = "scrollbars,resizable,width=800,height=600";
	var help;
  // The definitions of the help urls are in helpURLs.js
	if (what == "instructor") {
		help = INSTRUCTOR_HELP_URL;
	} else if (what == "administrator") {
		help = SYSADMIN_HELP_URL;
	} else if (what == "proctor") {
		help = PROCTOR_HELP_URL;
	} else if (what == "student") {
		help = STUDENT_HELP_URL;
	} else if (what == "getting_started") {
		help = INSTRUCTOR_GETTIN_STARTED;
	} else if (what == "user_guide_pdf") {
		help = INSTRUCTOR_USER_GUIDE_PDF;
	} else if (what == "inline_editor") {
		help = INLINE_EDITOR_HELP_URL;
	} else if (what == "math_symbol_mode") {
		help = MATH_SYMBOL_MODE_HELP_URL;
	} else if (what == "math_text_mode") {
		help = MATH_TEXT_MODE_HELP_URL;
	} else if (what == "student_math_editor") {
		help = STUDENT_MATH_EDITOR_HELP;
	} else if (what == "instructor_math_editor") {
		help = INSTRUCTOR_MATH_EDITOR_HELP;
	} else if (what == "chem_symbol_mode") {
		help = CHEM_SYMBOL_MODE_HELP_URL;
	} else if (what == "chem_text_mode") {
		help = CHEM_TEXT_MODE_HELP_URL;
	} else {
		help = ASSIGNMENT_TYPE_HELP_URL;
	}

	window.open(where+help, "helpWindow", winspec);
}
/*
 * Utility method. Not called from outside this package.
 */
function getMaplePlotURL(maple, plot, type, libname, driver, width, height) {
	var url = getBaseURL() + "modules/mapleTA.plotserver.PlotServer" + "?maple=" + myEscape(maple) + (plot != null ? "&plot=" + myEscape(plot) : "") + (type != null ? "&type=" + myEscape(type) : "") + (libname != null ? "&libname=" + myEscape(libname) : "") + ((driver == null || driver.length == 0) ? "" : "&plotdriver=" + myEscape(driver)) + ((width == null || height == null) ? "" : "&width=" + width + "&height=" + height);
	return url;
}
/*
 * Create a plot using the provided Maple code.
 * Utility method. Not called from outside this package.
 */
function drawMaplePlot(maple, width, height, libname, driver) {
	var url = getMaplePlotURL(maple, null, null, libname, driver, width, height);
	document.write("<IMG title=\"Maple plot\"");
	document.write("SRC=\"" + url + "\" ");
  //size the image if we have that parameters, otherwise, let the browser figure it out
	if (width != null && height != null) {
		document.write("WIDTH=" + width + " ");
		document.write("HEIGHT=" + height);
	}
	document.write(">");
}
/*
 * Create a popup plot of Maple code.
 */
function popupMaplePlot(maple, plot, type, libname, driver) {
	var url = getMaplePlotURL(maple, plot, type, libname, driver, null, null);
	var w = window.open("", "maplepopup", "width=640,height=480,scrollbars=no,resizable=no");
	var d = w.document;
	d.open("text/html");
	d.writeln("<HTML>");
	d.writeln("<HEAD>");
	d.writeln("</HEAD>");
	d.writeln("<BODY>");
  //size the image according the system defaults
	d.writeln("<IMG SRC=\"" + url + "\" NAME=plot title=\"Maple plot\">");
	d.writeln("</BODY>");
	d.writeln("</HTML>");
	d.close();
	w.focus();
}
/*
 * Utility method to perform URL escaping since there are problems with the Javascript 
 * built-in function.
 */
function myEscape(s) {
	return encodeURIComponent(s);
}
/*
 * Generate a popup message
 */
function popupMessage(msg) {
	var w = window.open("", "popup", "width=500,height=380,scrollbars=no,resizable=no,status=no,location=no,dependent=yes");
	var d = w.document;
	d.open("text/html");
	d.writeln("<HTML>");
	d.writeln("<HEAD>");
	d.writeln("</HEAD>");
	d.writeln("<BODY>");
	d.writeln("<TABLE ALIGN=\"CENTER\">");
	d.writeln("<TR VALIGN=\"CENTER\"><TD>");
	d.writeln(msg);
	d.writeln("</TD></TR>");
	d.writeln("</TABLE>");
	d.writeln("</BODY>");
	d.writeln("</HTML>");
	d.close();
	w.focus();
}
var _preview = null;
var _previewEq = null;
function previewFormula(f, s) {
	var platf = navigator.platform;
	var useJava = (platf != null) && (platf.indexOf("Win32") == 0 || platf.indexOf("Linux") == 0);
	_previewEq = null;
	_previewEq = f;
	var b = myEscape(f);
	if (_preview != null) {
		_preview.close();
	}
	_preview = window.open(getBaseURL() + "modules/preview.Preview?eq=" + b + "&actionID=" + s, "previewer", "width=350,height=200,scrollbars,resizable");
 // _preview.resizeTo(350, 200);
}
function previewChemistry(f) {
	var b = myEscape(f);
	window.open(getBaseURL() + "modules/preview.Preview?actionID=chemistry&eq=" + b, "previewer", "width=300,height=175,resizable");
}
/*
 * Holds a pointer to an inline question's webeq input control applet.
 * Used by popupMathToolbar() (below) and the JS in mathEditor/toolbar.html.
 */
var _math_toolbar_target;
/*
 * Pop up a toolbar window which writes templates to a webeq IC. Used
 * by the Inline question.
 */
function popupMathToolbar(name) {
	_math_toolbar_target = document[name + ".sro"];
	window.open(getBaseURL() + "modules/mathEditor/toolbar.html", "math_editor_toolbar", "width=240,height=50").focus();
}
/*
 * Pop up a toolbar window which writes templates to a webeq IC. Used
 * by the Inline question.
 */
function popupChemToolbar(name) {
	_math_toolbar_target = document[name + ".sro"];
	window.open(getBaseURL() + "modules/mathEditor/chem_toolbar.html", "math_editor_toolbar", "width=240,height=50").focus();
}
/*
 * Popup describing EDU server, version, etc.
 */
function aboutPopup(server_url) {
	window.open(server_url+"About.do", "version_info", "width=350,height=250,resizable,scrollbars");
}
/*
 * Warning that the session timeout is close to expiring.
 */
function warnOfImminentSessionTimeout(k) {
	clearInterval(_sessionTimeoutTimerID);
	var timestamp = new Date();
	alert("DISCONNECTION WARNING\n\n" +
	 "You may be in danger of losing your work on this page. The internet server\n" +
	 "that sent this question to you needs a reply. To save your work and continue\n" +
	 "working, do the following within the next " + 
	 (k / (60 * 1000)) + 
	 " minutes:\n\n" +
	 "1) Click the Next or Back button above.\n\n" +
	 "2) When the new question appears, click the Back or Next button to return to this\n" + 
	 "question.  Your work will be saved and you can then continue to enter responses\n" + 
	 "on this page.\n\n" + 
	 "(If the Next or Back buttons are greyed out, click the Save & Quit button.  You\n" + 
	 "will have to log-in again to return to this question, but your work will be preserved.)\n\n" + 
	 "Message time: " + 
	 (new Date()).toLocaleString());
}
var _sessionTimeoutTimerID = 0;
function startSessionTimeoutWarningTimer(timeout) {
	var k = 5 * 60 * 1000;
	var t = timeout - k;
	if (t < 0) {
		t = timeout / 2;
	}
	_sessionTimeoutTimerID = setInterval("warnOfImminentSessionTimeout(" + k + ")", t);
}
/*
 *  Get a handle to the object matching the given name
 */
function findObj(n, d) {
	var p, i, x;
	if (!d) {
		d = document;
	}
	if ((p = n.indexOf("?")) > 0 && parent.frames.length) {
		d = parent.frames[n.substring(p + 1)].document;
		n = n.substring(0, p);
	}
	if (!(x = d[n]) && d.all) {
		x = d.all[n];
	}
	for (i = 0; !x && i < d.forms.length; i++) {
		x = d.forms[i][n];
	}
	for (i = 0; !x && d.layers && i < d.layers.length; i++) {
		x = findObj(n, d.layers[i].document);
	}
	if (!x && d.getElementById) {
		x = d.getElementById(n);
	}
	return x;
}
/*
 *  Change the visibility of the style element to be hidden
 */
function hide(objName) {
	obj = findObj(objName);
	if (obj.style) {
		obj.style.visibility = "hidden";
	}
}
/*
 *  Change the visibility of the style element to be visible
 */
function show(objName) {
	obj = findObj(objName);
	if (obj.style) {
		obj.style.visibility = "visible";
	}
}
/*
 * This method installs CSS to enable (certain browsers) to display scrollable tables.
 * The method must be called in the document's <head>. The feature is enabled for
 * Mozilla/Firefox based on Gecko 1.7 or better, and for MSIE 6.0. 
 * Usage:
 *   Wrap the table in a div.scrollableTableWrapper and include the scrollable
 *   body in <tbody>:
 *     <div class="scrollableTableWrapper">
 *       <table>
 *         <thead><tr><td>Planes</td><td>Trains</td><td>Automobiles</td></tr></thead>
 *         <tbody>
 *           <tr><td>3</td><td>2</td><td>1</td></tr>
 *           <tr><td>1</td><td>2</td><td>1</td></tr>
 *           <tr><td>3</td><td>4</td><td>1</td></tr>
 *           etc...
 *         </tbody>
 *       </table>
 *     </div>
 */
function deployScrollableTableFeature() {
	var browser = getBrowserCategory();
	
	if (browser == "gecko") {
		document.writeln("<style type='text/css'> ");
		document.writeln("  div.scrollableTableWrapper tbody {  ");
		document.writeln("    overflow: auto;  ");
		document.writeln("    height: 35em;  ");
		document.writeln("  } ");
		document.writeln("</style>");
	} else {
		if (browser == "ie") {
			document.writeln("<style type='text/css'> ");
			document.writeln("  div.scrollableTableWrapper { ");
			document.writeln("    clear: left; ");
			document.writeln("    float:left; ");
			document.writeln("    height:250px; ");
			document.writeln("    width:100%; ");
			document.writeln("    overflow:scroll; ");
			document.writeln("  } ");
			document.writeln("  div.scrollableTableWrapper table th { ");
			document.writeln("    position: relative; ");
			document.writeln("    background:#f7f7f7; ");
			document.writeln("  } ");
			document.writeln("  div.scrollableTableWrapper table { ");
			document.writeln("    margin-right:16px; ");
			document.writeln("   } ");
			document.writeln("</style>");
		}
	}
}

function getBrowserCategory()
{
	var browser = "unavailable";
	if (navigator.userAgent.indexOf("MSIE") >= 0) {
		browser = "ie";
	} else {
		if (navigator.userAgent.indexOf("Gecko") >= 0) {
			var re = /rv:(\d+\.\d+)/;
			var m = re.exec(navigator.userAgent);
			if (m != null) {
				var v = parseFloat(m[1]);
				if (v >= 1.7) {
					browser = "gecko";
				}
			}
		}
	}
	
	return browser;
}

function BrowserCheck() {
	var b = navigator.appName;
	if (b == "Microsoft Internet Explorer") {
		this.b = "ie";
	} else {
		this.b = b;
	}
	this.v = parseInt(navigator.appVersion);
	this.ie = (this.b == "ie" && this.v >= 4);
	this.ie4 = (navigator.userAgent.indexOf("MSIE 4") > 0);
	this.ie5 = (navigator.userAgent.indexOf("MSIE 5") > 0);
}
is = new BrowserCheck();
selectAllItems = function (obj) {
	var check = obj.checked;
	var boxes = document.getElementsByName("selectedItems");
	for (i = 0; i < boxes.length; i++) {
		boxes[i].checked = check;
	}
};

//override the back button if the history is empty, meaning the window
//is brand new and should be closed
function sidebarBack() {
	if (history.length <= 1) {
		window.close();
	} else {
		history.back();
	}
}

/*
*	Checks for double-clicks on the test screen.
*   Checks Grade button only for now.
*/
function firstClick(action) {
	var status;
	
//	if (action != "grade")
//		return true;
		
	if (clickCounter != 1)
		status=true;
	else
		status=false;
	
	clickCounter=1;
	return status;
}

function doAssignment(id,tn,timed) {
	if (!firstClick("")) {
		return;
	}
	var f = document.forms["edu_form"];
	var url = getBaseURL()+"modules/test.Test?className=" + className + "&testName=" + encodeURIComponent(tn) + "&testId=" + id;
	if (edu_window == null || edu_window.closed) {
	    var accept;
	    if( timed ) {
	    	accept = confirm('This is a timed assignment.  Once it has been started the timer cannot\nbe stopped until it runs out or the assignment is graded.');
	    }
	    else {
	    	accept = true;
	    }
		if( accept ) {
		    edu_window = window.open(url, "assignment_window", "scrollbars,resizable");
		    edu_window.focus();
	    }
	} else {
		alert("You are currently either taking an assignment, or you\r\n" +
			"have another browser window open to the class homepage.\r\n\r\n" +
			"Please finish the assignment and/or close the other browser before\r\n" +
			"attempting another assignment.");
		edu_window.focus();
	}
	clickCounter=0;
}

function showAssignmentPolicies(id,tn) {
  var url = getBaseURL()+"modules/test.ShowPolicies?className=" + className + "&testName=" + encodeURIComponent(tn) + "&testId=" + id;
  window.open(url, "show_policies_window","width=400,height=300,scrollbars,resizable").focus();
}
