/*
+===========================================-===========================================+
|                               TEST ANSWERS VERSION 2.2                                |
|===========================================-===========================================|
|                                    VERSION HISTORY                                    |
| 2.0.00  2003.08.31  JEM  Reconstructed the logic of previous testAnswers() functions  |
|                          to make a solution that could be implemented with a global   |
|                          JS library and only one line of programming per page (the    |
|                          Submit button).                                              |
| 2.2.00  2004.02.03  JEM  Restructured v2.0 to simplify the LA types to the basic few  |
|                          by extracting the feedback information into their own        |
|                          values. Also support for clickable images and multiple FBs   |
|                          on one page.                                                 |
| 2.2.01  2004.02.18  JEM  Corrected logic flaw in feedback() for FBOnPage with RSFB    |
| 2.2.02  2004.02.19  JEM  Corrected logic flaw in feedback() for MultiFBOnPage, Normal |
| 2.2.03  2004.02.25  JEM  Added NS6 flicker fix (may revert this if NS6 is dropped?;   |
|                          Made FBOff a global variable; renamed calls to the change()  |
|                          function to changeClassById() for clarity.                   |
| 2.2.04  2004.04.21  JEM  Added displayXOK variable to allow option to not call the    |
|                          noteCorrects() function, if not desired.  explore() function |
|                          enhanced to allow reset of all explored elements.            |
| 2.2.05  2004.04.30  JEM  Modified the resetFeedback() function to scan for only 'div' |
|                          and 'p' elements, rather than '*' elements, in order to      |
|                          fully support IE 5.x, which does not understand '*'.  Added  |
|                          the arrayConcat() function.                                  |
| 2.2.06  2004.05.04  JEM  Recommented.  Changed logic that calculates the URL of a FB  |
|                          page to drop "_la" if it is present in the current URL       |
|                          before appending "_pf", etc.  Added support for the          |
|                          MultiFBOnPagePlusPageFB FB Location Indicator                |
| 2.2.07  2004.05.17  JEM  Added feedback type of none.  Added parameter for page-wide  |
|                          feedback, thus removing MultiFB* as a FB Location Indicator. |
| 2.2.08  2004.05.28  JEM  Fixed logic flaw in feedback() for FBOnPage lacking break.   |
|                                                                                       |
|                                        SUMMARY                                        |
| This function accepts a string of text representing the type of question used, the    |
| type of feedback to be used, and the correct answers for that question.  Given these  |
| values and the state of the form elements on the page, this function provides the     |
| overall programming flow that triggers the execution of other functions necessary to  |
| render the desired result -- usually an on-screen indiciation of correct or           |
| incorrect and feedback for each question.                                             |
|                                                                                       |
|                                  REQUIRED PARAMETERS                                  |
| Feedback Location Indicator, Question Type Indicator, Feedback Type Indicator,        |
| Correct Response String (see all below).    The string is structured as such:         |
|  '<feedback location indicator>,<page-wide feedback type indicator>',                 |
|  '<question type indicator1>,<feedback type indicator1>|<correct state indicator1>'   |
|  [,'<question type indicator2>,<feedback type indicator2>|<correct state indicator2>' |
|  [,'<question type indicator3>,<feedback type indicator3>|<correct state indicator3>' |
|  [...]]]                                                                              |
|                                                                                       |
|                              FEEDBACK LOCATION INDICATOR                              |
| The first argument indicates for the current LA, where the feedback will be displayed.|
| Values forthe feedback location indicator are:                                        |
|    FBOnPage                  All feedback (positive, negative, partial, response-     |
|                              specific) appear on the same page as the LA, often       |
|                              within a feedback DIV which is visually controlled by    |
|                              CSS.  Feedback applies to the LA as a whole.             |
|    FBPosNext                 Positive feedback is on its own page, all other feedback |
|                              appears on the same page as the LA.  Feedback applies to |
|                              the LA as a whole.  URL of destination page is           |
|                              [URL of current page] - [file extension] - ["_la" (if    |
|                              present)] + ["_pf"] + [file extension]                   |
|    FBNextPage                All feedback appears on another page.  Feedback applies  |
|                              to the LA as a whole.  URL of destination page is        |
|                              [URL of current page] - [file extension] - ["_la" (if    |
|                              present)] + ["_pf"|"_nf"] + [file extension]             |
| The following feedback locations have been dropped in v2.2.07:                        |
|    MultiFBOnPage             This is used when there are multiple questions on a      |
|                              given page and there is to be separate feedback given    |
|                              for each question.  Feedback appears on the same page as |
|                              the LA.                                                  |
|    MultiFBOnPagePlusAdvance  This is used when there multiple questions on a given    |
|                              page and there is to be separate feedback given for each |
|                              question.  Such feedback appears on the same page as the |
|                              LA.  Additionally, when all questions are correctly      |
|                              answered, the browser is redirected to a positive        |
|                              feedback page.  URL of destination page is               |
|                              [URL of current page] - [file extension] - ["_la" (if    |
|                              present)] + ["_pf"] + [file extension]                   |
|   MultiFBOnPagePlusPageFB   This is used when there multiple questions on a given     |
|                              page and there is to be separate feedback given for each |
|                              question.  Such feedback appears on the same page as the |
|                              LA.  Additionally, feedback regarding the page as a      |
|                              whole appears.  At this time, such feedback is limited   |
|                              to only appear when the entire page has been answered    |
|                              correctly.                                               |
| *IMPORTANT NOTE*: If there are multiple questions on the page, either MultiFBOnPage   |
| or MultiFBOnPagePlusAdvance must be used as the feedback location indicator **OR**    |
| all the question type indicators must be the same for each question.                  |
|                                                                                       |
|                           PAGE-WIDE FEEDBACK TYPE INDICATOR                           |
| This argument indicates the type of feedback that can be applied to the entire page.  |
| This is intended to supply a cummulative feedback for a page of multiple questions,   |
| however it may be possible to emulate the feedback for a single question via the      |
| page-wide feedback. Possible values are:                                              |
|    normal                    Requires that all questions are completely correct in    |
|                              order to display page-wode positive feedback.  All other |
|                              situations display page-wide negative feedback.          |
|    partial                   If all aspects of all of the questions on the page  are  |
|                              correct or incorrect, positive or negative feedback is   |
|                              displayed, respectively. If any one of the questions on  |
|                              the page are correct, the partial feedback is displayed. |
|    none                      No page-wide feedback should appear.                     |
|                                                                                       |
|                                  QUESTION DESCRIPTORS                                 |
| Following the feedback location and page-wide feedback type indicator arguments, each |
| successive argument string represents one question in the LA.  Each question is       |
| described by its question type indicator, feedback type indicator, and correct state  |
| string (see below).                                                                   |
|   QUESTION TYPE INDICATOR                                                             |
| The question type indicator has these defined possible values:                        |
|    singlesel                 single selection multiple choice (radio buttons)         |
|    multisel                  multiple selection multiple choice (check boxes)         |
|    text                      text responses (text boxes)                              |
|    dd                        drop-down menus (select boxes)                           |
|    img                       clickable images (image)                                 |
|   FEEDBACK TYPE INDICATOR                                                             |
| Feedback type indicator has these defined possible values:                            |
|    normal                    Requires that the question is completely correct in      |
|                              order to display positive feedback.  All other           |
|                              situations display negative feedback.                    |
|    partial                   If all aspects of the question(s) are correct or         |
|                              incorrect, positive or negative feedback is displayed,   |
|                              respectively. If only one of the multiple aspects of the |
|                              question(s) are correct, the partial feedback is         |
|                              displayed.                                               |
|    responseSpecific          In this case, feedback corresponding to the selected     |
|                              option or options is/are displayed.                      |
|    none                      No question-specific feedback should appear.             |
|   CORRECT STATE STRING                                                                |
| Correct state string can take a variety of forms:                                     |
|    1                         To represent that the element should be selected or      |
|                              checked.                                                 |
|    0                         To represent that the element should NOT be selected or  |
|                              checked.                                                 |
|    71 (or other number)      To represent the VALUE of the select option that is      |
|                              correct.                                                 |
|    71,75,77 (or others)      To represent the list of possible values of the select   |
|                              option that is correct (selecting any one will correctly |
|                              answer the question).                                    |
|    gaurd (or other text)     To represent the correct text for a text box (not case   |
|                              sensitive).                                              |
|    gaurd,guard,gard (etc.)   To represent a list of possible text values for a text   |
|                              box that is correct (typing any one will correctly       |
|                              answer the question).                                    |
| When a given question has multiple options (such as a radio button group), an         |
| additional pipe (|) is added, followed by the correct state for that option.          |
|                                                                                       |
|                                     EXAMPLE USAGE                                     |
| * One question with four radio buttons, with normal feedback located on the same page |
|   as the LA:                                                                          |
|      javascript:testanswers('FBOnPage,none','singlesel,normal|1|0|0|0');              |
| * Three questions, each with a text box and each accepting two possible answers, with |
|   normal feedback where the positive FB is on another page but negative FB is on the  |
|   same page as the LA:                                                                |
|      javascript:testanswers('FBPosNext,none','text,normal|hi,high',                   |
|      'text,normal|lo,low');                                                           |
| * Same as the three question scenario above, except that page-wide partial feedback   |
|   is also displayed:                                                                  |
|      javascript:testanswers('FBPosNext,partial','text,normal|hi,high',                |
|      'text,normal|lo,low');                                                           |
| * A response-specific FB single-select question, a partial FB multi-select question,  |
|   and a drop-down with two possible answers.  Since each question is to have its own  |
|   FB displayed, the MultiFBOnPage feedback location indicator is used:                |
|      javascript:testanswers('MultiFBOnPage|none','singlesel,responseSpecific|0|1|0|0',|
|      'multisel,partial|1|1|0|1|0','dd,normal|78,80');                                 |
|                                                                                       |
|                                   INCLUDED FUNCTIONS                                  |
| testanswers; buildMatricies; validateForm; resetFeedback; unvalidatedForm;            |
| allAreAnswered; isAnswered; findCorrects; usesValue; isCorrectByState; isCorrectByVal;|
| markCorrects; yesChange; tally; feedback; testForPartial; pageAdvance; setValue;      |
| explore; flicker; changeClassById; arrayConcat;                                       |
+===========================================-===========================================+
*/

/*
+===========================================-===========================================+
|                                    GLOBAL VARIABLES                                   |
+===========================================-===========================================+
*/
	var answerMatrix = new Array();  // array of answers for each question
	var correctMatrix = new Array();  // array of T/F values indiciating
									  // the correctness of each q item
	var responseMatrix = new Array();  // will hold the forms[] array and its elements
	var qTypeMatrix = new Array();  // array of question types for the page
	var feedbackMatrix = new Array();  // array of feedback type indicators
									   // for each question
	var pageFeedbackType;  // page-wide feedback type indicator
	var feedbackLocation;  // page-wide feedback location indicator
	var total = new Object();  // info regarding score totals
	total.perQPossible = new Array();  // array of possible correct per question
	total.perQCorrect = new Array();  // array of total correct per question
	var totalQ; // number of questions on the page
	var TimeDelay = 750;  // delay in milliseconds before fb appears
	var FBMultiOnPage = 'fboninline'; // class name for on state for MultiFBOnPage
	var FBOnPage = 'fbon'; // class name for normal on state for FB
	var FBOff = 'fboff'; // class name to hide FB
	var myURL = (window.location.toString()); // grab the current URL
	var myURLParts = new Array(); // array to hold parts of URL
	myURLParts = myURL.split('.'); // split it by the dots
	var myFileName = '';
	for (var i = 0; i < (myURLParts.length-1); i++) { // put back all but the last part
		myFileName+= myURLParts[i] + "."; // also add a dot as the split() removed them
	} // end for i loop
	var myFileExt = myURLParts[i]; // the last part is the file extension
	myFileName = myFileName.substring(0,(myFileName.length-1)); // take the last dot off
															    // that we added
	var IDAppend = 'li'; // string to append to end of element ID that gets the style
	var RespRight = 'RespRight'; // class name for correct responses
	var RespWrong = 'RespWrong'; // class name for incorrect responses
	var displayXOK = true; // boolean of whether X and OK images should be applied.
							// Default is true.  Locally override to false if desired.


function testanswers () {
/*
+===========================================-===========================================+
|                                    VERSION HISTORY                                    |
| 2.0.00  2003.08.31  JEM  Initial version.                                             |
| 2.2.04  2004.04.21  JEM  Added displayXOK variable to allow option to not call the    |
|                          noteCorrects() function, if not desired.                     |
| 2.2.06  2004.05.04  JEM  Moved principle commenting block to top of file.             |
|                                        SUMMARY                                        |
| Outlines program flow for entire testAnswers functionality.                           |
|                                       PARAMETERS                                      |
| None passed in.  References global objects: testanswers.arguments; totalQ;            |
| document.forms; displayXOK; TimeDelay; feedbackLocation;                              |
|                                  DEPENDANT FUNCTIONS                                  |
| buildMatricies; resetFeedback; validateForm; findCorrects; markCorrects; tally;       |
| feedback;                                                                             |
+===========================================-===========================================+
*/
	// nine sequential steps to pull the whole thing off...
	// 1) the first argument is the feedback location indicator
	
	var temp = testanswers.arguments[0].split(',');
	feedbackLocation = temp[0];
	pageFeedbackType = temp[1];
	// 2) one form for each question, thus this is total num of questions
	totalQ = document.forms.length;
	// 3) Call to function to build the qType, feedback, and answer matricies
	buildMatricies(testanswers.arguments);
	// 4) Turn off all feedback before continuing
	resetFeedback();
	// 5) Call to function to validate the form; if false...
	if (!validateForm()) return; // ...quit entirely
	// 6) Call to function that evaluates if each element was correct
	findCorrects();
	// 7) Call to function that marks each element as appropriate
	if (displayXOK) {markCorrects();};
	// 8) Get the total correct and total possible from the totals function
	tally();
	// 9) Call to function to display appropriate feedback
	setTimeout("feedback()", TimeDelay);
} // END TEST ANSWERS FUNCTION


function buildMatricies(args) {
/*
+===========================================-===========================================+
|                                    VERSION HISTORY                                    |
| 2.2.00  2004.05.04  JEM  Initial version and any changes undocumented to date.        |
|                                        SUMMARY                                        |
| This function builds the qTypeMatrix, feedbackMatrix, answerMatrix, and               |
| responseMatrix matricies which are used through the rest of the program flow.         |
|                                       PARAMETERS                                      |
| Arguments from testanswers (reference to other function's params is deprecated.       |
| References global objects: qTypeMatrix; feedbackMatrix; answerMatrix; responseMatrix; |
| document.forms;                                                                       |
|                                  DEPENDANT FUNCTIONS                                  |
| None.                                                                                 |
+===========================================-===========================================+
*/
	var i; // counter
	var tempArray = new Array(totalQ);  // a temporary array
	var tempArray2 = new Array(totalQ);  // a temporary array

	// Loops through each of the arguments passed to testanswers()
	for (i = 0; i < totalQ; i++) {
		// For the current argument, split the string of text into separate array elements
		tempArray[i] = args[i+1].split("|");
		tempArray2[i] = tempArray[i][0].split(",");
		qTypeMatrix[i] = tempArray2[i][0];  // log the question type for this question
		feedbackMatrix[i] = tempArray2[i][1];  // log the feedback type for this question
		// slice off the first element of the tempArray; the result is the answerMatrix
		answerMatrix[i] = tempArray[i].slice(1);
	};  // end for i loop
	// Grab all the forms[] array from the document and keep it in response matrix
	responseMatrix = document.forms;
} // end buildMatricies()

function validateForm() {
/*
+===========================================-===========================================+
|                                    VERSION HISTORY                                    |
| 2.2.00  2004.05.04  JEM  Initial version and any changes undocumented to date.        |
|                                        SUMMARY                                        |
| Calls a function that validates the form and calls another function if it is not.     |
|                                       PARAMETERS                                      |
| None.                                                                                 |
|                                  DEPENDANT FUNCTIONS                                  |
| allAreAnswered; unvalidatedForm;                                                      |
+===========================================-===========================================+
*/
	if (!allAreAnswered()) {
		unvalidatedForm ();
		return false;  // This ejects us from the remainder of the testanswers() function
	}; // end if
	return true;
} // end validateForm()

function resetFeedback() {
/*
+===========================================-===========================================+
|                                    VERSION HISTORY                                    |
| 2.2.00  2004.05.04  JEM  Initial version and any changes undocumented to date.        |
| 2.2.05  2004.04.30  JEM  Replaced getting all elements for getting 'div' and 'p'      |
|                          elements as IE 5.5 did not support the '*' selector.         |
| 2.2.06  2004.05.04  JEM  Streamlined the code a bit.                                  |
|                                        SUMMARY                                        |
| Finds all elements using reserved 'on' classes and turns them off.                    |
|                                       PARAMETERS                                      |
| None passed in.  References global objects: document.elements; FBOnPage; FBOff;       |
| FBMultiOnPage;                                                                        |
|                                  DEPENDANT FUNCTIONS                                  |
| changeClassById;                                                                      |
+===========================================-===========================================+
*/
	var els1 = document.getElementsByTagName('div'); // get all of the div's on page
	var els2 = document.getElementsByTagName('p'); // get all of the p's on page
	var els = arrayConcat(els1, els2); // concatenate the above together
	for (var i = 0; i < els.length; i++) { // loop through the captured elements
	    // test to see if they are currently classed using reserved 'on' classes
		if ((els[i].className == FBOnPage) || (els[i].className == FBMultiOnPage)) {
			changeClassById (els[i].id, FBOff); // if so, turn them off			
		} // end if
	} // end for i
}
function unvalidatedForm() {
/*
+===========================================-===========================================+
|                                    VERSION HISTORY                                    |
| 2.2.00  2004.05.04  JEM  Initial version and any changes undocumented to date.        |
|                                        SUMMARY                                        |
| This function displays the appropriate alert informing the learner that the form did  |
| not validate (one or more questions on the page were not answered). This function can |
| be locally added to a page to customize these messages.                               |
|                                       PARAMETERS                                      |
| None.                                                                                 |
|                                  DEPENDANT FUNCTIONS                                  |
| None.                                                                                 |
+===========================================-===========================================+
*/
	if (totalQ == 1) { // singular question
		alert ("Please answer this question.");
	} else { // multiple questions
		alert ("Please answer all questions on this page.");
	} // end if
} // end function unvalidatedForm()

function allAreAnswered() {
/*
+===========================================-===========================================+
|                                    VERSION HISTORY                                    |
| 2.2.00  2004.05.04  JEM  Initial version and any changes undocumented to date.        |
|                                        SUMMARY                                        |
| Loops through each question, calls isAnswered to analyze it.  Returns false if any    |
| question returns from isAnswered as false.  Otherwise returns true.                   |
|                                       PARAMETERS                                      |
| None passed in.  References global objects: totalQ;                                   |
|                                  DEPENDANT FUNCTIONS                                  |
| isAnswered;                                                                           |
+===========================================-===========================================+
*/
	var i; // counter
	for (i = 0; i < totalQ; i++) {  // Loop through each question stored in the array
		if (isAnswered(i) == false) {	// if any one is not answered...
			return false; // ...they are not all answered
		};	// end if	
	}; // end for
	return true; // if you get this far, they were all answered
} // end allAreAnswered

function isAnswered(currentQ) {
/*
+===========================================-===========================================+
|                                    VERSION HISTORY                                    |
| 2.2.00  2004.05.04  JEM  Initial version and any changes undocumented to date.        |
| 2.2.07  2004.05.18  JEM  Streamlined code by calling usesValue instead of evaluating  |
|                          such itself.                                                 |
|                                        SUMMARY                                        |
| Given the current question number, loop through all of the elements within that       |
| question's form element and ensure that at least one element per form is either       |
| checked or has a value.                                                               |
|                                       PARAMETERS                                      |
| currentQ - index of current question.  References global objects: responseMatrix;     |
| qTypeMatrix;                                                                          |
|                                  DEPENDANT FUNCTIONS                                  |
| usesValue;                                                                            |
+===========================================-===========================================+
*/
	var i; // counter
	// Loop through each option within the question
	for (i = 0; i < responseMatrix[currentQ].length; i++) {
		// for those LA types that are value-based
		if (usesValue(currentQ)) {
			if (responseMatrix[currentQ][i].value !== '') {
				// if any are selected or a text value provided, the question was answered
				return true;
			 }; // end if responseMatrix.value
		} else { // for the rest of the LA types that are indicated by selected states
			if (responseMatrix[currentQ][i].checked) {
				return true;  // if any are checked, the question was answered
			 }; // end if responseMatrix.checked
		}; // end if qTypeMatrix
	}; // end for
	return false; // if you get this far, the question was not answered
} // end isAnswered

function findCorrects () {
/*
+===========================================-===========================================+
|                                    VERSION HISTORY                                    |
| 2.2.00  2004.05.04  JEM  Initial version and any changes undocumented to date.        |
|                                        SUMMARY                                        |
| Given an array of question elements and an array of the appropriate responses, record |
| which items were correctly answered.                                                  |
|                                       PARAMETERS                                      |
| None passed in.  References global objects: totalQ; responseMatrix; answerMatrix;     |
| correctMatrix;                                                                        |
|                                  DEPENDANT FUNCTIONS                                  |
| isCorrectByVal; isCorrectByState; usesValue;                                          |
+===========================================-===========================================+
*/
	var j; // counter
	var k; // counter
	var possAns = new Array(); // will hold possible answers

	//Loop through all of the responses and check against the answers provided to testanswers()
	for (j = 0; j < totalQ; j++) {  // Loop through all of the questions; j tracks current question
		// Each time we come to a new question, rebuild the currQCorrects temporary array so
		// that it is of same size as the total number of options on this item
		var currQCorrects = new Array(responseMatrix[j].length);
		// Loop through all of the options of the current question
		for (k = 0; k < responseMatrix[j].length; k++) {
			// Go check to see if the current option of the current question was answered
			// correctly.  currQCorrects then holds the result for all the options of the
			// current question.
			possAns = answerMatrix[j][k].split(","); // parse possible answers
			if (usesValue(j)) {
				// evaluate the elements based on their value
				currQCorrects[k] = isCorrectByVal(j,k,possAns);
			} else {
				// evaluate the elements based on their state
				currQCorrects[k] = isCorrectByState(j,k,possAns);
			} // end if qTypeMatrix[j]
		} // end for k loop
		// Now take all of the item results and store them in the correctMatrix
		// that will house all of the results from all of the questions
		correctMatrix[j] = currQCorrects;
	} // end for j loop
	return;
} // end findCorrects()

function usesValue(currentQ) {
/*
+===========================================-===========================================+
|                                    VERSION HISTORY                                    |
| 2.2.00  2004.05.04  JEM  Initial version and any changes undocumented to date.        |
|                                        SUMMARY                                        |
| Given a question, check it for a set of possible conditions that would qualify it as  |
| an element that should be dealt with by using its value.                              |
|                                       PARAMETERS                                      |
| None passed in.  References global objects: qTypeMatrix;                              |
|                                  DEPENDANT FUNCTIONS                                  |
| None.                                                                                 |
+===========================================-===========================================+
*/
	var boolUsesValue;
	boolUsesValue = (boolUsesValue || (qTypeMatrix[currentQ] == 'text'));
	boolUsesValue = (boolUsesValue || (qTypeMatrix[currentQ] == 'dd'));
	boolUsesValue = (boolUsesValue || (qTypeMatrix[currentQ] == 'img'));
	return boolUsesValue;
} // end usesValue

function isCorrectByState(qNumber, eNumber, possAns) {
/*
+===========================================-===========================================+
|                                    VERSION HISTORY                                    |
| 2.2.00  2004.05.04  JEM  Initial version and any changes undocumented to date.        |
|                                        SUMMARY                                        |
| Given the state of an option from a single question and the desired state of the      |
| corresponding option from the same question, see if the state was correct.            |
|                                       PARAMETERS                                      |
| None passed in.  References global objects: responseMatrix; possAns;                  |
|                                  DEPENDANT FUNCTIONS                                  |
| None.                                                                                 |
+===========================================-===========================================+
*/
   var k; // counter
   for (k = 0; k < possAns.length; k++) { // loop through each possible answer
		// if the control matches the answer key...
		if (responseMatrix[qNumber][eNumber].checked == possAns[k]) {
			return true; // the option is correct
		}; // end if
   } // end for k
	return false; // if you get this far, it was wrong
} // end isCorrect()

function isCorrectByVal(qNumber, eNumber, possAns) {
/*
+===========================================-===========================================+
|                                    VERSION HISTORY                                    |
| 2.2.00  2004.05.04  JEM  Initial version and any changes undocumented to date.        |
|                                        SUMMARY                                        |
| Given the value of an option from a single question and the desired value of the      |
| corresponding option from the same question, see if the value was correct.            |
|                                       PARAMETERS                                      |
| None passed in.  References global objects: responseMatrix; possAns;                  |
|                                  DEPENDANT FUNCTIONS                                  |
| None.                                                                                 |
+===========================================-===========================================+
*/
	var k; // counter
	for (k = 0; k < possAns.length; k++) {  // Loop through all of the acceptable answers
		// if the control matches the answer key... (drop all caps to make it not case sensitive)
		if (responseMatrix[qNumber][eNumber].value.toLowerCase() == possAns[k].toLowerCase()) {
			return true; // the option is correct
		}; // end if
	} // end for k
	return false; // if you get this far, it was wrong
} // end isCorrect()

function markCorrects() {
/*
+===========================================-===========================================+
|                                    VERSION HISTORY                                    |
| 2.2.00  2004.05.04  JEM  Initial version and any changes undocumented to date.        |
|                                        SUMMARY                                        |
| Given a matrix of what elements were correctly answered, mark the appropriate ones by |
| changing the class of a corresponding element.                                        |
|                                       PARAMETERS                                      |
| None passed in.  References global objects: responseMatrix; qTypeMatrix; IDAppend;    |
| RespRight; RespWrong; correctMatrix;                                                  |
|                                  DEPENDANT FUNCTIONS                                  |
| yesChange; changeClassById;                                                           |
+===========================================-===========================================+
*/
	var i; // counter
	var j; // counter
	var thisEl; // shortcut var
	var idToChange; // holds the final id of the element to adopt the class
	for (i = 0; i < totalQ; i++) { // loop through each question
		for (j = 0; j < responseMatrix[i].length; j++) {
			thisEl = responseMatrix[i][j]; // set shortcut var
			if (yesChange(thisEl)) { // if one of the above was true
				if (qTypeMatrix[i] == 'img') {
					idToChange = thisEl.id + "r" + thisEl.value; // Special ID for image fb
				} else {
					idToChange = thisEl.id + IDAppend;  // Append to match the ID of the container LI
				} // end if qTypeMatrix
				if (correctMatrix[i][j] == true) { // If they got the current item right
					changeClassById(idToChange, RespRight);  // Change an element to the RespRight class
				} else { // else they got it wrong
					changeClassById(idToChange, RespWrong);  // Change an element to the RespWrong class
				}; // end if true # 2
			}; // end if checked
		}; // end for j
	}; // end for i	
} // end markCorrects()

function yesChange(thisEl) {
/*
+===========================================-===========================================+
|                                    VERSION HISTORY                                    |
| 2.2.00  2004.05.04  JEM  Initial version and any changes undocumented to date.        |
|                                        SUMMARY                                        |
| Given the element in question, check a set of possible conditions that would qualify  |
| it as an element that should have local feedback (X and OK) applied to it.            |
|                                       PARAMETERS                                      |
| thisEl - a DOM reference to a form element on the page.                               |
|                                  DEPENDANT FUNCTIONS                                  |
| None.                                                                                 |
+===========================================-===========================================+
*/
	var boolToChange = false; // holds true if the current element should by styled
	// only mark feedback on the element if it...
	// ...is checked
	boolToChange = ((thisEl.checked));
	// ...has a value but isn't 'on' (value of radio buttons and check boxes)
	boolToChange = (boolToChange || ((thisEl.value != '') && (thisEl.value != 'on')));
	// ...it a textbox
	boolToChange = (boolToChange || thisEl.type == 'text');
	return boolToChange;
} // end yesChange()

function tally() {
/*
+===========================================-===========================================+
|                                    VERSION HISTORY                                    |
| 2.2.00  2004.05.04  JEM  Initial version and any changes undocumented to date.        |
|                                        SUMMARY                                        |
| Given a matrix of what elements were correctly answered, record total possible and    |
| total correct for each question and for all questions.                                |
|                                       PARAMETERS                                      |
| None passed in.  References global objects: totalQ; total.possible; total.correct;    |
| total.perQPossible; total.perQCorrect; responseMatrix; correctMatrix;                 |
|                                  DEPENDANT FUNCTIONS                                  |
| None.                                                                                 |
+===========================================-===========================================+
*/
	var i; // counter
	var j; // counter
	total.possible = totalQ; // initalize total possible to zero
	total.correct = 0; // initalize total correct to zero
	
	for (i = 0; i < totalQ; i++) { // loop through each question
		total.perQPossible[i] = 0; // initalize possible for the current question to zero
		total.perQCorrect[i] = 0; // initalize correct for the current questiont to zero
		for (j = 0; j < responseMatrix[i].length; j++) { // loop through the elements in the question
			total.perQPossible[i]++; // add one to total possible for this question
			if (correctMatrix[i][j] == true) { // If they got the current item right
				total.perQCorrect[i]++; // note it
			}; // end if true # 2
		}; // end for j
		// If all elements in this question were correct ...
		if (total.perQPossible[i] == total.perQCorrect[i]) {
				total.correct++; // ...then the entire question was correct
		} // end if correct
	}; // end for i
}  // end tally()

function feedback() {
/*
+===========================================-===========================================+
|                                    VERSION HISTORY                                    |
| 2.2.00  2004.05.04  JEM  Initial version and any changes undocumented to date.        |
| 2.2.06  2004.05.04  JEM  Added support for MultiFBOnPagePlusPageFB feedbackLocation.  |
|                                        SUMMARY                                        |
| Based upon both the feedbackLocation and feedbackMatrix, display the appropriate      |
| feedback or advance to the appropriate page.  This function displays feedback per     |
| per question, with the exception of when the feedback location is set to FBNextPage,  |
| in which, if a question is also given a feedback type other than none, the page will  |
| advance.                                                                              |
|                                       PARAMETERS                                      |
| None passed in.  References global objects: feedbackLocation; total.correct;          |
| total.possible; total.perQCorrect; total.perQPossible; FBOnPage; FBMultiOnPage;       |
| feedbackMatrix; responseMatrix;                                                       |
|                                  DEPENDANT FUNCTIONS                                  |
| pageAdvance; changeClassById; yesChange; testForPartial; flicker; usesValue;          |
| pageFeedback;                                                                         |
+===========================================-===========================================+
*/
	var i; // counter
	var j; // counter
	var eligibleForPartial; // boolean to indicate if current q qualifies for partial FB
	var fbStyleToUse = (totalQ == 1) ? FBOnPage : FBMultiOnPage; // If it is the only one, give it standard FB styles;
															// else styles for multiple questions on the page
	for (i = 0; i < totalQ; i++) { // loop through each question to display fb per question
		switch (feedbackLocation) {
			case ('FBPosNext'):
				if (total.correct == total.possible) {
					pageAdvance('p');  // all correct and next page
					break;
				}
				// *NO* break; (we also want the following to happen)
			case ('FBOnPage'):
				switch (feedbackMatrix[i]) {
					case ('responseSpecific'): 
						for (j = 0; j < responseMatrix[i].length; j++) {  // Loop through each item within the current question
							if (yesChange(responseMatrix[i][j])) {  // for selected responses...
								if (usesValue(i)) { // ...display appropriate feedback
									changeClassById ("fb" + i + "r" + responseMatrix[i][j].value, fbStyleToUse);  
								} else {
									changeClassById ("fb" + i + "r" + j, fbStyleToUse);
								} // end if usesValue
							} // end if checked
						} // end for j loop
						break; // end case responseSpecific
					case ('partial'):
						eligibleForPartial = testForPartial(i);  // check if partially correct or better
						if (total.perQCorrect[i] == total.perQPossible[i]) {  // all correct
							flicker ("fb" + i + "p", fbStyleToUse, FBOff);
						} else if (eligibleForPartial == true) {  // partially correct
							flicker ("fb" + i + "part", fbStyleToUse, FBOff);
						} else {  // must be wrong
							flicker ("fb" + i + "n", fbStyleToUse, FBOff);
						}; // end if
						break;  // end case partial
					case ('normal'):
						if (total.perQCorrect[i] == total.perQPossible[i]) {  // all correct
							flicker ("fb" + i + "p", fbStyleToUse, FBOff);
						} else {  // simply wrong
							flicker ("fb" + i + "n", fbStyleToUse, FBOff);
						}  // end if correct
						break;  // end case normal
					case ('none'):
						break;
				}; // end switch feedbackMatrix[i]
			break;  // end case FBOnPage and FBPosNext
		case ('FBNextPage'):
			switch (feedbackMatrix[i]) {
				case ('responseSpecific'): // this can only apply when there is only 1 question on the page, so assume as such
					for (j = 0; j < responseMatrix[0].length; i++) {
						if (yesChange(responseMatrix[0][j])) { // whichever is checked...
							pageAdvance(j); // triggers the fb
						}  // end if checked
					}  // end if i
					break; // end case responseSpecific
				case ('partial'): // this can only apply when there is only 1 question on the page, so assume as such
					eligibleForPartial = testForPartial(0);
					// This is the partially correct allowed approach to displaying feedback
					if (eligibleForPartial == true) { // all correct already handled
						pageAdvance('part');
					} else {
						pageAdvance('n');
					} // end false condition; end of if
					break; // end case partial
				case ('normal'): // this can only apply when there is only 1 question on the page, so assume as such
					if (total.correct == total.possible) {
						pageAdvance('p');
					} else {
						pageAdvance('n');
					}; // end false condition; end of if
					break; // end case partial
				case ('none'): // only when the question-specific feedback is set to none is the page allowed to evaluate it's feedback
					break;
			} // end switch feedbackMatrix[0]
		}; // end switch feedbackLocation
	}; // end for i
	pageFeedback(); // call to handle page-wide feedback, if any
} // end feedback()

function pageFeedback() {
/*
+===========================================-===========================================+
|                                    VERSION HISTORY                                    |
| 2.2.07  2004.05.17  JEM  Introduced.                                                  |
|                                        SUMMARY                                        |
| Based upon the feedback location and the page-wide feedback type indicator, display   |
| page-wide feedback or advance the page as appropriate.                                |
|                                       PARAMETERS                                      |
| None passed in.  References to global objects: feedbackLocation; total.correct;       |
| total.possible; FBOnPage; FBOff;                                                      |
|                                  DEPENDANT FUNCTIONS                                  |
| pageAdvance; flicker;                                                                 |
+===========================================-===========================================+
*/
	switch (feedbackLocation) {
		case ('FBPosNext'):
			if (total.correct == total.possible) {
				pageAdvance('p');  // all correct and next page
				break; // break now so other fb does not appear
			}
			// *NO* break; (we also want the following to happen)
		case ('FBOnPage'):
			switch (pageFeedbackType) {
				case ('partial'):
					if (total.correct > 0) {
						flicker ("pagefbpart", FBOnPage, FBOff);
						break; // break now so negfb does not appear
					}
					// *NOTE* No break, we want the case for normal to ensue if we get this far
				case ('normal'):
					if (total.correct == total.possible) {
						flicker ("pagefbp", FBOnPage, FBOff);
					} else {
						flicker ("pagefbn", FBOnPage, FBOff);
					}
					break;
				case ('none'):
					break;
			} // end switch
			break;
		case ('FBNextPage'):
			switch (pageFeedbackType) {
				case ('partial'):
					if (total.correct > 1) {
						pageAdvance('part');
					}
					// *NOTE* No break, we want the case for normal to ensue if we get this far
				case ('normal'):
					pageAdvance('n'); // if they are not all correct, it must be wrong
					break;
				case ('none'):
					break;
			} // end switch
			break;
	}
} // end pageFeedback()

function testForPartial(qNumber) {
/*
+===========================================-===========================================+
|                                    VERSION HISTORY                                    |
| 2.2.00  2004.05.04  JEM  Initial version and any changes undocumented to date.        |
|                                        SUMMARY                                        |
| Given an index to the matrix of what elements were correctly answered, record total   |
| possible and total correct for each question and for all questions.                   |
|                                       PARAMETERS                                      |
| qNumber - index for current question number.  References global objects:              |
| responseMatrix; correctMatrix;                                                        |
|                                  DEPENDANT FUNCTIONS                                  |
| None.                                                                                 |
+===========================================-===========================================+
*/
	// Loop through each item within the current question
	for (var j = 0; j < responseMatrix[qNumber].length; j++) {
		// If they got the current item right and it was checked
		if ((correctMatrix[qNumber][j] == true) && (responseMatrix[qNumber][j].checked)) {
				return true; // they are eligible for partial correct credit.
		}; // end if true # 1
	}; // end for j loop
	return false; // must not be eligible for partial
} // end testForPartial

function pageAdvance(fileNameSuffix) {
/*
+===========================================-===========================================+
|                                    VERSION HISTORY                                    |
| 2.2.00  2004.05.04  JEM  Initial version and any changes undocumented to date.        |
| 2.2.06  2004.05.04  JEM  Added logic to strip "_la" from the current URL, if present. |
|                                        SUMMARY                                        |
| Given the string that should be added to the filename, go to the URL by the new name. |
|                                       PARAMETERS                                      |
| fileNameSuffix - extension extracted from current URL.  References global objects:    |
| myFileName; window.location; myFileExt;                                               |
|                                  DEPENDANT FUNCTIONS                                  |
| None.                                                                                 |
+===========================================-===========================================+
*/
	if (myFileName.substring((myFileName.length-3),(myFileName.length)) == "_la") {
		myFileName = myFileName.substring(0,(myFileName.length-3));
	}
	window.location = (myFileName + "_" + fileNameSuffix + "f." + myFileExt);
} // end pageAdvance

function setValue(elementID, newVal) {
/*
+===========================================-===========================================+
|                                    VERSION HISTORY                                    |
| 2.2.00  2004.05.04  JEM  Initial version and any changes undocumented to date.        |
|                                        SUMMARY                                        |
| Given the ID of the desired element and the new value for that element, assign the    |
| new value to the element.                                                             |
|                                       PARAMETERS                                      |
| elementID - the ID of the desired element; newVal - the new value for that element.   |
|                                  DEPENDANT FUNCTIONS                                  |
| None.                                                                                 |
+===========================================-===========================================+
*/
	identity = document.getElementById(elementID);
	identity.value = newVal;
} // end setValue

function explore (prefix, myNum, total, onClass, offClass) {
/*
+===========================================-===========================================+
|                                    VERSION HISTORY                                    |
| 1.0.00  2004.05.04  JEM  Initial version and any changes undocumented to date.        |
| 1.0.01  2004.05.04  JEM  Added functionality to not turn any element back on (reset). |
|                                        SUMMARY                                        |
| Turns off all elements with an id within a specified sequence, then turns on the      |
| desired element out of that sequence.                                                 |
|                                       PARAMETERS                                      |
| prefix - the initial portion of the id's for a series of desired elements.            |
| myNum - of all of the elements within the series, the specific one to turn on.        |
| total - the total (upperBound) of the elements in the series.                         |
| onClass - the class to assign to the element that should remain on.                   |
| offClass - the class to assign to the elements to be turned off.                      |
|                                  DEPENDANT FUNCTIONS                                  |
| changeClassById;                                                                      |
|                                     EXAMPLE USAGE                                     |
| In the HTML: <div id="els1">...</div><div id="els2">...</div><div id="els3">...</div> |
| The JS call: explore('els',2,3,'fbon','fboff');                                       |
| assuming the second div is desired, and 'fbon' and 'fboff' were appropriatly defined  |
| in the CSS.                                                                           |
+===========================================-===========================================+
*/
	for (i = 1; i <= total; i++) {
		currEl = prefix + i;
		changeClassById (currEl, offClass);
	}
	if (myNum != '') {
		currEl = prefix + myNum;
		changeClassById (currEl, onClass);
	}
} // end explore

function flicker (id, onClass, offClass) {
/*
+===========================================-===========================================+
|                                    VERSION HISTORY                                    |
| 1.0.00  2004.05.04  JEM  Initial version and any changes undocumented to date.        |
|                                        SUMMARY                                        |
| Is called in place of changeClassById as a preface to that function in order to fix a |
| slight bug in Netscape 6 in which content changing from display:none; to              |
| display:block; does not appear.  The solution is to display the content, hide it,     |
| then display it again, hence the name flicker.  Not necessary if not supporting NS6.  |
|                                       PARAMETERS                                      |
| id - id of the element in question.                                                   |
| onClass - the class to assign to the element to hide it.                              |
| offClass - the class to assign to the elements to show it.                            |
|                                  DEPENDANT FUNCTIONS                                  |
| changeClassById;                                                                      |
|                                     EXAMPLE USAGE                                     |
| In the HTML: <div id="els1">...</div>                                                 |
| The JS call: flicker ('els1','fbon','fboff');                                         |
| assuming 'fbon' and 'fboff' were appropriatly defined in the CSS.                     |
+===========================================-===========================================+
*/
	changeClassById (id, onClass);
	changeClassById (id, offClass);
	changeClassById (id, onClass);
} // end flicker
		
		
function changeClassById(id, newClass) {
/*
+===========================================-===========================================+
|                                    VERSION HISTORY                                    |
| 1.0.00  2004.05.04  JEM  Initial version and any changes undocumented to date.        |
|                                        SUMMARY                                        |
| Given the ID attribute of the desired HTML element and the newClass to which the      |
| element should change, do just that and assign newClass to the class property of the  |
| the element ID. Rename of the change() function.                                      |
|                                       PARAMETERS                                      |
| id - id of the element in question.                                                   |
| newClass - the desired class to assign to the element.                                |
|                                  DEPENDANT FUNCTIONS                                  |
| None.                                                                                 |
|                                     EXAMPLE USAGE                                     |
| In the HTML: <div id="els1">...</div>                                                 |
| The JS call: flicker ('els1','fbon');                                                 |
| ...asigns the class 'fbon' to the element with an id of 'els1'.                       |
+===========================================-===========================================+
*/
	//alert (id + " to class " + newClass); // good for debugging
	var identity=document.getElementById(id);
	identity.className=newClass;
} // end changeClassById()

function arrayConcat(array1, array2) {
/*
+===========================================-===========================================+
|                                    VERSION HISTORY                                    |
| 1.0.00  2004.05.04  JEM  Initial version and any changes undocumented to date.        |
|                                        SUMMARY                                        |
| Given two arrays, returns one array containing the elements of the first followed by  |
| the elements of the second. Suggested enhancements: allow n arrays to be passed in    |
| and loop through the arguments and concatenate them all together; test for m-         |
| dimensions and concatenate across each.                                               |
|                                       PARAMETERS                                      |
| array1, array2 - two single-dimensional arrays.                                       |
|                                  DEPENDANT FUNCTIONS                                  |
| None.                                                                                 |
|                                     EXAMPLE USAGE                                     |
| The JS call: foodArray = arrayConcat(fruitsArray, vegetablesArray);                   |
+===========================================-===========================================+
*/
	var returnArray = new Array();
	for (var i=0; i<array1.length; i++) {
		returnArray[returnArray.length] = array1[i];
	}
	for (var j=0; j<array2.length; j++) {
		returnArray[returnArray.length] = array2[j];
	}
	return returnArray;
}

