//---------------------------------------------------------------------------
// Copyright (c) Knowledge Analysis Technologies, LLC  All Rights Reserved
//
// Proprietary - Use with KATech Written Permission Only
// Module Name:   ssAuthor.js
// Primary Author: Scott Dooley
// Last Revised:   $Id: ssAuthor.js,v 1.140 2009/03/05 23:17:45 dooley Exp $

var encryptMap;

function openWindow( url, windowTitle, width, height ) {
  var newWindow =
    window.open( url, windowTitle,
                 "height=" + height + ",width=" + width + 
                 ",menubar=yes,toolbar=no,directories=no,resizable=yes,scrollbars=yes",
                 true );
  newWindow.focus();
}

// Open the "more info" window to the given page. Used for password guidelines.

function openDetail( pageName, docPath ) {
  openWindow( docPath + "helptext/" + pageName, 'moreInfo', 750, 600 );
}

// Utility function to determine if we are running a version of IE.

function isExplorer() {
  return ( navigator.appName.indexOf( "Microsoft" ) != -1 );
}


//---------------------------------------------------------------------------
// BEGIN author interface functions.

// The author/teacher has clicked the "Edit Term" button.  Check that
// they have clicked a valid term.
//
function validateTermEditing() {
  var termForm = document.forms.dictEditForm;
  var termIDIndex = termForm.termIDList.selectedIndex;
  var returnVal = true;

  if ( termIDIndex == -1 ) {
    returnVal = false;
    confirm( 'Please select a term before clicking "Edit Term"');
  }
  else {
    termID = termForm.termIDList.options[ termIDIndex ].value;
    if ( termID == 0 ) {
      returnVal = false;
      confirm( 'Please select a specific term before clicking "Edit Term"');
    }
  }

  return returnVal;
}


// In the user editing interface, an ID for a class has been selected.  Take the 
// selected class ID and set the class ID input field.
//
function copySelectedClassID( selectWidget, classIDInputWidget ) {
  var classIDIndex = selectWidget.selectedIndex;
  classIDInputWidget.value = selectWidget.options[ classIDIndex ].value;
}


// reset the various widget values.
//
function clearFormValues( editingForm ) {
  var oneElt;

  for (index = 0; oneElt = editingForm.elements[ index ]; index++) {
    if (( oneElt.type == 'text' ) ||
        ( oneElt.type == 'textarea' ) ||
        ( oneElt.type == 'password' )) {
      oneElt.value = '';
    }
    else if ( oneElt.type == 'select-one' ) {
      oneElt.selectedIndex = 0;
    }
  }
}


//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

// prepareForUserSubmission( action );
//   Validate the form values.
//   Set the userClasses hidden parameter to the union of all the values
//   in the userClassSelection list.  Otherwise only the highlighted ones
//   are submitted.

function prepareForUserSubmission( action ) {
  var userForm = document.forms.userEditForm;
  var classSelection = userForm.userClassSelection;
  var numOptions = 0;
  if ( typeof classSelection != "undefined" ) {
    numOptions = classSelection.options.length;
  }
  var classIDString = '';

  var returnVal = true;
  if ( action == 'delete' ) {
    if ( !confirmUserDeletion( userForm.userType.value ))
      returnVal = false;
  }
  else { 
    returnVal = validateUserForm( userForm );
  }

  if ( returnVal ) {
    var i;
    var first = true;
        
    for ( i = 0; i < numOptions; i++ ) {
      if ( !first ) {
        classIDString += ',';
      }
      classIDString += classSelection.options[ i ].value;
      first = 0;
    }
    userForm.userClasses.value = classIDString;
  }

  return returnVal;
}

// Ensure that the author has entered a user ID and password
// Until we look in the DB we don't know whether the author is a teacher
// or a fully privileged author, so we don't know whether they need to have
// selected a school.  That validation is done by the processing script. 
//
function validateAuthorLogin() {
  var form = document.forms.loginForm;

  var userID = form.login.value;
  var password = form.password.value;
  var userIDError = false;
  var passwordError = false;

  var returnVal = true;

  if ( !userID ) { userIDError = true; }
  if ( !password ) { passwordError = true; }

  if ( userIDError && passwordError ) {
    alert( "Please type in your user ID and password." );
    returnVal = false;
  }
  else if ( userIDError ) {  
    alert( "Please type in your user ID" );
    returnVal = false;
  }
  else if ( passwordError ) {
    returnVal = false;
    alert( "Please enter your password." );
  }

  return returnVal;
}

// Validate entry, length and type of Author password fields on Change
// Password. Validate DB password against entered "Old Password".
//
function validateAuthorPassword( authorDBPassword, authorDBName ) {

  var form = document.forms.passwordForm;

  var password = form.password.value;
  var newPassword = form.newPassword.value;
  var newPwdReEnter = form.newPwd2.value;
  var passwordLen = 0;
  var re = /^[A-Za-z0-9]+$/;
  var authorName;
  var tempNewPassword;
  var encryptPassword = encrypt( authorDBPassword );

  // check for entry of required fields (all)

  if (!password) {
    alert ("The Old Password value is invalid." );
    return false;
  } else if ((!newPassword) || (!newPwdReEnter)) {
    alert ("You must enter a new password." );
    return false;
  } else if (newPassword != newPwdReEnter) {
    alert( "Your new password must be entered twice." );
    return false;
  } else {
    passwordLen = newPassword.length;
  }

  // Verify the entered Old Password is the same as what is stored in the DB

  if ((password) != (encryptPassword)) {
    alert ("Your Old Password value is invalid." );
    return false;
  }

  // check password length and type

  if ((passwordLen < 5) || (passwordLen > 20)) {
    alert ("Your new password must be between 5 and 20 characters long." );
    return false;
  } else if (newPassword.search(re) == -1) {

    alert ("Your new password must consist of alphabetic and/or numeric characters.");
    return false;
  }

  // verify new password is different than old password

  if ((password) == (newPassword)) {
    alert ("Your new password must be different than your old password.");
    return false;
  }

  // final check is to ensure password does not contain any part of author's
  // name. Both the password and author name are set to lower case.

  tempNewPassword = (newPassword.toLowerCase());
  authorName = (authorDBName.toLowerCase());

  re = new RegExp(tempNewPassword);

  if ((authorName.search(re)) != -1) {
    alert ("Your new password cannot contain part of your name.");
    return false;
  }
  return true;
}

// ROT13 encryption for passwords.
//
function encryptInit() {
  var map = new Array();
  var s = "abcdefghijklmnopqrstuvwxyz";

  for ( i=0; i < s.length; i++ ) {
    map[s.charAt(i)] = s.charAt(( i+13 )%26);
  }
  for ( i=0; i < s.length; i++ ) {
    map[s.charAt(i).toUpperCase()] = s.charAt(( i+13 )%26).toUpperCase();
  }
  return map;
}
function encrypt(a) {
  if (!encryptMap) {
    encryptMap = encryptInit();
  }
  s = "";
  for ( i=0; i < a.length; i++ ) {
    var b = a.charAt(i);
    s += ( b >= 'A' && b <= 'Z' || b >= 'a' && b <= 'z' ? encryptMap[b] : b);
  }
  return s;
}
  
// Author menu validation
//
function validateToolSelection( teacherFlag, schoolIDWidget, toolButton ) {

  if ( teacherFlag == 1 ) {
    return true;
  }
  else {
    var schoolIDIndex = schoolIDWidget.selectedIndex;
    if ( schoolIDIndex > 0 ) {
      return true;
    }
    else {
      alert( "Please select a school before selecting that tool button" );
      return false;
    }
  }
}
 

//---------------------------------------------------------------------------

// validate the attributes provided by the author for the user.
//
function validateUserForm( userForm ) {

  var userID    = userForm.login.value;
  var password  = userForm.password.value;
  var passwordV = userForm.passwordVerification.value;
  var userType  = userForm.userType.value;

  var name;
  if ( userType == 'student' ) {
    name = userForm.firstName.value;
    if ( name == '' ) {
      name = userForm.lastName.value;
    }
  }
  else {
    name = userForm.name.value;
  }

  var email = 'ignore';
  if ( typeof userForm.email != "undefined" ) {
    email = userForm.email.value;
  }
      
  var userIDError        = false;
  var nameError          = false;
  var passwordError      = false;
  var passwordMatchError = false;
  var emailError         = false;
  var returnVal          = true;

  if ( !userID ) { userIDError = true; }
  if ( !name ) { nameError = true; }
  if ( !password ) { passwordError = true; }
  if ( !email ) { emailError = true; }

  if ( password != passwordV ) { passwordMatchError = 1; }

  if ( userIDError && passwordError && nameError ) {
    alert( "Please provide a login ID, name and password." );
    returnVal = false;
  }
  else if ( userIDError && passwordError ) {
    alert( "Please provide a login ID and password." );
    returnVal = false;
  }
  else if ( userIDError ) {  
    alert( "Please provide a login ID." );
    returnVal = false;
  }
  else if ( passwordError ) {  
    alert( "Please provide a password." );
    returnVal = false;
  }
  else if ( passwordMatchError ) {
    alert( "Password and password verification do not match.\n" );
    returnVal = false;
  }
  else if ( nameError ) {
    alert( "Please provide a name." );
    returnVal = false;
  }
  else if ( emailError ) {
    alert( "Please provide an e-mail address." );
    returnVal = false;
  }

  if ( typeof userForm.oldSchoolID != "undefined" ) {
    var oldSchoolID = userForm.oldSchoolID.value;
    var newSchoolID = userForm.newSchoolID.value;

    if ( newSchoolID != oldSchoolID ) {
      returnVal = confirm( "You are moving the " + userType +
                           " to a new school. Please confirm that this " +
                           "is what you want to do." );
    }
  }

  return returnVal;
}


// moveSelectionItems
//    Move the selected items to/from one a source list to a
//    destination list.  This is used by multiple authoring tools.
//
function moveSelectionItems( sourceList, destinationList ) {
    
  var destIndex = destinationList.options.length;

  // Copy and delete from the bottom of the list up.  This allows the 
  // shrinking of the source list to not have ill effects on the loop index.
  //
  var newOption;
  var oldOption;
  for (var i = (sourceList.options.length - 1) ; i >= 0; i--) {
    //confirm ("i is " + i);
    //confirm ("option is " + sourceList.options[i] );
    if ( sourceList.options[i].selected ) {
      oldOption = sourceList.options[i];
      //confirm ("old option is " + oldOption );
      newOption = new Option(oldOption.text, oldOption.value, false, true);
      //confirm ("new option is " + newOption );
      destinationList.options[ destIndex ] = newOption;
      destIndex ++;
      //confirm( "copied " + sourceList.options[i].text +
      //"to " + destinationList.name );
      //confirm ("setting option to null");
      sourceList.options[i] = null;
      //confirm ("finished setting option to null");
    }
  }
  return false;   // so that the form isn't submitted.
}


// Display a new window with the small version of the student editor.
//
function openStudentEditor( scriptPath, classSetupForm, sessionID ) {

  var schoolID = classSetupForm.schoolID.value;

  var newLocation =
    scriptPath + 'authoring/userEditing.cgi?userType=student' +
    '&schoolID=' + schoolID + '&newForClass=1' + 
    '&sessionID=' + sessionID;

  var userWindow =
    window.open( newLocation, "SSuserEditor",
                 "height=375,width=440,menubar=yes,toolbar=no,directories=no,resizable=yes,scrollbars=yes",
                 true );
  userWindow.focus();
}


function studentEditorClassChange() {
  var form = document.userEditForm;
  var classIDIndex = form.classIDSelection.selectedIndex;
  var classID = form.classIDSelection.options[ classIDIndex ].value;

  //alert( "text assignment: Class changed to " + classID + " from " +
  //form.classID.value );

  if ( form.classID.value != classID ) {
    form.classID.value = classID;
    form.submit();
    return true;
  }
  else {
    return false;
  }
}


// Confirm deletion of a school
//
function confirmSchoolDeletion( form, schoolName ) {
  if ( confirm( "Are you sure you want to delete school " +
                "\"" + schoolName + "\"?" ) ) {
    // form target may have been set to unit editor window.  reset it.
    form.target = '';
    return true;
  }
  else { 
    return false;
  }
}

// Confirm duplication of a school
//
function confirmSchoolDuplication( form, schoolName ) {
  if ( confirm( "A new school with name \"" + schoolName + " Copy\" " +
                "will be created.  Please confirm." )) {
    form.target = '';
    return true;
  }
  else { 
    return false;
  }
}


// confirm deletion of a class.
//
function confirmClassDeletion( form, className ) {

  if ( confirm( "Are you sure you want to delete class " +
                "\"" + className + "\"?" ) ) {
    // form target may have been set to unit editor window.  reset it.
    form.target = '';
    return true;
  }
  else { 
    return false;
  }
}


// confirm deletion of a text.
//
function confirmTextDeletion( form, textName, classCount, scriptPath ) {

  form.target = '';
  form.action = scriptPath + "authoring/textEditing.cgi";

  var message = "Are you sure you want to delete " +
    "\"" + textName + "\"?";

  if ( classCount > 0 ) {
    if ( classCount == 1 ) {
      message += "  It is used in 1 class.";
    }
    else {
      message += "  It is used in " + classCount + " classes.";
    }
  }
  else {
    message += "  It is not currenty used in any classes.";
  }

  if (confirm( message )) {
    // form target may have been set to unit editor window.  reset it.
    form.target = '';
    return true;
  }
  else { 
    return false;
  }
}


// Display a new window showing a list of the students in a class 
//
function openStudentList( scriptPath, classForm, sessionID ) {

  var schoolID = classForm.schoolID.value;
  var classID  = classForm.classID.value;

  var newLocation =
    scriptPath + 'authoring/classEditing.cgi?listStudentsButton=1' +
    '&schoolID=' + schoolID + '&classID=' + classID +
    '&sessionID=' + sessionID;

  var listWindow =
    window.open( newLocation, "SSClassStudentList",
                 "height=600,width=400,menubar=yes,toolbar=no,directories=no,resizable=yes,scrollbars=yes",
                 true );
  listWindow.focus();
  return false;
}

// prepareForUnitSubmission( action );
//   Set the unitTexts hidden parameter to the union of all the values
//   in the unitTextSelection list.  (Otherwise only the highlighted ones
//   are submitted.)

function prepareForUnitSubmission( buttonName ) {
  var unitForm = document.forms.unitEditForm;
  var textSelection = unitForm.unitTextSelection;
  var numOptions = textSelection.options.length;
  var textIDString = '';

  var returnVal = true;

  var i;
  var first = true;
        
  for ( i = 0; i < numOptions; i++ ) {
    if ( !first ) {
      textIDString += ',';
    }
    textIDString += textSelection.options[ i ].value;
    first = 0;
  }

  // set the unit texts value.
  unitForm.unitTexts.value = textIDString;

  // set the form target to be the 'SSTools' (main) window.
  unitForm.target = 'SSTools';

  returnVal = unitForm.submit();

  // Netscape won't submit if the window closes right away.  Add a little
  // delay.
  setTimeout( "self.close()", 2500 );

  return false;   // keep the browser from submitting again.
}


function openUnitEditor( action ) {
  var classForm = document.forms.classEditForm;

  if ( classForm.classID.value == '' ) {
    alert( "Please create or select a class before attempting to " +
           action + " a unit." );
    return false;
  }
  else if ( action == 'edit' ) {
    if ( classForm.unitIDSelection.selectedIndex < 0 ) {
      alert( 'You must choose a unit before clicking the "Edit Unit" button' );
      return false;
    }
  }
  else {
    classForm.unitIDSelection.value = "-1";
  }
    
  openWindow( "", 'unitEditor', 700, 550 );
  classForm.target = 'unitEditor';
  //classForm.action = '/cgi-bin/printParms.cgi';
  return true;
}


function validateUnitDeletion() {
  var classForm = document.forms.classEditForm;
  var returnVal = false;

  if ( classForm.classID.value == '' ) {    
    alert( 'You must choose a select a class and a unit before attempting to delete a unit.' );
  }
  else if ( classForm.unitIDSelection.selectedIndex < 0 ) {
    alert('You must choose a unit before clicking the "Delete Unit" button');
  }
  else {
    returnVal = true;
  }
  return returnVal;
}


// prepareForTextSubmission( action );
//   Set the textSchools hidden parameter to the union of all the values
//   in the textSchoolSelection list.  (Otherwise only the highlighted ones
//   are submitted.)

function prepareForTextSubmission( buttonName ) {
  var textForm = document.forms.textEditForm;
  var schoolSelection = textForm.textSchoolSelection;

  if ( buttonName == 'save' ) {
    var minWC  = textForm.minWC.value;
    var maxWC  = textForm.maxWC.value;
    var red    = textForm.redundanceThreshold.value;
    var rel    = textForm.relevanceThreshold.value;
    var maxAtt = 0;
    if ( typeof textForm.attemptLimit != "undefined" ) {
      // if no attempt limiting then won't have this field.
      maxAtt = textForm.attemptLimit.value;
    }

    var message = checkAttemptsAndWordCounts( minWC, maxWC, maxAtt, false );
    if ( isNaN(red) || red <= 0 || red > 1 ) {
      message +=
        "Redundance threshold must be a number between 0.0 and 1.0.\n";
    }
    if ( isNaN(rel) || rel <= 0 || rel > 1 ) {
      message +=
        "Relevance threshold must be a number between 0.0 and 1.0.\n";
    }

    if (message != '') {
      alert( message );
      return false;
    }
  }

  // set the contentFilePath var in case the user has given a full URL.
  if ( typeof textForm.contentFilePath != "undefined" ) {
    textForm.contentFilePath.value = textForm.contentFileName.value;
  }

  // Check that there is a selection widget.  If a teacher is using the
  // editor then there will be no selection widget and the textSchools
  // input widget will already be set.
  //
  if ( !schoolSelection ) {
    return true;
  }

  var numOptions = schoolSelection.options.length;
  var schoolIDString = '';

  var i;
  var first = true;
        
  for ( i = 0; i < numOptions; i++ ) {
    if ( !first ) {
      schoolIDString += ',';
    }
    schoolIDString += schoolSelection.options[ i ].value;
    first = 0;
  }

  // set the text schools value.
  textForm.textSchools.value = schoolIDString;

  return true;  // let the browser submit the form.
}


// Return a string that is non-empty if there are any goofy values in the
// various limit parameter values.
//
function checkAttemptsAndWordCounts(minWC, maxWC, maxAtt, allowEmpty) {
  var message = '';
  var maxAttValue = 100;
  var maxWordValue = 5000;
  var smallRange = 20;

  var minWCNaNError = false;
  var maxWCNaNError = false;
  var attemptsNaNError = false;
  var checkMinWC = true;
  var checkMaxWC = true;
  var checkAttempts = true;

  if ( allowEmpty ) {
    if ( minWC == '' ) { checkMinWC = false; }
    else if (isNaN(minWC)) { minWCNaNError = true; }

    if ( maxWC == '' ) { checkMaxWC = false; }
    else if (isNaN(maxWC)) { maxWCNaNError = true; }

    if ( maxAtt == '' ) { checkAttempts = false; }
    else if (isNaN(maxAtt)) { attemptsNaNError = true; }
  }
  else {
    if (isNaN(minWC)) { minWCNaNError = true; }
    if (isNaN(maxWC)) { maxWCNaNError = true; }
    if (isNaN(maxAtt)) { attemptsNaNError = true; }
  }

  if ( checkMinWC &&
       (minWCNaNError || minWC <= 0 || minWC > maxWordValue )) {
    message += "Minimum word count must be an integer between 0 and " +
      + maxWordValue + ".\n";
  }
  if ( checkMaxWC &&
       (maxWCNaNError || maxWC <= 0 || maxWC > maxWordValue)) {
    message += "Maximum word count must be an integer between 0 and " +
      + maxWordValue + ".\n";
  }
  if ( checkMinWC && checkMaxWC && !minWCNaNError && !maxWCNaNError &&
       ((Number(minWC) + smallRange) > maxWC) ) {
    if ( minWC < maxWC ) {
      message += "" +  (maxWC - minWC) +
        " words is a very small range for acceptable summary length.\n";
    }
    message
      += "The maximum word count must be at least 20 greater than " +
      "the minimum word count.\n";
  }

  if ( checkAttempts &&
       (attemptsNaNError || maxAtt < 0 || maxAtt > maxAttValue )) {
    message += "Maximum attempts must either be blank or an integer " +
      "from 0 to " + maxAttValue + ".\n";
  }
  return message;
}


// The student has requested the next text in the sequence of texts.
// 

function goToNextText( cgiPath, nextTextID ) {
  var form = document.forms.feedbackForm;
  form.action = cgiPath;
  form.textID.value = form.nextTextID.value;
  form.summary.value = "";    // set the summary to empty for next topic.
  return true;  // let the browser submit the form.
}


function verifyDiscardForMainMenu() {
  return true;
  //return confirm( "Switching to the Authoring Tools Menu.\nAny unsaved " +
  //"changes will be discarded." );
}

//----------------------------------------------------------------------
//-- BEGIN - Class Setup Form functions.

// Class Setup Form method.
//   The user has chosen a different class from the list.
//   Set the selected class ID and submit the form.
//
function classSetupClassChange() {
  var form = document.classSetupForm;

  var classIDIndex = form.classIDSelection.selectedIndex;
  var classID = form.classIDSelection.options[ classIDIndex ].value;
  if ( form.classID.value != classID ) {
    form.classID.value = classID;
    form.unitID.value = -1;
    form.submit();
    return true;
  }
  else {
    return false;
  }
}

// Class Setup Form method.
//   The user has chosen a different class unit from the list.
//   Set the selected unit ID and submit the form.
//
function classSetupUnitChange() {
  var form = document.classSetupForm;

  var unitIDIndex = form.unitIDSelection.selectedIndex;
  var unitID = form.unitIDSelection.options[ unitIDIndex ].value;

  if ( form.unitID.value != unitID ) {
    form.unitID.value = unitID;
    form.submit();
    return true;
  }
  else {
    return false;
  }
}


// Class Setup Form method.
//   The user has chosen to reset the form.  This is best accomplished
//   by resetting the classID and unitID values and submitting.
//
function classSetupIDReset() {
  var form = document.forms.classSetupForm;

  form.classID.value = "-1";
  form.unitID.value = "-1";
  return true;
}


// Add an item to a selection list in opener window.
//
function addStudentToClassSetup( studentForm ) {

  var studentLogin = studentForm.login.value;
  var studentName = studentForm.name.value;

  if ( passwordMatchCheck( studentForm ) ) {

    if (isExplorer()) {
      alert( "Student will be created.\n\nNote: The student list in" +
             " the Class Setup Form will not be updated until you" + 
             " click the \"Save Class Setup\" button." );
    }
    else {
      var setupWindow = self.opener;
      var setupForm = setupWindow.document.forms.classSetupForm;
      var studentList = setupForm.classStudentSelection;
        
      var destIndex = studentList.options.length;
      var optionText = studentLogin + ' / ' + studentName;
      var newOption = new Option( optionText, studentLogin, false, false );
      studentList.options[ destIndex ] = newOption;
    }
    return true;
  }
  else {
    alert( "The passwords do not match" );
    return false;
  }
}


// Add an item to a selection list in opener window.
//
function addStudentToClassEdit( studentForm ) {

  var studentLogin = studentForm.login.value;
  var studentName = studentForm.name.value;

  if ( passwordMatchCheck( studentForm ) ) {
    if (isExplorer()) {
      alert( "Student will be created.\n\nNote: The student list in" +
             " the Class Editor will not be updated until you" + 
             " click the \"Save Class\" button." );
    }
    else {
      var setupWindow = self.opener;
      var editForm = setupWindow.document.forms.classEditForm;
      var studentList = editForm.classStudentSelection;
        
      var destIndex = studentList.options.length;
      var optionText = studentLogin + ' / ' + studentName;
      var newOption = new Option( optionText, studentLogin, false, false );
      studentList.options[ destIndex ] = newOption;
    }
    return true;
  }
  else {
    alert( "The passwords do not match" );
    return false;
  }
}

// auxiliary function for addStudentToClassSetup.
//
function passwordMatchCheck( studentForm ) {
  var studentPass1 = studentForm.password.value;
  var studentPass2 = studentForm.passwordVerification.value;

  studentPass1 = studentPass1.toLowerCase();
  studentPass2 = studentPass2.toLowerCase();

  return (studentPass1 == studentPass2);
}


// prepareForClassSetupSubmission();
//   Set the classTexts and classStudents hidden parameters to the union of
//   all the values in the respective selection lists. (Otherwise only the
//   highlighted ones are submitted.)

function prepareForClassSetupSubmission() {
  var form = document.forms.classSetupForm;
  var textSelection = form.unitTextSelection;
  var studentSelection = form.classStudentSelection;

  // First handle the texts for the class unit..
  var numOptions = textSelection.options.length;
  var textIDString = '';

  var i;
  var first = true;
        
  for ( i = 0; i < numOptions; i++ ) {
    if ( !first ) { textIDString += ','; }
    textIDString += textSelection.options[ i ].value;
    first = 0;
  }

  form.unitTexts.value = textIDString;

  // Now handle the class student selections.

  numOptions = studentSelection.options.length;
  var studentIDString = '';

  first = true;
    
  for ( i = 0; i < numOptions; i++ ) {
    if ( !first ) { studentIDString += ','; }
    studentIDString += studentSelection.options[ i ].value;
    first = 0;
  }

  // set the unit texts value.
  form.classStudents.value = studentIDString;

  //confirm( "unit texts: " + form.unitTexts.value );
  //confirm( "class students: " + form.classStudents.value );

  return true;  // let the browser submit the form.
}


//-- END - Class Setup Form functions.
//----------------------------------------------------------------------

//----------------------------------------------------------------------
//-- BEGIN - Text Assignment Form Functions

// Text Assignment Tool method.
//   The user has chosen a different class from the list.
//   Set the selected class ID and submit the form.
//
//   Need to set the classChange element so we know to ignore the unitSelection
//   widget values on the sort.
//

function textAssignmentClassChange() {
  var form = document.textAssignmentForm;

  var classIDIndex = form.classIDSelection.selectedIndex;
  var classID = form.classIDSelection.options[ classIDIndex ].value;

  //alert( "text assignment: Class changed to " + classID + " from " +
  //form.classID.value );

  if ( form.classID.value != classID ) {
    form.classID.value = classID;
    form.classChange.value = 1;
    form.displayMode.value = '';
    form.submit();
    return true;
  }
  else {
    return false;
  }
}


// User has asked for a sorting of the texts by the given attribute.
// Set the sortBy hidden parameter and submit the form.
function textAssignmentSort( headingTag ) {
  var form = document.textAssignmentForm;

  var oldSort = form.sortBy.value;
  form.sortBy.value = headingTag;

  // See if we are just swapping the sort order for the same field.
  if ( oldSort == headingTag ) {
    var sortOrder = form.sortOrder.value;
    if ( sortOrder == 'ascending' ) { form.sortOrder.value = 'descending' }
    else { form.sortOrder.value = 'ascending' }
  }
  else {
    //if switching fields, ascending is default.
    form.sortOrder.value = 'ascending' 
      }
  form.submit();
  return false;
}


function verifyDiscardAssignmentsForEdit( toolName ) {

  return true;
  //return confirm( "Switching to the " + toolName + ".  Any unsaved " +
  //"assignments will be discarded." );
}


function verifyQuery() {
  var form = document.textAssignmentForm;

  var returnVal = false

    // Ensure that we have a selection for all the criteria selectors
    var typeSelector = form.TypeSelect;        // could be list or hidden
  var gradeSelector = form.GradeSelect;      // could be list or hidden
  var subjectSelector = form.SubjectSelect;  // could be list or hidden

  if ( ( typeSelector.type.match(/^select/) &&
         typeSelector.selectedIndex == -1 ) ||
       ( gradeSelector.type.match(/^select/) &&
         gradeSelector.selectedIndex == -1 ) ||
       ( subjectSelector.type.match(/^select/) &&
         subjectSelector.selectedIndex == -1 )) {
    alert( "Please select a Type, Grade and Subject before clicking Find" );
    returnVal = false;
  }
  else {
    var query = form.query.value;
    query = query.replace( / +$/g, "" ); // trim whitespace
    query = query.replace( /^ +/g, "" ); // trim whitespace

    if (query == '') {
      // DAW: This used to be true, but now it is valid for the user to leave
      // the query blank.-- it's part of a larger search context.      
      //     alert("You must provide some text in your search string.");
      //     return false;
      returnVal = true;;
    }
    else {
      returnVal = true;
    }

  }
  return returnVal;
}

// enableFindButton
//   At least one of the selection criteria has been selected;
//   enable the find button for clicking.

function enableFindButton() {
  var form = document.textAssignmentForm;

  var findButton = form.fetchFromContext;
  if (  findButton != null ) {
    findButton.disabled = false;
  }
}


//-- END - Text Assignment Form functions.
//----------------------------------------------------------------------

//----------------------------------------------------------------------
//-- BEGIN - Unit Editing functions.

//   The user has chosen a different class from the list.
//   Set the selected class ID and submit the form.
//
function unitEditingClassChange() {
  var form = document.unitEditForm;

  var classIDIndex = form.classIDSelection.selectedIndex;
  var classID = form.classIDSelection.options[ classIDIndex ].value;

  if ( form.classID.value != classID ) {
    form.classID.value = classID;
    form.submit();
    return true;
  }
  else {
    return false;
  }
}

function verifyDiscardForClassFromUnit() {

  return confirm( "Switching to the Class Editor.  Any unsaved unit " +
                  "changes will be discarded." );
}


function verifyDiscardForAssignFromUnit() {

  return confirm( "Switching to the Text Assignment Tool.  Any unsaved " +
                  "unit edits will be discarded." );
}

function verifyDiscardForAssignFromText( form, scriptPath ) {

  form.target = '';
  form.action = scriptPath + "authoring/textEditing.cgi";

  return true;

  //return confirm( "Switching to the Text Assignment Tool.  Any unsaved " +
  //"text attribute changes will be discarded." );
}


//-- END - Unit Editing functions.
//----------------------------------------------------------------------

//----------------------------------------------------------------------
//-- BEGIN - Threshold Editing functions.

//   The user has chosen a different class from the list.
//   Set the selected class ID and submit the form.
//
function thresholdEditingClassChange() {
  var form = document.thresholdEditForm;

  var classIDIndex = form.classIDSelection.selectedIndex;
  var classID = form.classIDSelection.options[ classIDIndex ].value;

  if ( form.classID.value != classID ) {
    form.classID.value = classID;
    form.submit();
    return true;
  }
  else {
    return false;
  }
}

function verifyDiscardForClassFromThreshold() {

  return true;
  //return confirm( "Switching to the Class Editor.  Any unsaved threshold " +
  //"changes will be discarded." );
}


function verifyDiscardForAssignFromThreshold() {

  return true;
  //return confirm( "Switching to the Text Assignment Tool.  Any unsaved " +
  //"threshold edits will be discarded." );
}


//   The user has chosen a different text from the list.
//   Set the selected text ID and submit the form.
//
function thresholdEditTextChange(scriptPath) {
  var form = document.thresholdEditForm;

  var textIDIndex = form.textIDSelection.selectedIndex;
  var textID = form.textIDSelection.options[ textIDIndex ].value;

  form.target = '';
  form.action = scriptPath + "authoring/thresholdEditing.cgi";

  if ( form.textID.value != textID ) {
    form.textID.value = textID;
    form.submit();
    return true;
  }
  else {
    return false;
  }
}

//-- END - Threshold Editing functions.
//----------------------------------------------------------------------

//----------------------------------------------------------------------
//-- BEGIN - User Editor functions.


// confirmUserDeletion
//
function confirmUserDeletion( userType ) {
  return (confirm( "Are you sure you want to delete this " + userType +
                   " account?" ));
}

// User Editor Form method.
//   The user has chosen a different class from the list.
//   Set the selected class ID and submit the form.
//
function userEditClassChange() {
  var form = document.userEditForm;

  var classIDIndex = form.classIDSelection.selectedIndex;
  var classID = form.classIDSelection.options[ classIDIndex ].value;
  if ( form.classID.value != classID ) {
    form.classID.value = classID;
    form.userID.value = -1;
    form.userIDSelection.selectedIndex = 0;
    form.submit();
    return true;
  }
  else {
    return false;
  }
}


// User Editor Form method.
//   The author has chosen a different user (student or teacher) from the list.
//   Set the selected user ID and submit the form.
//
function userEditUserChange() {
  var form = document.userEditForm;

  var userIDIndex = form.userIDSelection.selectedIndex;
  var userID = form.userIDSelection.options[ userIDIndex ].value;
  if ( form.userID.value != userID ) {
    form.userID.value = userID;
    form.submit();
    return true;
  }
  else {
    return false;
  }
}


function verifyDiscardForStudentEdit() {

  return true;
  //return confirm( "Switching to the Student Editor.  Any unsaved student " +
  //"values will be discarded." );
}


function verifyDiscardForClassEdit2() {

  return true;
  //return confirm( "Switching to the Class Editor.  Any unsaved student " +
  //"values will be discarded." );
}


function verifyDiscardForStudentBatchCreate() {

  return true;
  //return confirm( "Switching to the Student Creation Tool.  Any unsaved " +
  //"student values will be discarded." );
}

// confirmUserDeactivation
//
function confirmUserDeactivation( userType ) {
  if ( userType == 'student' ) {
    return (confirm( "Deactivating the student account will unenroll the student from all classes and remove the account from the teacher viewable roster.  Please click \"OK\" to confirm." ));
  }
  else if ( userType == 'teacher' ) {
    alert( "Deactivation of teacher accounts is not yet available.");
    return 0;
  }
  else {
    return 0;
  }
}


//-- END - User Editor functions.
//----------------------------------------------------------------------

//----------------------------------------------------------------------
//-- BEGIN - Class Editor functions.

// Class Editor Form method.
//   The user has chosen a different class from the list.
//   Set the selected class ID and submit the form.
//
function classEditClassChange() {
  var form = document.classEditForm;

  var classIDIndex = form.classIDSelection.selectedIndex;
  var classID = form.classIDSelection.options[ classIDIndex ].value;
  if ( form.classID.value != classID ) {
    form.classID.value = classID;
    // form target may have been set to unit editor window.  reset it.
    form.target = '';
    form.submit();
    return true;
  }
  else {
    return false;
  }
}

// Class Editor Form method.
//   The user has chosen a different class from the list.
//   Set the selected class ID and submit the form.
//
function classEditClassChangeForSearchBox(divID, formName) {
  var form = document.getElementsByName(formName).item(0);
  var currentClassIDSelection = 'classIDSelection_'+divID;
  var classIDSelectionElement = document.getElementsByName(currentClassIDSelection).item(0);
  var classIDIndex = classIDSelectionElement.selectedIndex;
  var classID = classIDSelectionElement.options[ classIDIndex ].value;
  var selectedClassFromSearchElement = document.getElementsByName('selectedClassFromSearch').item(0);
  if ( selectedClassFromSearchElement.value != classID ) {
    selectedClassFromSearchElement.setAttribute('value', classID);
    // form target may have been set to unit editor window.  reset it.
    return true;
  }
  else {
    return false;
  }
}


// prepareForClassEditSubmission();
//   Set the classStudents hidden parameters to the union of all the values
//   all the values in the selection lists. (Otherwise only the highlighted
//   ones are submitted.)
// OLD class editor

function prepareForClassEditSubmission() {
  var form = document.forms.classEditForm;
  var studentSelection = form.classStudentSelection;

  var numOptions = studentSelection.options.length;
  var studentIDString = '';

  var first = true;
  var i;
  for ( i = 0; i < numOptions; i++ ) {
    if ( !first ) { studentIDString += ','; }
    studentIDString += studentSelection.options[ i ].value;
    first = 0;
  }

  // set the unit texts value.
  form.classStudents.value = studentIDString;
  //confirm( "class students: " + form.classStudents.value );

  return true;  // let the browser submit the form.
}


function verifyDiscardForTextAssign( message ) {

  return true;
  //return confirm( message );
}


//-- END - Class Editor functions.
//----------------------------------------------------------------------

//----------------------------------------------------------------------
//-- BEGIN - Activity Editor and Activity Settings functions.

//   The teacher has chosen a different activity from the list.
//   Set the selected activity ID and submit the form.
//
function settingsActivityChange(fullScriptPath, resetClassFlag) {
  var form = document.textEditForm;

  var textIDIndex = form.textIDSelection.selectedIndex;
  var textID = form.textIDSelection.options[ textIDIndex ].value;

  form.target = '';
  form.action = fullScriptPath;

  if ( textID == -1 &&
       typeof form.textTypeSelection.options != "undefined" ) {
    // reset the text type selection so that we output the empty form
    // on the reload.
    form.textTypeSelection.selectedIndex = 0;
    form.textTypeSelection.options[0].value = '';
  }

  if ( form.textID.value != textID ) {
    if ( resetClassFlag ) {
      form.classID.value = -1;
    }
    form.textID.value = textID;
    form.submit();
    return true;
  }
  else {
    return false;
  }
} // settingsActivityChange


//   The author has chosen a different text from the list.
//   Set the selected text ID and submit the form.
//
function textEditTextChange(fullScriptPath) {
  var form = document.textEditForm;

  var textIDIndex = form.textIDSelection.selectedIndex;
  var textID = form.textIDSelection.options[ textIDIndex ].value;

  form.target = '';
  form.action = fullScriptPath;

  if ( textID == -1 &&
       typeof form.textTypeSelection.options != "undefined" ) {
    // reset the text type selection so that we output the empty form
    // on the reload.
    form.textTypeSelection.selectedIndex = 0;
    form.textTypeSelection.options[0].value = '';
  }

  if ( form.textID.value != textID ) {
    form.textID.value = textID;
    form.submit();
    return true;
  }
  else {
    return false;
  }
}


//   The user has chosen a different school from the list.
//   Set the selected school ID and submit the form.
//
function textEditSchoolChange(scriptPath) {
  var form = document.textEditForm;

  var schoolIDIndex = form.schoolIDSelection.selectedIndex;
  var schoolID = form.schoolIDSelection.options[ schoolIDIndex ].value;

  form.target = '';
  form.action = scriptPath + "authoring/textEditing.cgi";

  if ( form.schoolID.value != schoolID ) {
    form.schoolID.value = schoolID;
    form.classID.value = -1;  // unselect any selected class
    form.textID.value = -1;  // unselect any selected text
    form.submit();
    return true;
  }
  else {
    return false;
  }
}


//   The user has chosen a different school from the list.
//   Set the selected school ID and submit the form.
//   Note that this function does not deselect the text.  If that
//   text is available in this class then we should go straight to 
//   the class specific text data editor.
//
function textEditClassChange(fullScriptPath, resetTextFlag) {
  var form = document.textEditForm;

  var classIDIndex = form.classIDSelection.selectedIndex;
  var classID = form.classIDSelection.options[ classIDIndex ].value;

  form.target = '';
  form.action = fullScriptPath;

  if ( form.classID.value != classID ) {
    if ( resetTextFlag ) {
      form.textID.value = -1;
    }

    form.classID.value = classID;
    form.submit();
    return true;
  }
  else {
    return false;
  }
}

function addSlimBook() {
  var textEditForm = document.textEditForm;
  addItemToList( textEditForm, textEditForm.bookID,
                 'Provide a name for the new book', textEditForm.bookName );
  textEditForm.chapterID.options.length = 0;
  textEditForm.addChapter.enabled = false;
}


function addSlimChapter() {
  var textEditForm = document.textEditForm;
  if ( textEditForm.bookID.selectedIndex != -1 ) {
    return addItemToList( textEditForm, textEditForm.chapterID,
                          'Provide a name for the new chapter',
                          textEditForm.chapterName );
    return true;
  }
  else {
    alert( "You must select a book before a chapter can be added" );
    return false;
  }

}


// If we change the book then we need to have the user submit the
// change before we can show the chapters.
//
function textEditBookChange() {
  var textEditForm = document.textEditForm;
  if (typeof textEditForm.chapterID != "undefined") {
    textEditForm.chapterID.options.length = 1;
    textEditForm.chapterID.options[0] = 
      new Option('Click "Update Entry" to see chapters', -1,
                 false, true);
    textEditForm.addChapter.disabled = true;
  }
}


function addItemToList( form, list, promptString, newItemField ) {
  var newItem = prompt( promptString );

  if (typeof newItem != "undefined") {
    var numItems = list.length;
    list.options[numItems] = new Option();
    list.options[numItems].text = newItem;
    list.options[numItems].value = -99;
    list.selectedIndex = numItems;
  }

  if ( typeof newItemField != "undefined" ) {
    newItemField.value=newItem;
  }
}


// The user has chosen a different point scale for the overall
// score category for an essay.  Dig into the javascript and 
// make adjustments to the radio buttons for score points 5 and 6
// if they exist.  This may involve hiding them (if the user is 
// switching to lower point scale (currently limited to 4 point only)
// or switching to a higher point scale (currently limited to 6 point
// only. Also ensure that if the threshold was set at 5 or 6 and the
// scale is being changed to 4 then the threshold is changed to 4 as
// well. 

function pointScaleUpdate( sectionID ) {

  var form = document.textEditForm;
  var pointScaleItem = form.pointScale;
  var pointScaleValue = pointScaleItem.options[pointScaleItem.selectedIndex].value;
  var threshItemID = 'thresh-' + sectionID;

  var p2Item = document.getElementById( sectionID + 'b2' );
  var p3Item = document.getElementById( sectionID + 'b3' );
  var p4Item = document.getElementById( sectionID + 'b4' );
  var p5Item = document.getElementById( sectionID + 'b5' );
  var p6Item = document.getElementById( sectionID + 'b6' );
  var p5HdrItem = document.getElementById( 'adjusterHead-5' );
  var p6HdrItem = document.getElementById( 'adjusterHead-6' );
  var threshItem = document.getElementById( threshItemID );

  var psSpan = document.getElementById('pointScaleDefault');
  if ( pointScaleValue == '4-point' ) {
    // set the new threshold to 3.
    p2Item.checked = false;
    p3Item.checked = true; updateChange( p3Item );
    p4Item.checked = false;
    if ( p5Item ) {
      hideItem( p5Item );
      hideItem( p6Item );
      //hideItem( p5HdrItem );
      //hideItem( p6HdrItem );// firefox, safari place 6 too close to 5 on show

      p5Item.checked = false;
      p6Item.checked = false;
    }
    psSpan.setAttribute('class','pointScaleMessage');
    psSpan.setAttribute('className','pointScaleMessage');
    psSpan.innerHTML = form.defaultScaleMessage.value;

    alert( 'The prompt scale will be changed to 4-point when you click ' +
           '"Save Changes".  The Overall Passing Threshold will be ' +
           'set to 3.' );
  }
  else if ( pointScaleValue == '6-point' ) {
    // set the new threshold to 4.
    p2Item.checked = false;
    p3Item.checked = false;
    p4Item.checked = true; updateChange( p4Item );

    alert( 'The prompt scale will be changed to 6-point when you click ' +
           '"Save Changes".  The Overall Passing Threshold will be ' +
           'set to 4.' );

    if ( p5Item ) {
      psSpan.setAttribute('class','pointScaleMessage');
      psSpan.setAttribute('className','pointScaleMessage');

      // Ensure that p5 and p6 are deselected.
      p5Item.checked = false;
      p6Item.checked = false;

      showItem( p5Item );
      showItem( p6Item );
      //showItem( p5HdrItem );
      //showItem( p6HdrItem );  // firefox, safari place 6 directly next to 5

      //psSpan.setAttribute('class','pointScaleMessage');
      //psSpan.setAttribute('className','pointScaleMessage');
      //psSpan.innerHTML = form.defaultScaleMessage.value;

    }
    else {
      ;
      //psSpan.setAttribute( 'class', 'pointScaleNotification' );
      //psSpan.setAttribute( 'className', 'pointScaleNotification' );
      //psSpan.innerHTML = 'Click "Save Changes" if you want to adjust the ' +
      //'Overall Passing Threshold.';
    }
  }
}

function hideItem( item ) {
  item.visibility = "hidden";
  item.style.display = "none";
}

function showItem( item ) {
  item.visibility = "visible";
  item.style.display = "inline";
}

//-- END - Text Editor functions.
//----------------------------------------------------------------------


//----------------------------------------------------------------------
//-- BEGIN - School Editor functions.

// Prompt Editor Form method.
//   The user has chosen a different prompt from the list.
//   Set the promptID and submit the form.
//
function promptEditPromptChange() {
  var form = document.promptEditForm;

  var promptIDIndex = form.promptIDSelection.selectedIndex;
  var promptID = form.promptIDSelection.options[ promptIDIndex ].value;
  if ( form.activityID.value != promptID ) {
    form.activityID.value = promptID;
    form.submit();
    return true;
  }
  else {
    return false;
  }
} // promptEditPromptChange

//-- END - Text Editor functions.
//----------------------------------------------------------------------

//----------------------------------------------------------------------
//-- BEGIN - Provisioning tool  functions.


// Provisioning Tool Form method.
//   The user has chosen a different entity from the list.
//   Submit the form.
//
function provisionerEntityChange() {

  var form = document.licenseForm;
  form.newLicenseFlag.value = 0;
  if (typeof form.licenseID != "undefined") {
    form.licenseID.selectedIndex = 0;
  }
  form.submit();
  return true;
}


// Provisioning Tool Form method.
//   The user has chosen a different subscription from the list.
//   Submit the form.
//
function provisionerSubscriptionChange() {

  var form = document.licenseForm;
  if ( form.licenseID.selectedIndex == 0 ) {
    form.newLicenseFlag.value = 1;
  }
  form.submit();
  return true;
}


// prepareForLicenseSubmission( action );

function prepareForLicenseSubmission( buttonName ) {
  var licenseForm = document.forms.licenseForm;
  
  return true;
}


// Confirm deletion of a license
//
function confirmLicenseDeletion( form, licenseName, licenseType ) {
  if ( confirm( "Are you sure you want to delete this subscription for " +
                licenseType + ' ' + licenseName + "?" ) ) {
    // form target may have been set to unit editor window.  reset it.
    form.target = '';
    return true;
  }
  else { 
    return false;
  }
}

// Confirm enablling of a feature
//   Currently no features require confirmation.
//
function confirmEnableFeature( featureElementID, featureName ) {
  return true;
}  // confirmEnableTTSFeature



function limitValueChange() {
  var licenseForm = document.forms.licenseForm;
  var limitValue = licenseForm.limit.value;
  var transientWidget = licenseForm.transientAllowance;
  if ( limitValue == '' ) {
    transientWidget.value = '';
  }
  else {
    // set transient allowance to be 10% of limit, rounded up.
    transientWidget.value = Math.ceil(limitValue * 0.1);
  }

}

function editCustomerContact( editingScript ) {
  openWindow( editingScript, 'contactInfoEditor', 700, 700 );
  return false;
}


//-- END - Provisioning tool  functions.
//----------------------------------------------------------------------
//-- BEGIN - Customer Contact Editing tool functions.

// prepareForContactSubmission( action );

function prepareForContactSubmission( form, buttonName ) {
  var returnVal = true;

  var name = form.contactName.value;
  name = name.replace( / +$/g, "" ); // trim whitespace
  name = name.replace( /^ +/g, "" ); // trim whitespace

  if (name == '') {
    returnVal = false;
    alert( 'A customer contact must have a name.' );
  }

  var email = form.email.value;
  email = email.replace( / +$/g, "" ); // trim whitespace
  email = email.replace( /^ +/g, "" ); // trim whitespace

  if ( returnVal ) {
    // Update our parent window with our new contact name.
    var parentWindow = self.opener;
    var contactDescription;
    if ( parentWindow ) {
      contactDescription =
        parentWindow.document.getElementById('contactDescription');
      contactDescription.innerHTML = name + ', ' + email;

      var button = parentWindow.document.licenseForm.editContactButton;
      button.value = 'Edit Contact';
    }
  }

  return returnVal;
}


// Confirm deletion of a contact
//
function confirmContactDeletion( form ) {
  var contactName = form.contactName.value;

  if ( confirm( 'Are you sure you want to delete contact "' +
                contactName + '"?' ) ) {
    var parentWindow = self.opener;
    var contactDescription;
    if ( parentWindow ) {
      contactDescription =
        parentWindow.document.getElementById('contactDescription');
      contactDescription.innerHTML = 'Not specified ';
      var button = parentWindow.document.licenseForm.editContactButton;
      button.value = 'Add Contact';
    }
    return true;
  }
  else { 
    return false;
  }
}

//-- END - Customer Contact Editing tool functions.
//----------------------------------------------------------------------

//----------------------------------------------------------------------
//-- BEGIN - School Editor functions.

// School Editor Form method.
//   The user has chosen a different school from the list.
//   Set the selected school ID and submit the form.
//
function schoolEditSchoolChange() {
  var form = document.schoolEditForm;

  var schoolIDIndex = form.schoolIDSelection.selectedIndex;
  var schoolID = form.schoolIDSelection.options[ schoolIDIndex ].value;
  if ( form.schoolID.value != schoolID ) {
    form.schoolID.value = schoolID;
    form.submit();
    return true;
  }
  else {
    return false;
  }
}


// prepareForSchoolSubmission( action );
//   Set the schoolTexts hidden parameter to the union of all the values
//   in the schoolTextSelection list.  (Otherwise only the highlighted ones
//   are submitted.)

function prepareForSchoolSubmission( buttonName ) {
  var schoolForm = document.forms.schoolEditForm;
  var textSelection = schoolForm.schoolTextSelection;
  var numOptions = textSelection.options.length;
  var textIDString = '';

  var returnVal = true;

  var name = schoolForm.schoolName.value || '';
  name = name.replace( / +$/g, "" ); // trim whitespace
  name = name.replace( /^ +/g, "" ); // trim whitespace

  var message = '';
  if (name == '') {
    returnVal = false;
    message += "\nThe school must have a name.";
  }

  var pearsonID = schoolForm.pearsonID.value;
  if (typeof pearsonID != "undefined" && isNaN(pearsonID)) {
    returnVal = false;
    message += "\nThe school Pearson ID must be a number.";
  }

  if ( returnVal ) {
    var i;
    var first = true;
        
    for ( i = 0; i < numOptions; i++ ) {
      if ( !first ) {
        textIDString += ',';
      }
      textIDString += textSelection.options[ i ].value;
      first = 0;
    }

    // set the school texts value.
    schoolForm.schoolTexts.value = textIDString;
  }
  else {
    alert( message );
  }
  
  return returnVal;
}


//-- END - School Editor functions.
//----------------------------------------------------------------------

//----------------------------------------------------------------------
//-- BEGIN - District Editor functions.

// District Editor Form method.
//   The user has chosen a different district from the list.
//   Set the selected district ID and submit the form.
//
function districtEditDistrictChange() {
  var form = document.districtEditForm;

  var districtIDIndex = form.districtIDSelection.selectedIndex;
  var districtID = form.districtIDSelection.options[ districtIDIndex ].value;
  if ( form.districtID.value != districtID ) {
    form.districtID.value = districtID;
    form.submit();
    return true;
  }
  else {
    return false;
  }
}


// prepareForDistrictSubmission( action );
//   Set the districtTexts hidden parameter to the union of all the values
//   in the districtTextSelection list.  (Otherwise only the highlighted ones
//   are submitted.)

function prepareForDistrictSubmission( buttonName ) {
  var districtForm = document.forms.districtEditForm;
  var schoolSelection = districtForm.districtSchoolSelection;
  var numOptions = schoolSelection.options.length;
  var schoolIDString = '';

  var returnVal = true;
     
  var name = districtForm.districtName.value || '';
  name = name.replace( / +$/g, "" ); // trim whitespace
  name = name.replace( /^ +/g, "" ); // trim whitespace

  var message = '';
  if (name == '') {
    returnVal = false;
    message += "\nThe district must have a name.";
  }

  var pearsonID = districtForm.pearsonID.value;
  if (typeof pearsonID != "undefined" && isNaN(pearsonID)) {
    returnVal = false;
    message += "\nThe district Pearson ID must be a number.";
  }

  if ( returnVal ) {
    var i;
    var first = true;

    for ( i = 0; i < numOptions; i++ ) {
      if ( !first ) {
        schoolIDString += ',';
      }
      schoolIDString += schoolSelection.options[ i ].value;
      first = 0;
    }
    
    // set the district schools value.
    districtForm.districtSchools.value = schoolIDString;
  }
  else {
    alert( message );
  }
  return returnVal;
}


// Confirm deletion of a district
//
function confirmDistrictDeletion( form, districtName ) {
  if ( confirm( "Are you sure you want to delete district " +
                "\"" + districtName + "\"?" ) ) {
    form.target = '';  // reset form target just in case.
    return true;
  }
  else { 
    return false;
  }
}


//-- END - District Editor functions.

//----------------------------------------------------------------------
//-- BEGIN - Class Report Methods.

// Class Report method.
//   The user has chosen a different class from the list.
//   Set the selected class ID and submit the form.
//
function classReportClassChange() {
  var form = document.classReportForm;

  var classIDIndex = form.classIDSelection.selectedIndex;
  var classID = form.classIDSelection.options[ classIDIndex ].value;
  if ( form.classID.value != classID ) {
    form.classID.value = classID;
    if (typeof form.textIDSelection != "undefined") {
      form.textIDSelection.selectedIndex = -1;
    }
    form.textID.value = '';
    form.submit();
    return true;
  }
  else {
    return false;
  }
}

// Class Report Form method.
//   The user has chosen a different text from the list.
//   Set the selected text ID and submit the form.
//
function classReportTextChange( submitFlag ) {
  var form = document.classReportForm;

  var textIDIndex = form.textIDSelection.selectedIndex;
  var textID = form.textIDSelection.options[ textIDIndex ].value;

  var returnVal = false;
  if ( form.textID.value != textID ) {
    form.textID.value = textID;
    if ( submitFlag && textID!=-1 ) {
      form.submit();
      return true;
    }
  }
  return returnVal;
}

function displayRubric( rubricScript ) {
  openWindow( rubricScript, 'rubricViewer', 680, 615 );
  return false;
}

function displaySectionName( readingName, sectionLabel, sectionName ) {
  alert( readingName + ', ' + sectionLabel + ': ' + sectionName );
}


//-- END - Class Report Methods.
//----------------------------------------------------------------------

//----------------------------------------------------------------------
//-- BEGIN - Student Report Methods.

// Student Report method.
//   The user has chosen a different class from the list.
//   Set the selected class ID and submit the form.
//
function studentReportClassChange() {
  var form = document.studentReportForm;

  var classIDIndex = form.classIDSelection.selectedIndex;
  var classID = form.classIDSelection.options[ classIDIndex ].value;
  if ( form.classID.value != classID ) {
    form.classID.value = classID;
    if ( typeof form.studentID != "undefined" ) {   
      form.studentID.value = -1;
      form.createFromSelection.value = 0;
    }
    if ( typeof form.studentIDSelection != "undefined" ) {  
      form.studentIDSelection.value = -1;
    }
    form.submit();
    return true;
  }
  else {
    return false;
  }
}

function studentReportStudentChange() {
  var form = document.studentReportForm;

  var studentIDIndex = form.studentIDSelection.selectedIndex;
  var studentID = form.studentIDSelection.options[ studentIDIndex ].value;
  if ( form.studentID.value != studentID ) {
    form.studentID.value = studentID;
    form.createFromSelection.value = 1;
    form.submit();
    return true;
  }
  else {
    return false;
  }
}


//-- END - Student Report Methods.
//----------------------------------------------------------------------

//----------------------------------------------------------------------
//-- BEGIN - Text Usage Report Methods.


// Activity Usage Report Form method.
//   The user has chosen a different text from the list.
//   Set the selected text ID and submit the form.
//
function activityUsageTextChange( submitFlag ) {
  var form = document.activityUsageReportForm;

  var textIDIndex = form.textIDSelection.selectedIndex;
  var textID = form.textIDSelection.options[ textIDIndex ].value;

  var returnVal = false;
  if ( form.textID.value != textID ) {
    form.textID.value = textID;
    if ( submitFlag && textID!=-1 ) {
      form.usageSchoolID.value = -1;
      form.submit();
      return true;
    }
  }
  return returnVal;
}


// Class Report Form method.
//   The user has chosen a different school from the list.
//   Set the selected school ID and submit the form.
//
function activityUsageSchoolChange( submitFlag ) {
  var form = document.activityUsageReportForm;

  var schoolIDIndex = form.usageSchoolIDSelection.selectedIndex;
  var schoolID = form.usageSchoolIDSelection.options[ schoolIDIndex ].value;

  var returnVal = false;
  if ( form.usageSchoolID.value != schoolID ) {
    form.usageSchoolID.value = schoolID;
    if ( submitFlag && schoolID!=-1 ) {
      form.submit();
      return true;
    }
  }
  return returnVal;
}

//-- END - Text Usage Report
//----------------------------------------------------------------------


//----------------------------------------------------------------------
//-- BEGIN - Student Archiver Methods.

// Student Archiver method.
//   The user has chosen a different class from the list.
//   Set the selected student ID and submit the form.
//
function studentArchiverClassChange() {
  var form = document.studentArchiverForm;

  var classIDIndex = form.classIDSelection.selectedIndex;
  var classID = form.classIDSelection.options[ classIDIndex ].value;
  if ( form.classID.value != classID ) {
    form.classID.value = classID;
    form.submit();
    return true;
  }
  else {
    return false;
  }
}

// Student Archiver method.
//   The user has chosen a different student from the list.
//   Update the submit button
//
function studentArchiverStudentChange() {
  var form = document.studentArchiverForm;

  var button = form.archiveStudents;
  var studentIDIndex = form.studentIDSelection.selectedIndex;
  var studentID = form.studentIDSelection.options[ studentIDIndex ].value;
  var classIDIndex = form.classIDSelection.selectedIndex;
  var classID = form.classIDSelection.options[ classIDIndex ].value;

  if ( studentID == -2 ) {
    if ( classID == -2 )
      button.value = 'Archive Students in All Classes';
    else
      button.value = 'Archive All Students Class';
  }
  else {
    button.value = 'Archive Student';
  }
}


//-- END - Student Archiver Methods.
//----------------------------------------------------------------------

//----------------------------------------------------------------------
//-- BEGIN - Summary Lister Methods.

// Summary Lister method
//   The user has chosen a class from the list.
//   Set the selected class ID and submit the form.
//
function summaryListClassChange() {
  var form = document.summaryListForm;

  var classIDIndex = form.classIDSelection.selectedIndex;
  var classID = form.classIDSelection.options[ classIDIndex ].value;
  if ( form.classID.value != classID ) {
    form.classID.value = classID;
    form.reportNow.value = 0;
    form.textID.value = -99;
    if ( typeof form.textIDSelection != "undefined") {
      form.textIDSelection.selectedIndex = -1;
    }
    form.studentID.value = -99;
    if ( typeof form.studentIDSelection != "undefined") {
      form.studentIDSelection.selectedIndex = -1;
    }               
    form.submit();
    return true;
  }
  else {
    return false;
  }
}

// Summary Lister method.
//   The user has chosen a text from the list.
//   Set the selected text ID and submit the form.
//
function summaryListTextChange() {
  var form = document.summaryListForm;

  var textIDIndex = form.textIDSelection.selectedIndex;
  var textID = form.textIDSelection.options[ textIDIndex ].value;

  if ( form.textID.value != textID ) {
    form.textID.value = textID;
    form.reportNow.value = 0;
    if ( typeof form.studentIDSelection != "undefined") {
      form.studentIDSelection.selectedIndex = -1;
    }
    form.studentID.value = -99;
    form.submit();
    return true;
  }
  else {
    return false;
  }
}


// Summary Lister method.
//   The user has chosen a student from the list.
//   Set the selected student ID.
//
function summaryListStudentChange( bigListMessage ) {
  var form = document.summaryListForm;

  var studentIDIndex = form.studentIDSelection.selectedIndex;
  var studentID = form.studentIDSelection.options[ studentIDIndex ].value;

  var submitFlag = false;
  if ( form.studentID.value != studentID ) {
    form.studentID.value = studentID;
    form.reportNow.value = 1;

    if ( checkForAllStudentsAndTexts( bigListMessage ) ) {
      submitFlag = true;
    }
    else {
      submitFlag = false;
    }       
  }
  if (submitFlag) {
    form.submit();
    return true;
  }
  else {
    return false;
  }
}


function checkForAllStudentsAndTexts( message ) {
  var form = document.summaryListForm;
  var studentIDIndex = form.studentIDSelection.selectedIndex;
  var studentID = form.studentIDSelection.options[ studentIDIndex ].value;

  if ( studentID == -2 ) {
    var textIDIndex = form.textIDSelection.selectedIndex;
    var textID = form.textIDSelection.options[ textIDIndex ].value;
    if ( textID == -2 ) {
      return confirm( message );
    }
  }
  return true;
}

//-- END - Summary Lister Methods.
//----------------------------------------------------------------------


//----------------------------------------------------------------------
//-- BEGIN - Class Snapshot functions.

// Class Snapper Form method.
//   The user has chosen a different class from the list.
//   Set the selected class ID and submit the form.
//
function classSnapperClassSelection() {
  var form = document.classReportForm;

  var classIDIndex = form.classIDSelection.selectedIndex;
  var classID = form.classIDSelection.options[ classIDIndex ].value;
  if ( form.classID.value != classID ) {
    form.classID.value = classID;
    form.createFromSelection.value = '1';
    form.submit();
    return true;
  }
  else {
    return false;
  }
}

//-- END - Class Snapshot Methods.
//----------------------------------------------------------------------
//----------------------------------------------------------------------
//-- BEGIN - Hint Editor-related functions.
//
//
// This function is called from the Text Editor to open the Hint Editor
//

function openHintEditorNeedTextID( scriptPath ) {

  var textForm = document.forms.textEditForm;

  if ( textForm.textID.value == '' ) {
    alert( "Please create or select a text before attempting to " +
           " open the Hint Editor." );
    return false;
  }
    
  openWindow( "", 'ss_hintEditor', 800, 550 );
  textForm.target = 'ss_hintEditor';
  textForm.action = scriptPath + "authoring/hintEditing.cgi";
  return true;
}

//
// This function is called from the Section Editor to open the Hint Editor.
// It requires a check for a selected section and hint.
//

function openHintEditorNeedHintID( scriptPath ) {

  var sectionForm = document.forms.sectionEditForm;

  if ( sectionForm.sectionSelection.selectedIndex < 0 ) {
    alert( "Please select a section before attempting to " +
           " open the Hint Editor." );
    return false;
  }
  else if ( sectionForm.hintID.selectedIndex < 0 ) {
    if ( sectionForm.hintID.options.length > 0 ) {
      alert( "Please select a hint before attempting to " +
             " open the Hint Editor." );
    }
    else {
      alert("Please create and select a hint before clicking the \"Edit Hint\" button.");
    }
    return false;
  }
    
  openWindow( "", 'ss_hintEditor', 800, 550 );
  sectionForm.target = 'ss_hintEditor';
  sectionForm.action = scriptPath + "authoring/hintEditing.cgi";
  return true;
}

//
// This function is called from the Section Editor to open the Hint Editor.
// It only requires a check for a selected section.
//

function openHintEditorNeedSectID( scriptPath ) {

  var sectionForm = document.forms.sectionEditForm;
  if ( sectionForm.sectionSelection.selectedIndex < 0 ) {
    alert( "Please select a section before attempting to " +
           " open the Hint Editor." );
    return false;
  }
  if (typeof sectionForm.hintID != "undefined") {
    sectionForm.hintID.selectedIndex = -1;   
  }
  openWindow( "", 'ss_hintEditor', 800, 550 );
  sectionForm.target = 'ss_hintEditor';
  sectionForm.action = scriptPath + "authoring/hintEditing.cgi";
  return true;
}

//
// This function was used by Hint Editor to check value of Attempt Count
// field. Has since been incorporated into other functions, and is not
// currently used as a standalone.
//

function checkHintAttemptCount() {

  var textForm = document.forms.hintEditForm;
  var attemptCt = textForm.hintAttemptCount.value;

  if (((isNaN (attemptCt)) || (attemptCt < 0)) || (!attemptCt)) {
    alert ("Attempt count must be a positive number.");
    return false;
  } 
  else if (attemptCt > 100) {
    alert ("Attempt count must be less than or equal to 100.");
    return false;
  }
  else {
    return true;
  }
}

//
// This function is currently not in use. The delete functionality was
// removed from the Section Editor.
//

function checkForHintDelete(scriptPath) {

  var sectionForm = document.forms.sectionEditForm;
  if ( sectionForm.hintID.selectedIndex < 0 ) {
    if (sectionForm.hintID.options.length > 0) {
      alert( "Please select a hint before attempting to delete." );
    }
    else {
      alert( "Please create and select a hint before clicking the \"Delete Hint\" button.");
    }
    return false;
  }
  sectionForm.target = '';
  sectionForm.action = scriptPath + "authoring/sectionEditing.cgi";
  return true;
}

//
// This function will add a new hint to the Section Editor. It will also
// check the values of text and attempt count.
//

function addHintToSectionText( hintForm ) {

  var returnVal;
  // first ensure that a section has been selected.
  if ( hintForm.sectionID.selectedIndex < 1 ) {
    alert( "You must select a section from the list." );
    return false;
  }
  returnVal = checkHintContent( hintForm );
  if ( returnVal ) {
    var hintContent = hintForm.hintContent.value;
    var parentWindow = self.opener;
    var parentForm = parentWindow.document.forms.sectionEditForm;

    // If we came from the section editor then we need to update
    // the list of hints there.
    if ( typeof parentForm != "undefined" ) {
      var secEdSectionIndex = parentForm.sectionSelection.selectedIndex;
      var sectSection =
        parentForm.sectionSelection.options[secEdSectionIndex].value;
      var hintEdSectionIndex = hintForm.sectionID.selectedIndex;
      var hintSection =
        hintForm.sectionID.options[hintEdSectionIndex].value;
      var hintList = parentForm.hintID;
      //
      // Check that selected sections are the same in the hint editor
      // and the section editor.  User may have changed either or both. 
      //
      if (hintSection == sectSection) {
        if (isExplorer()) {
          alert( "Hint will be added.\n\nNote: The hint list in the" +
                 " section editor will not be updated until you" +
                 " click the \"Update Section\" button." );
          return true;
        }

        var destIndex = hintList.options.length;
        var newOption =
          new Option( hintContent, hintContent, false, false );
        hintList.options[ destIndex ] = newOption;
      }
    }
    return true;
  }
  else {
    return false;
  }
}


// Ensure that the user has entered appropriate values for a hint.
// Display a message to the user if not.
//
function checkHintContent( hintForm ) {

  var attemptCt = hintForm.hintAttemptCount.value;

  if (((isNaN (attemptCt)) || (attemptCt < 0)) || (!attemptCt)) {
    alert ("Attempt count must be a positive number.");
    return false;
  } 
  else if (attemptCt > 100) {
    alert ("Attempt count must be less than or equal to 100.");
    return false;
  }
  else {
    var hintContent = hintForm.hintContent.value;

    if (!isNaN (hintContent)) {
      alert ("Text cannot be numeric only or blank.");
      return false;
    }
  }
  // default case.
  return true;
}

//
// This function deletes a hint from the Section Editor if the
// sections are the same.
//

function deleteHintFromSectionText( hintForm ) {

  var hintEdHintIndex = hintForm.hintID.selectedIndex;
  var delHintContent = hintForm.hintID.options[hintEdHintIndex].text;
  var delHintID = hintForm.hintID.options[hintEdHintIndex].value;

  var parentWindow = self.opener;
  var parentForm = parentWindow.document.forms.sectionEditForm;

  // If we came from the section editor then we need to update
  // the list of hints there.
  if ( typeof parentForm != "undefined" ) {
    var secEdSectionIndex = parentForm.sectionSelection.selectedIndex;
    var sectSection =
      parentForm.sectionSelection.options[secEdSectionIndex].value;
    var hintEdSectionIndex = hintForm.sectionID.selectedIndex;
    var hintSection = hintForm.sectionID.options[hintEdSectionIndex].value;
    var sectionHintList = parentForm.hintID;

    //
    // Check that selected sections are the same in the hint editor
    // and the section editor.  User may have changed either or both. 
    //
    if (hintSection == sectSection) {
      var howMany = sectionHintList.options.length;
      var foundIt = false;
      var i;

      // first attempt to find the hint in the sec ed with the same ID
      for (i=0; i < howMany; i++) {
        if(delHintID == sectionHintList.options[i].value) {
          sectionHintList.options[i] = null;
          foundIt = true;
          break;
        }
      }

      // if not found, then look in the sec ed for a hint with the
      // same content as the content our hint used to have.
      if (!foundIt) {
        for (i=0; i < howMany; i++) {
          if ((isNaN (sectionHintList.options[i].value)) &&
              (delHintContent == sectionHintList.options[i].value)) {
            sectionHintList.options[i] = null;
            break;
          }
        }
      }
    }
  }
  return true;
}

//
// This function puts an edited hint in the Section Editor if the
// sections match. It will also check the values of text and the
// attempt count field.
//

function updateHintFromSectionText(hintForm) {

  var returnVal = checkHintContent( hintForm );
  if ( returnVal ) {
    var hintContent = hintForm.hintContent.value;
    var parentWindow = self.opener;
    var parentForm = parentWindow.document.forms.sectionEditForm;

    // If we came from the section editor then we need to update
    // the list of hints there.
    if ( typeof parentForm != "undefined" ) {
      var secEdSectionIndex = parentForm.sectionSelection.selectedIndex;
      var sectSection =
        parentForm.sectionSelection.options[secEdSectionIndex].value;

      var hintEdSectionIndex = hintForm.sectionID.selectedIndex;
      var hintSection =
        hintForm.sectionID.options[hintEdSectionIndex].value;
      var sectionHintList = parentForm.hintID;

      var hintEdHintIndex = hintForm.hintID.selectedIndex;

      // grab the old hint content from the drop-down list in the hint ed.
      var preEditHintContent =
        hintForm.hintID.options[hintEdHintIndex].text;
      var editHintID = hintForm.hintID.options[hintEdHintIndex].value;

      //
      // Check that selected sections are the same in the hint editor
      // and the section editor.  User may have changed either or both. 
      //
      if (hintSection == sectSection) {
        // update the hint content in the section editor.
        var howMany = sectionHintList.options.length;
        var foundIt = false;
        var i;
        // first attempt to find the hint in the sec ed with the same ID
        for (i=0; i < howMany; i++) {
          if (editHintID == sectionHintList.options[i].value) {
            sectionHintList.options[i].text = hintForm.hintContent.value;
            foundIt = true;
            break;
          }
        }

        // if not found, then look in the sec ed for a hint with the
        // same content as the content our hint used to have.
        if (!foundIt) {
          for (i=0; i < howMany; i++) {
            if ((isNaN (sectionHintList.options[i].value)) &&
                (preEditHintContent == sectionHintList.options[i].value)) {
              sectionHintList.options[i].text = hintForm.hintContent.value;
              sectionHintList.options[i].value = editHintID;
              break;
            }
          }
        }
      }

    }
    return true;
  }
  else {
    return false;
  }
}


//-- END - Hint Editor-related Functions.
//----------------------------------------------------------------------
//-- BEGIN - ComparisonAnswer Editor-related Functions.

// Validate the comparison answer values.
//

function addComparisonAnswer( comparisonAnswerForm, editAnswerButtonLabel ) {

  var parentWindow = self.opener;
  var parentForm = parentWindow.document.forms.textEditForm;

  var returnVal = checkComparisonAnswerValues( comparisonAnswerForm );
  if (returnVal) {
    if ( typeof parentForm != "undefined" ) {
      parentForm.comparisonAnswerButton.value = editAnswerButtonLabel;
    }
  }   
  return returnVal;
}


// Validate the comparison answer values.
//
function updateComparisonAnswer(comparisonAnswerForm) {

  var returnVal = checkComparisonAnswerValues( comparisonAnswerForm );
  return returnVal;
}


// assume that the delete will be successful.  Update the parent window. 

function deleteComparisonAnswer( comparisonAnswerForm, createAnswerButtonLabel) {

  var parentWindow = self.opener;
  var parentForm = parentWindow.document.forms.textEditForm;

  var returnVal = checkComparisonAnswerValues( comparisonAnswerForm );
  if (returnVal) {
    if ( typeof parentForm != "undefined" ) {
      parentForm.comparisonAnswerButton.value = createAnswerButtonLabel;
    }
  }   
  return returnVal;
}

// Ensure that the user has entered appropriate values for a comparison answer.
// Display a message to the user if not.
//
function checkComparisonAnswerValues( compForm ) {

  var label = compForm.label.value;
  var answer = compForm.answer.value;
  var threshold = compForm.threshold.value;

  if ( label == '' ) {
    alert ("A label must be supplied.");
    return false;
  }
  else if ( answer == '' ) {
    alert ("An answer must be supplied.");
    return false;
  }
  else if ((isNaN (threshold) || (threshold < 0.1)) || (threshold > 0.9)) {
    alert ("The threshold must be a number between 0.1 and 0.9");
    return false;
  }
  else {
    return true;
  }
}


function openComparisonEditor( scriptPath, editorName ) {

  var textForm = document.forms.textEditForm;

  if ( textForm.textID.value == '' ) {
    alert( "Please create or select a text before attempting to " +
           " open the " + editorName );
    return false;
  }
    
  openWindow( "", 'ss_comparisonEditor', 800, 650 );
  textForm.target = 'ss_comparisonEditor';
  textForm.action = scriptPath + "authoring/comparisonEditing.cgi";
  return true;
}

//-- END - Comparison Answer Editor functions.
//----------------------------------------------------------------------
//-- BEGIN - Section editor related functions

function warnContentActive( count, activityType ) {

  if ( count > 0 ) {
    if ( activityType == 'essay' ) {
      return confirm( '' + count +
                      " responses have been submitted for this prompt.  Please " +
                      "confirm that you want to modify the score categories." );
    }
    else {
      return confirm( '' + count +
                      " summaries have been submitted for this reading. " +
                      "Please confirm that you want to modify the sections." );
    }
  }
}

//-- END - Section editor-related Functions.
//----------------------------------------------------------------------

//
// Equivalent to window.print, but safely detects whether the brower
// supports window.print, and directs the user to the browser's
// print menu if not.
//
function printWindowSafe() {
  if (window.print) {
    window.print()  
      } else {
    alert('Your browser does not support this print button. To print, select Print from the File menu.');
  }
}



// -- functions for school database management --

// confirm that user wants to assign selected school to selected DB
function confirmAssignSchoolToDB() {
  var form = document.schoolDbForm;
  var sch = form.schoolSelection.value;
  var db = form.databaseSelection.value;
  if ((typeof sch == "undefined") || (typeof db == "undefined") ||
      (sch.match(/^-----/)) || (db.match(/^-----/))) {
    alert("To assign a school to a database, select both a school and a database, then click 'Assign'.");
    return false;
  }         
  return confirm("Assign school '" + sch + "' to database '" + db + "'?");
}

// add new school DB name to selection list
function newDbName() {
  var schools = document.getElementById('databaseSelection');
  var newOption = document.createElement('option');
  var newDbName = prompt('New Database Name:');
  var dbSchoolDisplay = document.getElementById('selectedDBSchoolList');
  newOption.value = newDbName;
  newOption.text = newDbName;
  schools.appendChild(newOption);
  schools.value = newDbName;
  dbSchoolDisplay.value = '';
}

// in SchoolDbSelector, show current db for schoolID (if any)
function displayForSelectedSchool() {
  var school = document.getElementById('schoolSelection').value;
}

// display list of schools currently in selected db (in any)
function displayForSelectedDatabase(dbID) {
  var db = document.getElementById('databaseSelection').value;
  var dbSchoolDisplay = document.getElementById('selectedDBSchoolList');
  var dbSchools = getDbSchools(db);
  if (dbSchools.length > 0) {
    var schoolsTxt = dbSchools.join("\n");
    dbSchoolDisplay.value = schoolsTxt;
  } else {
    dbSchoolDisplay.value = '';
  }
}

// return list of schools assigned to db
function getDbSchools(db) {
  var dbSchools = document.getElementsByName('SCHOOLDB_' + db);
  var aSchools = new Array(dbSchools.length);
  for (i = 0; i < dbSchools.length; i++) {
    aSchools[i] = dbSchools[i].value;
  }
  return aSchools;
}


// Ensure that the user has entered a user ID and selected (or preselected)
//    a school. 
//
function validateLogin( ) {
  var form = document.forms.loginForm;

  var userID = form.login.value;
  var password = form.password.value;
  var userIDError = false;
  var passwordError = false;
  var schoolSelectionError = false;

  var returnVal = true;

  if ( !userID ) { userIDError = true; }
  if ( !password ) { passwordError = true; }

  // schoolID may be a hidden field or it may be a selection box.
  if (( typeof form.schoolID != "undefined" ) &&
      (typeof form.schoolID.selectedIndex != "undefined" ) &&
      (form.schoolID.selectedIndex < 1)) {
    schoolSelectionError = true;
  }

  if ( userIDError && passwordError ) {
    var message =
      "Please type in your user ID and password and select your " +
      "school from the list.";
    alert( message );
    returnVal = false;
  }
  else if ( userIDError ) {  
    alert( "Please type in your user ID." );
    returnVal = false;
  }
  else if ( passwordError ) {  
    alert( "Please type in your password." );
    returnVal = false;
  }
  else if ( schoolSelectionError ) {
    returnVal = false;
    alert( "Please select a school." );
  }

  return returnVal;
}


//----------------------------------------------------------------------
//-- BEGIN - Registration functions.

function verifyRegistrationSchoolSelection() {
  var form = document.registrationForm;  

  var schoolPIDIndex = form.schoolSelection.selectedIndex;
  var returnVal = true;
  if ( schoolPIDIndex == 0 ) {
    var otherSchool = form.otherSchool.value;
    if ( otherSchool.match( /^\s*$/ ) ) {
      alert( 'You must either select a school from the drop-down list, ' +
             'type in a school name, or click ' +
             '"Back to Step 1" and provide a different school zip code.' );
      returnVal = false;
    }
  }

  return returnVal;
}


function verifyAgreementAcceptance( appName ) {
  var form = document.registrationForm;  

  var checkbox = form.acceptAgreement;
  if ( !checkbox.checked ) {
    alert( 'You must accept the subscriber agreement to register your ' +
           appName + ' purchase.' );
    return false;
  }
  else {
    return true;
  }
}

//-- END - Registration functions.
//----------------------------------------------------------------------
//-- BEGIN - Subscription Activator / Account Archiver functions

function confirmSubscriptionActivation( challengeMessage ) {
  return confirm( challengeMessage );
}

//-- END - Subscription Activator / Account Archiver functions
//----------------------------------------------------------------------

//----------------------------------------------------------------------
//-- BEGIN - Prompt Editing functions.

function prepareForPromptSubmission() {
  var form = document.promptEditForm;

  var returnVal = true;

  var gradeLevelIndex = form.gradeLevel.selectedIndex;
  var genreIndex = form.genre.selectedIndex;
  var title = form.promptTitle.value;
  var prompt = form.promptContent.value;

  if ( prompt.match( /^\s*$/ ) ) {
    alert( 'You must provide prompt content. ' +
           'The prompt is what the student reads and responds to. ' + 
           'For help writing the prompt, click the green question mark.' );
    returnVal = false;
  }
  else if ( title.match( /^\s*$/ ) ) {
    alert( 'You must provide a title for your prompt. ' +
           'The title is what the student sees on their activity selection page. ' +
           'For help writing a title, click the green question mark.' );
    returnVal = false;
  }     
  else if ( gradeLevelIndex == 0 ) {
    alert( 'You must select a grade level for your prompt. ' +
           'For help selecting a grade level, click the green question mark.' );
      returnVal = false;
  }
  else if ( genreIndex == 0 ) {
    alert( 'You must select an essay type for your prompt. ' +
           'For help selecting an essay type, click the green question mark.' );
      returnVal = false;
  }
  
 
  return returnVal;
}  // prepareForPromptSubmission


function prepareForAssignmentRedirect() {
  var form = document.promptEditForm;
  
  var returnVal = true;
  if ( form.dirty.value != '' ) {
    var confMsgPrefix = 'You have changed ';
    var confMsgSuffix = ' Click OK to save your changes and ' +
      'switch to the Assignments Tool.';
    var fieldMsg;
    if ( form.dirty.value == 'multiple' ) {
      fieldMsg = 'multiple attribute values.'
    }
    else {
      fieldMsg = 'the "' + form.dirty.value + '" field.'
    }
    returnVal = confirm( confMsgPrefix + fieldMsg + confMsgSuffix );
    if ( returnVal ) {
      returnVal = prepareForPromptSubmission()
    }
  }

  return returnVal;

} // prepareForAssignmentRedirect


// Confirm deletion of a prompt
//
function confirmPromptDeletion( form, promptName, classCount ) {

  var message = "Are you sure you want to delete the prompt " +
    "\"" + promptName + "\"?";

  if ( classCount > 0 ) {
    if ( classCount == 1 ) {
      message += "  It is used in 1 class.";
    }
    else {
      message += "  It is used in " + classCount + " classes.";
    }
  }
  else {
    message += "  It is not currenty used in any classes.";
  }

  if ( confirm( message )) {
    // clear form target in case it was previously set to a child window.
    form.target = '';
    return true;
  }
  else { 
    return false;
  }
} // confirmPromptDeletion


function recordPromptFieldChange( columnLabel ) {
  var form = document.promptEditForm;

  if ( form.dirty.value == '' || form.dirty.value == columnLabel ) {
    form.dirty.value = columnLabel;
  }
  else {
    form.dirty.value = 'multiple';
  }

} // recordPromptFieldChange


//-- END - Prompt Editing functions.
//----------------------------------------------------------------------

// Open the teacher comments response display window.
//
function displayResponseWithComments( windowTitle, displayScript, linkId,
                                      newLinkLabel ) { 

  var annoLink = document.getElementById( linkId );
  annoLink.innerHTML = newLinkLabel;
  openWindow( displayScript, windowTitle, 900, 600 );
  return false;
}


// displayBrowserUnsupported
//
//   Something the user wants to do is not supported by the
//   browser they are using.  Alert them to the situation.

function displayBrowserUnsupported( message ) {

  alert( message );
  return false;

}  // displayBrowserUnsupported


//-- BEGIN - Utility functions.

// Ensure that the author has selected given list item.
//
function validateSelection(element, descriptor) {
  var selectionError = false;
  var returnVal = true;

  if (element.selectedIndex < 1) { selectionError = true; }

  if ( selectionError ) {
    returnVal = false;
    alert( "Please select a " + descriptor + "." );
  }

  return returnVal;
}

//-- END - Utility functions
//----------------------------------------------------------------------
