function FormManager(form)
{
  this.myForm = this.getFormObj(form);

  this.subscrFields = new Array();
  this.unsubFields = new Array();
  this.checkboxFields = new Array();
  this.radioFields = new Array();
  this.radioSets = new Array();
  this.textFields = new Array();
  this.hiddenFields = new Array();
  this.otherFields = new Array();

  this.errObjArray = new Array();
  this.errMsgArray = new Array();
  this.errMsgStr = "";

  this.phoneRE = new RegExp('[^\\d]*(\\d{3})[^\\d]*(\\d{3})[^\\d]*(\\d{4})');
  //this.phoneRE.compile('[^\\d]*(\\d{3})[^\\d]*(\\d{3})[^\\d]*(\\d{4})');

  this.invalidEmailCharsRE = new RegExp('[\\s/:,;]');
  //this.invalidEmailCharsRE.compile('[\\s/:,;]');

  if (this.myForm) {
    this.init();
  }

  /*
  alert ("FormMgr: "
      + (this.myForm.id ? this.myForm.id : this.myForm.name)
      + " is ready"
    );
  */
}


FormManager.prototype.getFormObj = function(form)
{
  if (!form) {
    return null;
  }
  var rtVal = null;

  if (typeof form == "string") {
    if (document.getElementById) {
      rtVal = document.getElementById(form);
    }
    else if (document.elements) {
      rtVal = document.elements[form];
    }
    else {
      return null;
    }
  }
  else {
    rtVal = form;
  }

  if (typeof rtVal == "object") {
    var formRE = new RegExp('^form$', 'i');
    if (! formRE.test(rtVal.nodeName)) {
      rtVal = null;
    }
  }
  return rtVal;
}

FormManager.prototype.init = function()
{
  if (!this.myForm) {
    return false;
  }

  if (this.subscrFields.length > 0) {
    this.subscrFields = new Array();
  }
  if (this.unsubFields.length > 0) {
    this.unsubFields = new Array();
  }
  if (this.checkboxFields.length > 0) {
    this.checkboxFields = new Array();
  }
  if (this.radioFields.length > 0) {
    this.radioFields = new Array();
  }
  if (this.radioSets.length > 0) {
    this.radioSets = new Array();
  }
  if (this.textFields.length > 0) {
    this.textFields = new Array();
  }
  if (this.hiddenFields.length > 0) {
    this.hiddenFields = new Array();
  }
  if (this.otherFields.length > 0) {
    this.otherFields = new Array();
  }

  var allFormFields;
  if (this.myForm.elements) {
    allFormFields = this.myForm.elements;
  }
  else {
    return false;
  }

  var i;
  var iObj;

  for (i=0; i<allFormFields.length; i++) {
    var iObj = allFormFields[i];
    if (iObj.type == "checkbox") {
      if (iObj.value == "subscribe") {
	this.subscrFields.push(iObj);
      }
      else if (iObj.value == "unsubscribe") {
	this.unsubFields.push(iObj);
      }
      else {
	this.checkboxFields.push(iObj);
      }
    } // END if (checkbox)
    else if (iObj.type == "radio") {
      this.radioFields.push(iObj);
    }
    else if (iObj.type == "text") {
      this.textFields.push(iObj);
    }
    else if (iObj.type == "hidden") {
      this.hiddenFields.push(iObj);
    }
    else if (iObj.type == "button") {
      // ignore
    }
    else if (iObj.type == "submit") {
      // ignore
    }
    else {
      this.otherFields.push(iObj);
    }
  }

  for (i=0; i<this.radioFields.length; i++) {
    iObj = this.radioFields[i];
    if (! this.radioSets[iObj.name]) {
      this.radioSets[iObj.name] = new Array();
    }
    this.radioSets[iObj.name].push(iObj);
  }

  return true;

} // End function init

FormManager.prototype.clearForm = function()
{
  this.clearWhoAreYou();
  this.clearListSelections();
}

FormManager.prototype.clearWhoAreYou = function()
{
  var clearThese;
  var fieldArray;
  var fieldObj;
  var i;

  clearThese = new Array();
  clearThese['firstName'] = true;
  clearThese['lastName'] = true;
  clearThese['userEmail'] = true;
  clearThese['userEmail2'] = true;
  clearThese['subscriberType'] = true;

  fieldArray = this.textFields;
  for (i=0; i<fieldArray.length; i++) {
    fieldObj = fieldArray[i];
    if (clearThese[fieldObj.name]) {
      fieldObj.value = "";
    }
  }

  fieldArray = this.radioFields;
  for (i=0; i<fieldArray.length; i++) {
    fieldObj = fieldArray[i];
    if (clearThese[fieldObj.name]) {
      if (fieldObj.click) {
	fieldObj.checked = true;
	fieldObj.click();
      }
      fieldObj.checked = false;
    }
  }

}

FormManager.prototype.clearListSelections = function()
{
  var fieldArray;
  var fieldObj;
  var i;
  var clearThese;

  // The click() method will toggle a checkbox.  To make the checkbox
  // false, first set it to truw, then toggle it.  This doesn't seem
  // to work on ALL browsers so explicitly set checked to false.
  fieldArray = this.subscrFields;
  for (i=0; i<fieldArray.length; i++) {
    fieldObj = fieldArray[i];
    if (fieldObj.checked) {
      fieldObj.click();
      fieldObj.checked = false;
    }
  }

  fieldArray = this.unsubFields;
  for (i=0; i<fieldArray.length; i++) {
    fieldObj = fieldArray[i];
    if (fieldObj.checked) {
      fieldObj.click();
      fieldObj.checked = false;
    }
  }

  clearThese = new Array();
  clearThese['phone'] = true;
  clearThese['nav-paper-optout'] = true;

  fieldArray = this.textFields;
  for (i=0; i<fieldArray.length; i++) {
    fieldObj = fieldArray[i];
    if (clearThese[fieldObj.name]) {
      fieldObj.value = "";
    }
  }

  fieldArray = this.checkboxFields;
  for (i=0; i<fieldArray.length; i++) {
    fieldObj = fieldArray[i];
    if (clearThese[fieldObj.name]) {
      if (fieldObj.checked) {
	fieldObj.click();
	fieldObj.checked = false;
      }
    }
  }
}

FormManager.prototype.showMe = function(textField)
{
  var showMeObj = document.getElementById(textField);
  if (! showMeObj) {
    return;
  }
  showMeObj.value = "allFormFields: " + this.myForm.elements.length;
  showMeObj.value += "\n" + "subscrFields=" + this.subscrFields.length;
  showMeObj.value += "\n" + "unsubFields=" + this.unsubFields.length;
  showMeObj.value += "\n" + "checkboxFields=" + this.checkboxFields.length;
  showMeObj.value += "\n" + "radioFields=" + this.radioFields.length;
  showMeObj.value += "\n" + "textFields=" + this.textFields.length;
  showMeObj.value += "\n" + "hiddenFields=" + this.hiddenFields.length;
  showMeObj.value += "\n" + "otherFields=" + this.otherFields.length;

} // End function showMe()

FormManager.prototype.enablePhone = function(chkBoxObj)
{
  var phoneDivObj;
  var phoneObj;

  if (document.getElementById) {
    phoneDivObj = document.getElementById("phoneDiv");
    phoneObj = document.getElementById("phone");
  }

  if ((! chkBoxObj) || (! phoneDivObj) || (! phoneObj)) {
    return;
  }

  if (chkBoxObj.checked) {
    phoneDivObj.style.display = "block";
    phoneObj.disabled = false;
    phoneObj.removeAttribute("readonly", 0);
    if (phoneObj.scrollIntoView) {
	phoneObj.scrollIntoView(false);
    }
  }
  else {
    phoneDivObj.style.display = "none";
    phoneObj.disabled = true;
    phoneObj.setAttribute("readonly", true, 0);
  }
}

FormManager.prototype.canonicalizePhone = function(phoneStr)
{
  // The pattern (spread out for readability):
  // [^\d]*  (\d{3})  [^\d]*  (\d{3})  [^\d]*  (\d{4})
  //
  // The pattern says this:
  // [^\d]*  ==> zero or more non-digit characters
  // -- followed by
  // (\d{3}) ==> 3 digits (Area Code), the parens tell the pattern
  //             matcher to add the match to the results array
  // -- followed by
  // [^\d]*  ==> zero or more non-digit characters
  // -- followed by
  // (\d{3}) ==> 3 digits (Prefix), the parens tell the pattern
  //             matcher to add the match to the results array
  // -- followed by
  // [^\d]*  ==> zero or more non-digit characters
  // -- followed by
  // (\d{4}) ==> 4 digits (Suffix), the parens tell the pattern
  //             matcher to add the match to the results array
  //
  // Put more simply, a numeric pattern of 3 3 4 possibly separated
  // or surrounded with non-numeric chars
  //
  var tmpStr = new String(phoneStr);
  var matchResults;
  matchResults = tmpStr.match(this.phoneRE);
  if (matchResults) {
    return '(' + matchResults[1] + ') '
	       + matchResults[2] + '-' + matchResults[3];
  }
  else {
    return null;
  }
}

FormManager.prototype.phoneBlur = function(phoneObj)
{
  if ( (! phoneObj)
       ||
       (! phoneObj.value)
       ||
       (phoneObj.disabled)
       ||
       (phoneObj.value == "")
     )
  {
    return;
  }

  var tmpStr = this.canonicalizePhone(phoneObj.value);

  if (tmpStr) {
    phoneObj.value = tmpStr;
  }
}

FormManager.prototype.nameBlur = function(nameObj)
{
  if (nameObj && nameObj.value) {
    nameObj.value = FormManager.trim(nameObj.value);
  }
}

FormManager.prototype.emailBlur = function(emailObj)
{
  if (emailObj && emailObj.value) {
    emailObj.value = FormManager.trim(emailObj.value);
  }
}

FormManager.prototype.validateName = function()
{
  var retVal = true;
  var nameObj;

  if (this.myForm.elements) {
    nameObj = this.myForm.elements['firstName'];
  }
  else {
    nameObj = null;
    retVal = false;
  }
  if (nameObj) {
    nameObj.value = FormManager.trim(nameObj.value);
    if (nameObj.value.length < 1) {
      this.errObjArray.push(nameObj);
      this.errMsgArray.push("First Name is empty");
      retVal = false;
    }
  }

  if (this.myForm.elements) {
    nameObj = this.myForm.elements['lastName'];
  }
  else {
    nameObj = null;
    retVal = false;
  }
  if (nameObj) {
    nameObj.value = FormManager.trim(nameObj.value);
    if (nameObj.value.length < 1) {
      this.errObjArray.push(nameObj);
      this.errMsgArray.push("Last Name is empty");
      retVal = false;
    }
  }

  return retVal;
}


FormManager.prototype.validateEmail = function()
{
  var emailObj;
  var emailAddr;
  var emailObj2;
  var emailAddr2;
  var errMsg;

  if (this.myForm.elements) {
    emailObj = this.myForm.elements['userEmail'];
    emailObj2 = this.myForm.elements['userEmail2'];
  }
  else {
    emailObj = null;
    emailObj2 = null;
    retVal = false;
  }

  if (emailObj) {
    emailObj.value = FormManager.trim(emailObj.value);
    emailAddr = emailObj.value;
  }
  else {
    return false;
  }

  if (emailObj2) {
    emailObj2.value = FormManager.trim(emailObj2.value);
    emailAddr2 = emailObj2.value;
  }

  if ((!emailAddr) || (emailAddr.length < 1)) {
    this.errObjArray.push(emailObj);
    this.errMsgArray.push("Email Address is empty");
    return false;
  }
    
  if (this.invalidEmailCharsRE.exec(emailAddr) != null) {
      errMsg = "Your e-mail address contains an invalid character.\n"
	    +
	    "The character \"" + RegExp.lastMatch
	    + "\" is not allowed in an e-mail address."
	    + "\n\n" + emailAddr
	    ;
    this.errObjArray.push(emailObj);
    this.errMsgArray.push(errMsg);
    return false;
  }

  // Check for the presence of the "@" symbol
  var atIdx;
  if ((atIdx=emailAddr.indexOf("@",0)) < 0) {
    errMsg = "Did you forget the \"@\" symbol in your e-mail address?"
	  + "\n\n" + emailAddr;
    this.errObjArray.push(emailObj);
    this.errMsgArray.push(errMsg);
    return false;
  }

  // Check to make sure there is only a single "@" symbol
  if (emailAddr.indexOf("@", atIdx+1) >= 0) {
    errMsg = "A valid e-mail address may only contain one \"@\" symbol."
	  + "\n\n" + emailAddr;
    this.errObjArray.push(emailObj);
    this.errMsgArray.push(errMsg);
    return false;
  }

  // Check for at least one "." after the "@"
  var dotIdx
  if ((dotIdx=emailAddr.indexOf(".", atIdx)) < 0) {
    errMsg = "The domain name (the part after the '@') appears to be incomplete."
	  + "\n\n" + emailAddr;
    this.errObjArray.push(emailObj);
    this.errMsgArray.push(errMsg);
    return false;
  }

  // Check for at least two chars after the  "."
  if ((dotIdx+3) > emailAddr.length) {
    errMsg = "Did you forget the domain (\".com\", \".net\", \".org\", etc.)?"
	  + "\n\n" + emailAddr;
    this.errObjArray.push(emailObj);
    this.errMsgArray.push(errMsg);
    return false;
  }

  if (emailObj2 && (emailAddr != emailAddr2)) {
    errMsg = "The two e-mail addresses don't match"
    this.errObjArray.push(emailObj);
    this.errMsgArray.push(errMsg);
    return false;
  }

  return true;

} // END validateEmail(emailAddr)


FormManager.prototype.validateChoices = function()
{
  var navOptOut;
  var phoneObj;
  var retVal = true;
  var count=0;
  var optOut = false;
  var i;

  for (i=0; i<this.subscrFields.length; i++) {
    if (this.subscrFields[i].checked) {
      count++;
    }
  }

  for (i=0; i<this.unsubFields.length; i++) {
    if (this.unsubFields[i].checked) {
      count++;
    }
  }


  if (this.myForm.elements) {
    navOptOut = this.myForm.elements['nav-paper-optout'];
    phoneObj = this.myForm.elements['phone'];
  }
  else {
    retVal = false;
    navOptOut = null;
    phoneObj = null;
  }

  if (navOptOut && phoneObj) {
    if (navOptOut.checked) {
      var tmpStr = this.canonicalizePhone(phoneObj.value);
      optOut = true;
      if (tmpStr) {
	phoneObj.value = tmpStr;
	count++;
      }
      else {
	this.errObjArray.push(navOptOut);
	if (phoneObj.value.length < 1) {
	  this.errMsgArray.push("News and Views paper opt out: We need your phone number to locate your record");
	}
	else {
	  this.errMsgArray.push("News and Views paper opt out: The phone number seems to be incomplete.  Please provide your area code and phone number");
	}
        retVal = false;
      }
    }
  }

  if (retVal && (count > 0)) {
    retVal = true;
  }
  else {
    if (document.getElementById) {
      var errObj = document.getElementById("lists");
      if (errObj) {
	this.errObjArray.push(errObj);
      }
    }
    if (!optOut && (count < 1)) {
      this.errMsgArray.push("You haven't selected any lists");
    }
    retVal = false;
  }

  return retVal;
}

FormManager.prototype.validateSubscriberType = function()
{
  var rtVal = false;
  var i;
  var iObj;
  var radioSet =  this.radioSets['subscriberType'];
  if (radioSet) {
    for (i=0;i<radioSet.length;i++) {
      iObj = radioSet[i];
      if (iObj.checked) {
        rtVal = true;
	break;
      }
    }
  }
  if (!rtVal) {
    if (document.getElementById) {
      var errObj = document.getElementById("lists");
      if (errObj) {
	this.errObjArray.push(errObj);
      }
    }
    this.errMsgArray.push("You haven't selected the type of subscriber you are");
  }

  return rtVal;
}

FormManager.prototype.validationReset = function()
{
  this.errMsgStr = "";
  this.errObjArray = new Array();
  this.errMsgArray = new Array();
}

FormManager.prototype.validationErrorDialog = function()
{
  var scrollY = 0;
  var i;

  if (this.errObjArray.length > 0) {
    for (i=0; i<this.errMsgArray.length; i++) {
      if (i > 0) {
	this.errMsgStr += "\n";
      }
      this.errMsgStr +=  "=> " + this.errMsgArray[i];
    }

    if (! this.errMsgStr) {
      this.errMsgStr =
	  "One or more required fields in the form are incomplete.\n"
	+ "Please review the required fields and make sure they are filled in."
	;
    }

    alert("Please fix the following errors:\n" + this.errMsgStr);

    if (this.errObjArray[0].focus) {
      this.errObjArray[0].focus();
      scrollY = -30;
    }

    if (this.errObjArray[0].scrollIntoView) {
      this.errObjArray[0].scrollIntoView();
      scrollY = -30;
    }

    if (window.scrollBy) {
      window.scrollBy(0, scrollY);
    }

  }
  else {
    alert("One or more required fields in the form are incomplete.\n"
	+ "Please review the required fields and make sure they are filled in."
      );
  }
}

FormManager.prototype.validateForm = function()
{
  var retVal = false;
  this.validationReset();

  // Set the return value to the result of the first
  // test, then && with the rsults of subsequent tests.
  // Thus, if any test returns false, the result will be false.
  retVal = this.validateName();
  retVal = this.validateSubscriberType() && retVal;
  retVal = this.validateEmail() && retVal;
  retVal = this.validateChoices() && retVal;

  if (! retVal) {
    this.validationErrorDialog();
  }

  return retVal;
}


function cellClick(listName, myAction, otherAction, ev)
{
  objID = listName + "-" + myAction;
  obj = document.getElementById(objID);
  if (obj) {
    obj.focus();
    obj.click();
    //obj.checked = ! obj.checked;
    //radioCheck(obj, listName, myAction, otherAction, ev);
  }
}


// Make checkboxes work like radio buttons
function radioCheck(cbox, listName, myAction, otherAction, ev)
{
  // On the way into this function, ev will be null for IE, non-null
  // for Firefox.  If it's null, fix it up.
  if (!ev) {
    var ev = window.event;
  }
  var cellID = listName + "-" + myAction + "Cell";
  var cellObj = document.getElementById(cellID);

  if (cellObj) {
    if (cbox.checked) {
      cellObj.style.backgroundColor = 
	(myAction == "sub") ? "#98ff98" : "#ff9866"; //"#ffcc98";
    }
    else {
      cellObj.style.backgroundColor="";
    }
  }

  var otherObjID = listName + "-" + otherAction;
  var otherCellID = listName + "-" + otherAction + "Cell";
  var otherObj = document.getElementById(otherObjID);
  if (otherObj) {
    if (otherObj.checked) {
      otherObj.checked = 0; // Set it to false
      otherCellObj = document.getElementById(otherCellID);
      if (otherCellObj) {
	otherCellObj.style.backgroundColor="";
      }
    }
  }

  if (ev) {
    ev.cancelBubble = 1; // set it to true (for IE, no effect for Firefox)
    if (ev.stopPropagation) { // for Firefox
      ev.stopPropagation();
    }
  }
}

FormManager.trimWsRE = RegExp('^\\s+|\\s+$', 'g');
//FormManager.trimWsRE.compile('^\\s+|\\s+$', 'g');
FormManager.trim = function(str)
{
  if (typeof str == "string") {
    return str.replace(FormManager.trimWsRE, "");
  }
  else {
    return str;
  }
}
