/*
+===========================================-===========================================+
|                               TEST ANSWERS VERSION 2.3                                |
|===========================================-===========================================|
|                                    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.   |
| 2.3.00  2004.08.27  JEM  Externalized variables so that no params are passed into     |
|                          testanswers(), rather variables are explicitly declared on   |
|                          the page; other variables declared, so they too can be over- |
|                          ridden; added ability to declare URLs for FB pages; added    |
|                          functionality that only analyzes those form elements that    |
|                          are classed as taFormClass's value; added support for        |
|                          question feedback "single" and type "singleselgroup".  No    |
|                          longer compatable with 2.2.xx series, hence the 2.3.00.      |
| 2.3.01  2004.12.15  JEM  Added support for layered feedback.                          |
| 2.3.02  2005.01.21  JEM  Defined a series variables which allows the branching logic  |
|                          to handle different pf page URL calculations per series.     |
| 2.3.03  2005.04.28  YB   Added renderFeedback function to allow a jump to element     |
|                          feature when neccessary                                      |
| 2.3.04  2005.08.10  JEM  Changed renderFeedback to use scrollIntoView; ensured the    |
|                          responseMatrix did not contain Flash elements to fix a bug   |
|                          in IE.  Added TriU-specific code.                            |
| 2.3.05  2006.04.12  JEM  Modified yesChange() function to accurately not style radio  |
|                          buttons that had values (not common).  Added question level  |
|                          reporting functionality via functions feedback and           |
|                          questionLevelReporting and the enableQuestionLevelReporting  |
|                          variable.  Added ability to skip elements within a form via  |
|                          a skipElClass variable and an update to buildResponseMatrix  |
|                          function.  Declared answerStrings to avoid JS warnings.      |
|                                                                                       |
|                                        SUMMARY                                        |
| This collection of functions takes values defined on each page or defaulted in this   |
| file as the parameters by which a page's interactive elements are analyzed and        |
| feedback is displayed.                                                                |
|                                                                                       |
|                                  REQUIRED PARAMETERS                                  |
| Local to each page (or globally to a project, should that be desired), the following  |
| variables must be declared: Feedback Location Indicator, Page Feedback Type, Question |
| Type Indicator, Feedback Type Indicator, Correct Response String (see all below).     |
|                                                                                       |
|                              FEEDBACK LOCATION INDICATOR                              |
| Indicated by storing a value in the feedbackLocation variable. This value indicates   |
| what feedback should appear where for a given interaction.                            |
| Values for the 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.                                               |
|                                                                                       |
|                           PAGE-WIDE FEEDBACK TYPE INDICATOR                           |
| Indicated by storing a value in the pageFeedbackType variable. This value 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. |
|    single                    The same feedback is offered regardless of the response. |
|    none                      No page-wide feedback should appear.                     |
|                                                                                       |
|                                 QUESTION TYPE INDICATOR                               |
| The question type for each question is stored in the qTypeMatrix array.  This         |
| 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                              |
| The feedback type for each question is stored in the feedbackMatrix array.  This      |
| 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.                      |
|    single                    The same feedback is offered regardless of the response. |
|    none                      No question-specific feedback should appear.             |
|                                                                                       |
|                                   CORRECT STATE STRING                                |
| The correct answers for each question are stored in the answerStrings array.  The     |
| 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.                                                 |
|    1,0                       To represent that the element may be checked or not.     |
|    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                                     |
| All forms to be analyzed should be tagged with the following:                         |
|   <form action="javascript:testanswers()" class="taForm">                             |
| Additionally, a script block should be included in the head, indicating the required  |
| values for each of the above.  Examples of such script blocks are as follows:         |
| * One question with four radio buttons, with normal feedback located on the same page |
|   as the LA:                                                                          |
|      <script type="text/javascript">                                                  |
|         feedbackLocation = "FBOnPage";                                                |
|         pageFeedbackType = "none";                                                    |
|         qTypeMatrix = ["singlesel"];                                                  |
|         feedbackMatrix = ["normal"];                                                  |
|         answerStrings = ["1|0|0|0"];                                                  |
|      </script>                                                                        |
| * 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:                                                                |
|      <script type="text/javascript">                                                  |
|         feedbackLocation = "FBPosNext";                                               |
|         pageFeedbackType = "none";                                                    |
|         qTypeMatrix = ["text","text"];                                                |
|         feedbackMatrix = ["normal","normal"];                                         |
|         answerStrings = ["hi,high","lo,lo"];                                          |
|      </script>                                                                        |
| * A response-specific FB single-select question with normal page-wide feedback, a     |
|   partial FB multi-select question, and a drop-down with two possible answers:        |
|      <script type="text/javascript">                                                  |
|         feedbackLocation = "FBOnPage";                                                |
|         pageFeedbackType = "normal";                                                  |
|         qTypeMatrix = ["singlesel","multisel","dd"];                                  |
|         feedbackMatrix = ["responseSpecific","partial","normal"];                     |
|         answerStrings = ["0|1|0|0","1|1|0|1|0","78,80"];                              |
|      </script>                                                                        |
|                                                                                       |
|                                   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 = 'layeron'; // class name for on state for MultiFBOnPage
	var FBOnPage = 'layeron'; // class name for normal on state for FB
	var FBOff = 'off'; // class name to hide FB
	var myFileName; // will hold URL up to the extension
	var myFileExt; // will hold the file extension
	var skipElClass = "taSkip"; // class name for form elements to be ignored by testanswers
	var enableQuestionLevelReporting = false; // boolean of whether a string should be added to a
												// "skipped" form field reflecting the correctness
												// of each question.
	var qlrMsgCorrect = "Correct"; // Question level reporting correct message
	var qlrMsgIncorrect = "Incorrect"; // Question level reporting incorrect message
	var answerStringDelimiter = "|"; // the character that separates each answer in the
									 // answer string for each question
	var multipleAnswerDelmiter = ","; // if one response can have multiple answers, this is
									  // the separator that is used
	var qfbPrefix = "fb"; // the character string that begins the feedback DIVs
	var responseIndicator = "r"; // for response-specific feedback DIVs, this follows the
								 // the question number
	var positiveIndicator = "p"; // positive feedback DIVs end with this
	var partialIndicator = "part"; // partial feedback DIVs end with this
	var negativeIndicator = "n"; // negative feedback DIVs end with this
	var positiveUrlOverride = ""; // specify onpage to override the calculated URL for positive FB
	var negativeUrlOverride = ""; // specify onpage to override the calculated URL for negative FB
	var partialUrlOverride = ""; // specify onpage to override the calculated URL for partial FB
	var pagePositiveFbId = "pagefbp"; // ID for the page-wide positive feedback DIV
	var pageNegativeFbId = "pagefbn"; // ID for the page-wide negative feedback DIV
	var pagePartialFbId = "pagefbpart"; // ID for the page-wide partial feedback DIV
	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 taFormClass = 'taForm'; // class name of forms to be analyzed by testanswers
	var feedbackTags = ["p","div"]; // array of tags that could hold on-page feedback
	var displayXOK = true; // boolean of whether X and OK images should be applied.
							// Default is true.  Locally override to false if desired.
	var seriesName = "TriU"; // series declaration: FitPro, PASS, Bronze, ALP, TriU are choices.
	var answerStrings; // 2.3.05 Added to remove JS warnings.


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.             |
| 2.3.00  2004.08.30  JEM  Removed passed parameters - using global variables, instead. |
|                          Changed processing slightly to accomodate.                   |
|                                        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                                  |
| getFileName; getFileExtension; buildResponseMatrix; splitArrayElements; resetFeedback;|
| validateForm; findCorrects; tally; markCorrects; feedback;                            |
+===========================================-===========================================+
*/
	myFileName = getFileName (window.location.toString()); // get the file name
	myFileExt = getFileExtension (window.location.toString()); // get the file extension
	buildResponseMatrix (document.forms,taFormClass); // create the response Matrix
	totalQ = responseMatrix.length; // calculate how many total questions there are
	answerMatrix = splitArrayElements(answerStrings,answerStringDelimiter); // build the
																		// answer matrix
	resetFeedback(); // turn off any existing feedback
	if (!validateForm()) return; // ...quit entirely if forms do not validate
	findCorrects(); // figure out what responses are correct
	tally(); // tally the corrects
	if (displayXOK) {markCorrects();}; // mark the corrects
	setTimeout("feedback()", TimeDelay); // display appropriate feedback
} // END TEST ANSWERS FUNCTION

function splitArrayElements (stringArray, delimiter) {
/*
+===========================================-===========================================+
|                                    VERSION HISTORY                                    |
| 2.3.00  2004.08.26  JEM  Remnant of buildMatricies() reserved for answer matrix       |
|                                        SUMMARY                                        |
| This function takes an array and a delimiter and parses each element of the array     |
| into another array of elements as delimited by the delimiter.                         |
|                                       PARAMETERS                                      |
| An array of strings and a delimiter found within each array element.                  |
|                                  DEPENDANT FUNCTIONS                                  |
| None.                                                                                 |
+===========================================-===========================================+
*/
	var theMatrix = new Array();
	var i = 0;
	for (i = 0; i < stringArray.length; i++) {
		theMatrix[i] = stringArray[i].split(delimiter);
	}
	return theMatrix;
}

function buildResponseMatrix (collection, classFlag) {
/*
+===========================================-===========================================+
|                                    VERSION HISTORY                                    |
| 2.3.00  2004.08.26  JEM  Initial version.                                             |
| 2.3.04  2005.08.10  JEM  Added removal of non-form elements reported by the browser   |
|                          to be in the collection to counter a bug in IE where Flash   |
|                          elements are counted as form elements.                       |
| 2.3.05  2006.04.11  JEM  Added condition to skip skipElClass elements.                |
|                                        SUMMARY                                        |
| This function loops through a given collection and takes any of the elements within   |
| the collection that are classed as classFlag and adds them to the responseMatrix      |
| array.  NOTE: attempting to return an array of [object HTMLCollection] crashes all    |
| Netscape-compatible browsers (not sure if such is a bug or according to JS spec).     |
|                                       PARAMETERS                                      |
| A collection of DOM elements (typically document.forms) and the class of those        |
| elements that flags for analysis by testanswers.                                      |
|                                  DEPENDANT FUNCTIONS                                  |
| None.                                                                                 |
+===========================================-===========================================+
*/
	responseMatrix = new Array(); // must reset Array in event of resubmission
	var tempArray = new Array();
	var i = 0, j = 0;
	for (i = 0; i < collection.length; i++) { // loop through the collection
		if (collection[i].className.indexOf(classFlag) != -1) { // if the element contains the flag
			tempArray[i] = new Array();
			for (j = 0; j < collection[i].length; j++) { // loop through all elements of current form
				if ((collection[i].elements[j].type != "") && (collection[i].elements[j].className.indexOf(skipElClass) < 0)) { // don't allow IE to include Flash objects as part of our form collection
					tempArray[i][tempArray[i].length] = collection[i].elements[j]; // add our filtered elements to a temp array
				}
			}
			responseMatrix[responseMatrix.length] = tempArray[i]; // add our filtered array to the responseMatrix
		}
	}
}
function getFileName (theURL) {
/*
+===========================================-===========================================+
|                                    VERSION HISTORY                                    |
| 2.3.00  2004.08.26  JEM  Extracted from anonymous function to its own function.       |
|                                        SUMMARY                                        |
| This function analyzes the passed URL to parse it to return the extension.            |
|                                       PARAMETERS                                      |
| The URL of interest.                                                                  |
|                                  DEPENDANT FUNCTIONS                                  |
| None.                                                                                 |
+===========================================-===========================================+
*/
	var theFileName = "";
	var theURLParts = new Array(); // array to hold parts of URL
	theURLParts = theURL.split('.'); // split it by the dots
	for (var i = 0; i < (theURLParts.length-1); i++) { // put back all but the last part
		theFileName += theURLParts[i] + "."; // also add a dot as the split() removed them
	} // end for i loop
	theFileName = theFileName.substring(0,(theFileName.length-1)); // take the last dot off
															    // that we added
	return theFileName;
}

function getFileExtension (theURL) {
/*
+===========================================-===========================================+
|                                    VERSION HISTORY                                    |
| 2.3.00  2004.08.26  JEM  Extracted from anonymous function to its own function.       |
|                                        SUMMARY                                        |
| This function analyzes the passed URL to parse it to return all but the extension.    |
|                                       PARAMETERS                                      |
| The URL of interest.                                                                  |
|                                  DEPENDANT FUNCTIONS                                  |
| None.                                                                                 |
+===========================================-===========================================+
*/
	var theFileExtension;
	var theURLParts = new Array(); // array to hold parts of URL
	theURLParts = theURL.split('.'); // split it by the dots
	theFileExtension = theURLParts[theURLParts.length-1]; // the last part is the file extension
	return theFileExtension;
} // end getFileExtension()

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.                                  |
| 2.3.00  2004.08.30  JEM  Restructured code to loop through array of elements, instead.|
|                                        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 els = new Array();
	var i = 0;
	var j = 0;
	for (i = 0; i < feedbackTags.length; i++) { // loop through possible feedback tags
		els = new Array(); // reset the els array
		els = document.getElementsByTagName(feedbackTags[i]); // grab the current els
		for (j = 0; j < els.length; j++) { // loop through the captured elements
		    // test to see if they are currently classed using reserved 'on' classes
			if ((els[j].className == FBOnPage) || (els[j].className == FBMultiOnPage)) {
				changeClassById (els[j].id, FBOff); // if so, turn them off			
			} // end if
		} // end for j
	}
}
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.  References global object: totalQ;                                              |
|                                  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.        |
| 2.3.00  2004.08.30  JEM  Forced currQCorrects to reinitalize each time this is run.   |
|                                        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(multipleAnswerDelmiter); // 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.        |
| 2.3.00  2004.08.30  JEM  Restructured to loop through array of value-type els.        |
|                                        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 = false;
	var usesValueEls = ["text","dd","img"];
	for (var i = 0; i < usesValueEls.length; i++) {
		boolUsesValue = (boolUsesValue || (qTypeMatrix[currentQ] == usesValueEls[i]));
	}
	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 qCorrect(qNum) {
/*
+===========================================-===========================================+
|                                    VERSION HISTORY                                    |
| 2.3.00  2004.08.30  JEM  Initial version.                                             |
|                                        SUMMARY                                        |
| Given the number of a question, return whether it was correctly answered or not.      |
|                                       PARAMETERS                                      |
| Question number.  References global objects: total.perQPossible; total.perQCorrect    |
|                                  DEPENDANT FUNCTIONS                                  |
| None.                                                                                 |
+===========================================-===========================================+
*/
	var boolQIsCorrect = false; // default to incorrect
	if (total.perQPossible[qNum] == total.perQCorrect[qNum]) { 
		boolQIsCorrect = true;
	}
	return boolQIsCorrect;
} // end qCorrect()

function markCorrects() {
/*
+===========================================-===========================================+
|                                    VERSION HISTORY                                    |
| 2.2.00  2004.05.04  JEM  Initial version and any changes undocumented to date.        |
| 2.3.00  2004.08.30  JEM  Replaced strings with variables; reorganized logics; added   |
|                          support for "singleselgroup".                                |
|                                        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; qCorrect;                                        |
|                                  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
				switch (qTypeMatrix[i]) {
					case ('singleselgroup'):
						idToChange = thisEl.id.substring(0,thisEl.id.length - 1) + IDAppend;
						if (qCorrect(i)) {
							changeClassById(idToChange, RespRight);  // Change an element to the RespRight class
						} else {
							changeClassById(idToChange, RespWrong);  // Change an element to the RespWrong class
						}
						break;
					case ('img'):
						idToChange = thisEl.id + "r" + thisEl.value; // Special ID for image fb
						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
						break;
					default:
						idToChange = thisEl.id + IDAppend;  // Append to match the ID of the container LI
						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
						break;
				}
			}; // 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.        |
| 2.3.05  2006.04.11  JEM  Modified yesChange() function to accurately not style radio  |
|                          buttons that had values (not common).                        |
|                                        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.type != 'radio')) && (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.  |
| 2.3.00  2004.08.30  JEM  Replaced strings with variables; added support for 'single'  |
|                          feedback type;                                               |
| 2.3.01  2004.12.15  JEM  Added support for layered feedback.         					|
| 2.3.03  2005.04.28  YB   Added renderFeedback function to allow a jump to element 	|
|						   feature when neccessary										|
| 2.3.04  2005.09.29  LBH  Added function msgrActivityCorrect function to allow tracking|
|						   of question correctness simultaneous with feedback 			|
|						   presentation.												|
| 2.3.05  2006.04.11  JEM  Added call to questionLevelReporting.                        |
|                                        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(positiveIndicator);  // 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
									renderFeedback (qfbPrefix + i + responseIndicator + responseMatrix[i][j].value, fbStyleToUse);  
								} else {
									renderFeedback (qfbPrefix + i + responseIndicator + 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
							renderFeedback (qfbPrefix + i + positiveIndicator, fbStyleToUse);
						} else if (eligibleForPartial == true) {  // partially correct
							renderFeedback (qfbPrefix + i + partialIndicator, fbStyleToUse);
						} else {  // must be wrong
							renderFeedback (qfbPrefix + i + negativeIndicator, fbStyleToUse);
						}; // end if
						break;  // end case partial
					case ('normal'):
						if (total.perQCorrect[i] == total.perQPossible[i]) {  // all correct
							renderFeedback (qfbPrefix + i + positiveIndicator, fbStyleToUse);
							msgrActivityCorrect(true);
						} else {  // simply wrong
							renderFeedback (qfbPrefix + i + negativeIndicator, fbStyleToUse);
							msgrActivityCorrect(false);
						}  // end if correct
						break;  // end case normal
					case ('single'):
						renderFeedback (qfbPrefix + i + positiveIndicator, fbStyleToUse);
						break;
					case ('none'):
						break;
					case ('layered'):
						if (total.perQCorrect[i] == total.perQPossible[i]) {  // all correct
							renderFeedback (qfbPrefix + i + positiveIndicator, fbStyleToUse);
						} else if ((testForPartial(i)) && (numChecked(i) > 1)) {  // partially correct
							renderFeedback (qfbPrefix + i + partialIndicator, fbStyleToUse);
						} else if (firstOneChecked(i) != -1) { // response specific for only one
							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
										renderFeedback (qfbPrefix + i + responseIndicator + responseMatrix[i][j].value, fbStyleToUse);  
									} else {
										renderFeedback (qfbPrefix + i + responseIndicator + j, fbStyleToUse);
									} // end if usesValue
								} // end if checked
							} // end for j loop
						} else { // negative fb
							renderFeedback (qfbPrefix + i + negativeIndicator, fbStyleToUse);
						}
						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(partialIndicator);
					} else {
						pageAdvance(negativeIndicator);
					} // 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(positiveIndicator);
					} else {
						pageAdvance(negativeIndicator);
					}; // end false condition; end of if
					break; // end case partial
				case ('single'):
					pageAdvance(positiveIndicator);
					break;
				case ('none'): // only when the question-specific feedback is set to none is the page allowed to evaluate it's feedback
					break;
				case ('layered'):
					if (total.perQCorrect[i] == total.perQPossible[i]) {  // all correct
						pageAdvance(positiveIndicator);
					} else if ((testForPartial(i)) && (numChecked(i) > 1)) {  // partially correct
						pageAdvance(partialIndicator);
					} else if (firstOneChecked(i) != -1) { // response specific for only one
						for (j = 0; j < responseMatrix[i].length; j++) {  // Loop through each item within the current question
							if (yesChange(responseMatrix[i][j])) {  // for selected responses...
								pageAdvance(j); // triggers the fb
							} // end if checked
						} // end for j loop
					} else { // negative fb
						pageAdvance(negativeIndicator);
					}
					break;
			} // end switch feedbackMatrix[0]
		}; // end switch feedbackLocation
	}; // end for i
	if (enableQuestionLevelReporting) {questionLevelReporting();}; // 2006.04.11
	pageFeedback(); // call to handle page-wide feedback, if any
} // end feedback()

function questionLevelReporting() {
	/* questionLevelReporting
		ABOUT:				Adds correct/incorrect messages to reporter textboxes for display
		BUGS:				none known
		TODO:				Flexibility to update innerHTML rather than only form fields; auto numbering of elements or even better dynamic insertion of elements
		PARAMETERS:			none
		RETURNED VALUES:	none
			CHANGE LOG:
		2006.04.12   JEM   Created.
	*/
	var qlrEl, qlrMessage, j;
	for (var i=0; i<totalQ; i++) {
		j = i+1;
		if (document.getElementById("qlr"+j)) {
			if (total.perQCorrect[i] == total.perQPossible[i]) {
				qlrMessage = qlrMsgCorrect;
			} else {
				qlrMessage = qlrMsgIncorrect;
			}
			qlrEl = document.getElementById("qlr"+j);
			qlrEl.value = qlrMessage;
		}
	}
}

function numChecked(qNumber) {
/*
+===========================================-===========================================+
|                                    VERSION HISTORY                                    |
| 2.3.01  2004.12.15  JEM  Initial version and any changes undocumented to date.        |
|                                        SUMMARY                                        |
| Given an index to the matrix of what elements were correctly answered, return the     |
| total number checked.                                                                 |
|                                       PARAMETERS                                      |
| qNumber - index for current question number.  References global objects:              |
| responseMatrix; correctMatrix;                                                        |
|                                  DEPENDANT FUNCTIONS                                  |
| None.                                                                                 |
+===========================================-===========================================+
*/
	var totalChecked = 0;
	// Loop through each item within the current question
	for (var j = 0; j < responseMatrix[qNumber].length; j++) {
		// If it was checked
		if ((responseMatrix[qNumber][j].checked)) {
				totalChecked++; // increment the total counter
		}; // end if checked
	}; // end for j loop
	return totalChecked;
} // end numChecked

function firstOneChecked(qNumber) {
/*
+===========================================-===========================================+
|                                    VERSION HISTORY                                    |
| 2.3.01  2004.12.15  JEM  Initial version and any changes undocumented to date.        |
|                                        SUMMARY                                        |
| Given an index to the matrix of what elements were correctly answered, return the     |
| first correctly checked item.  May consolidate with isAnswered in future.             |
|                                       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 it was checked
		if ((responseMatrix[qNumber][j].checked)) {
				return j; // return its index
		}; // end if true checked
	}; // end for j loop
	return -1; // none must have been checked
} // end firstOneChecked

function pageFeedback() {
/*
+===========================================-===========================================+
|                                    VERSION HISTORY                                    |
| 2.2.07  2004.05.17  JEM  Introduced.                                                  |
| 2.3.00  2004.08.30  JEM  Replaced strings with variables; added support for 'single'  |
|                          feedback type;                                               |
|                                        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(positiveIndicator);  // 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) {
						renderFeedback (pagePartialFbId, FBOnPage);
						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) {
						renderFeedback (pagePositiveFbId, FBOnPage);
					} else {
						renderFeedback (pageNegativeFbId, FBOnPage);
					}
					break;
				case ('single'):
					renderFeedback (pagePositiveFbId, FBOnPage);
					break;
				case ('none'):
					break;
			} // end switch
			break;
		case ('FBNextPage'):
			switch (pageFeedbackType) {
				case ('partial'):
					if (total.correct > 1) {
						pageAdvance(partialIndicator);
					}
					// *NOTE* No break, we want the case for normal to ensue if we get this far
				case ('normal'):
					if (total.correct == total.possible) {
						pageAdvance(positiveIndicator);  // all correct and next page
					} else {
						pageAdvance(negativeIndicator); // if they are not all correct, it must be wrong
					}
					break;
				case ('single'):
					pageAdvance(positiveIndicator);
					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(advanceType) {
/*
+===========================================-===========================================+
|                                    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. |
| 2.3.00  2004.08.30  JEM  Completely revamped logic; function now parses parameter to  |
|                          determine action; added support for custom URLs.             |
| 2.3.02  2005.01.21  JEM  Adapted for FitPro, et al naming convention (no "_pf").      |
|                                        SUMMARY                                        |
| Given the string that should be added to the filename, go to the URL by the new name. |
|                                       PARAMETERS                                      |
| advanceType - determines course of action.  References global objects: myFileName;    |
| window.location; myFileExt; positiveIndicator; negativeIndicator; partialIndicator;   |
| positiveUrlOverride; negativeUrlOverride; partialUrlOverride;                         |
|                                  DEPENDENT FUNCTIONS                                  |
| modifyUrlString.                                                                      |
+===========================================-===========================================+
*/
	var urlToGoTo = window.location.toString();
	if ((seriesName == "FitPro") || (seriesName == "PASS") || (seriesName == "ALP") || (seriesName == "TriU")) {
		var temp = new Array();
		temp = urlToGoTo.split("_");
		var lastpiece = temp[temp.length-1];
		tempNew = lastpiece.split(".");
		var myPageNumber = tempNew[0];
		pfPageNumber = myPageNumber*1 + 1;
		pfPageNumber = pfPageNumber + "";
		if (pfPageNumber.length == 1) {
			pfPageNumber = "0" + pfPageNumber;
		}
	} else {
		pfPageNumber = "_pf";
		myPageNumber = "_la";
	}
	switch (advanceType) {
		case (positiveIndicator) :
				if (positiveUrlOverride.length == 0) {
					urlToGoTo = modifyUrlString(myFileName, myFileExt, pfPageNumber, myPageNumber);
				} else {
					urlToGoTo = positiveUrlOverride;
				}
			break;
		case (negativeIndicator) :
				if (negativeUrlOverride.length == 0) {
					urlToGoTo = modifyUrlString(myFileName, myFileExt, "_nf", "");
				} else {
					urlToGoTo = negativeUrlOverride;
				}
			break;
		case (partialIndicator) :
				if (partialUrlOverride.length == 0) {
					urlToGoTo = modifyUrlString(myFileName, myFileExt, "_pf", "");
				} else {
					urlToGoTo = partialUrlOverride;
				}
			break;
		default:
			alert ("Unable to advance to feedback.");
			break;
	}
	if (urlToGoTo != window.location) {
		window.location = (urlToGoTo);
	}
} // end pageAdvance

function modifyUrlString (currentFileName, currentExtension, fileAddOn, charsToTrim) {
/*
+===========================================-===========================================+
|                                    VERSION HISTORY                                    |
| 2.3.00  2004.08.30  JEM  Initial version.                                             |
|                                        SUMMARY                                        |
| Given a file name, some characters to trim off the end, some characters to add to the |
| end, and the file extension to tack back on, return a modified URL string.            |
|                                       PARAMETERS                                      |
| currentFileName; currentExtension; fileAddOn; charsToTrim                             |
|                                  DEPENDANT FUNCTIONS                                  |
| None.                                                                                 |
+===========================================-===========================================+
*/
	if (currentFileName.substring((currentFileName.length-charsToTrim.length),(currentFileName.length)) == charsToTrim) {
		currentFileName = currentFileName.substring(0,(currentFileName.length-charsToTrim.length));
	}
	var theNewUrl = currentFileName + fileAddOn + "." + currentExtension;
	return theNewUrl;
}
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: changeClassById ('els1','fbon');                                                 |
| ...asigns the class 'fbon' to the element with an id of 'els1'.                       |
+===========================================-===========================================+
*/
	//alert (id + " to class " + newClass); // good for debugging
	try {
		var identity=document.getElementById(id);
		identity.className=newClass;
	} catch (e) {
		alert ("changeClassById error: Error attempting to change the class of '" + id + "' to '" + newClass + "'. \n Error: " + e);
	}
} // 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;
}

function attachSubmitOnChange(){
	for (i=0; i < document.forms.length; i++){
		for (j=0; j < document.forms[i].elements.length; j++){
			document.forms[i].elements[j].onclick = function(){document.forms[0].submit();}
		}
	}
}

function renderFeedback(elId,elClass){
/*
+===========================================-===========================================+
|                                    VERSION HISTORY                                    |
| 2.3.03  2005.04.28  YB   Initial version.                                             |
| 2.3.04  2005.08.10  JEM  Added 'barBox' to detection list for TriU.                   |
|                                        SUMMARY                                        |
| Renders feedback by calling changeClassById and jumpToDiv only when neccessary.       |
|                                       PARAMETERS                                      |
| elID - the ID of the element in question; elClass - the class the element should adopt|
|                                  DEPENDANT FUNCTIONS                                  |
| changeClassById; jumpToDiv                                                            |
+===========================================-===========================================+
*/
	changeClassById(elId,elClass);
	if ((FBOnPage == 'on') || (FBOnPage == 'barBox') || (FBOnPage == 'layeron')){
		jumpToDiv(elId);
	}
}

function jumpToDiv(elId){
/*
+===========================================-===========================================+
|                                    VERSION HISTORY                                    |
| 2.3.03  2005.04.28  YB   Initial version.                                             |
| 2.3.04  2005.08.10  JEM  Changed method to scrollIntoView to avoid URL manipulation,  |
|                          which interferes with the back button.                       |
|                                        SUMMARY                                        |
| Ensures the selected element is within the view of the browser window.                |
|                                       PARAMETERS                                      |
| elID - the ID of the element in question                                              |
|                                  DEPENDANT FUNCTIONS                                  |
| none                                                                                  |
+===========================================-===========================================+
*/
	document.getElementById(elId).scrollIntoView();
	//window.location='#'+elId;
}

function msgrActivityCorrect(arg){
/*
+===========================================-===========================================+
|                                    VERSION HISTORY                                    |
| 2.3.04  2005.29.09  LBH  Initial version.										        |
|                                        SUMMARY                                        |
| Designated "msgr" or messenger function to alert any necessary page elements of 		|
| activity correctness. This messenger is sent during "normal" feedback calculations.   |
| Function will be further defined on page if it's information is needed.				|
|                                       PARAMETERS                                      |
| arg - true/false argument to signify correctness of activity.			                |
|                                  DEPENDANT FUNCTIONS                                  |
| None.                                                                                 |
+===========================================-===========================================+
*/
}