// $Id: lookupSupport.js,v 1.64 2008/09/18 22:56:51 dharris Exp $

// this holds the control that we're going to dynamically update with control values
var lookupControlToUpdate = null;

// this holds an error that might be detected during creation of the dynamic submit form
var submitFormError = "";

// this array has the default prompts for text fields in the search form and is used when we
// clear the text field or check to make sure it has a value.
var textFieldDefaultPrompts = new Array();
textFieldDefaultPrompts[0] = 'enter text...';
textFieldDefaultPrompts[1] = 'Enter part of candidate\'s name';
textFieldDefaultPrompts[2] = 'Enter a PAC, party committee or 527 organization name';
textFieldDefaultPrompts[3] = 'Enter a name';
textFieldDefaultPrompts[4] = 'Enter part of lobbyist name';
textFieldDefaultPrompts[5] = 'Enter part of lobbying firm or client name';

// when a text field has the prompt IN the field value, then when the user
// clicks on the field the prompt gets cleared out of the value.
function clearTextField(field) {
  for (n = 0; n < textFieldDefaultPrompts.length; n++) {
    if (textFieldDefaultPrompts[n] == field.value) {
      field.value = '';
      break;
    }
  }
}

// this function is called when a lookup select control is changed which might
// cause the controls that are displayed to change...
function lookupSelectChanged(controlidFragment, lookupIndex) {
  var el;
  // start by hiding all of the sub controls beneath the specified id (and making sure this one is shown)
  for ( lookupControlId in oLookupControlData ) {
    if (lookupControlId.indexOf(controlidFragment) == 0) {
      el = document.getElementById(lookupControlId + "_" + lookupIndex);
      if (lookupControlId == controlidFragment) {
        el.style.display = ''; // show the one that changed
      } else {
        el.style.display = 'none'; // hide the children of the one that changed
      }
    }
  }
  // then show the the children underneath the new value specified for the selected control
  var elControl = document.getElementById(controlidFragment + "_CONtrol_" + lookupIndex);
  if (elControl) {
    var newvalue = elControl.options[elControl.selectedIndex].value;
    // start by showing the immediate child based on what was selected but only if the child has a
    // control to show
    showLookupControl(controlidFragment + "_" + newvalue, lookupIndex);
  }
}

// this function is used to show a child control.  If the child control needs
// data and has an ajax hook that hasn't been used yet, use it.
function showLookupControl(controlid, lookupIndex) {
  var el = document.getElementById(controlid + "_" + lookupIndex);

  if (el) {
    // ajax call to get values for this control that we're going to show?
    if (oLookupControlData[controlid] != '') {
      fetchControlValues(controlid, lookupIndex);
    }
    // show the control
    el.style.display = 'inline';
    conditionallyShowGrandchild(controlid, lookupIndex);

    // copy in savedTextValue?
    if (oLookupToolControls[currentLookupToolName][controlid].leaf) {
      var elControlField = document.getElementById(controlid + "_CONtrol_" + lookupIndex);
      if (elControlField) {
        if (elControlField.type == "text" && savedTextValue != "") {
          elControlField.value = savedTextValue;
        } else {
          savedTextValue = "";
        }
      }
    }
  }
}

// If the provided control is a select type, then look at the selected option
// and try to show that control, then recurse as possible
function conditionallyShowGrandchild(controlid, lookupIndex) {
  var elControl = document.getElementById(controlid + "_CONtrol_" + lookupIndex);
  if (elControl && elControl.options) {
    var grandChildSelectedValue = elControl.options[elControl.selectedIndex].value;
    showLookupControl(controlid + "_" + grandChildSelectedValue, lookupIndex);
  }
}

// use ajax call to fetch control values for the element specified by controlid and lookupIndex
function fetchControlValues(controlid, lookupIndex) {
  var ajaxDataSource = oLookupControlData[controlid];
  // get the select control
  lookupControlToUpdate = document.getElementById(controlid + "_CONtrol_" + lookupIndex);
  lookupControlToUpdate.options[1] = new Option("please wait...", "please wait...");

  var isAjaxAvailable = Try.these(
      function() {return new ActiveXObject('Msxml2.XMLHTTP')},
      function() {return new ActiveXObject('Microsoft.XMLHTTP')},
      function() {return new XMLHttpRequest()}
      ) || false;
  if (isAjaxAvailable) {
    var params = 'datasource=' + ajaxDataSource;
    var ajaxCall = new Ajax.Request('fetch-lookup-data.do',
        { method: 'get', parameters: params, onComplete: parseControlValueResponse } );
  }
}

// this function handles the ajax request for control value data to be added to a
// control only when we need to display the control.
function parseControlValueResponse(originalRequest) {
  var root = originalRequest.responseXML.documentElement;
  var responseNodes = root.getElementsByTagName("option");
  lookupControlToUpdate.options[1] = null;
  for (var n = 0; n < responseNodes.length; n++) {
    var optionNode = responseNodes.item(n);
    lookupControlToUpdate.options[lookupControlToUpdate.options.length] = new Option(
        optionNode.firstChild.nodeValue, optionNode.attributes.getNamedItem("value").value);
  }
}

// return the first/root lookup control key for the specified lookup tool
function getRootLookupControlKey(lookupToolName) {
  for (lookupControlKey in oLookupToolControls[lookupToolName]) {
    return lookupControlKey;
  }
  return null;
}

// function called when search form submitted and used to re-render the search
// form based on what the user submitted (effectively, persists the search form)
function renderLookupControlsFromCurrentSearch(lookupToolName) {
  if (currentSearchParams.length == 0) {
    renderLookupControls(lookupToolName, 0);
  } else {
    for (n = 0; n < currentSearchParams.length; n++) {
      renderLookupControls(lookupToolName, n);
    }
    adjustFirstRow(lookupToolName);
  }
}

// render a set of lookup controls.  The lookupToolName is the lookupTool's name
// from the configuration file.  criteriaIndex indicates the row number for this
// set of controls, 0 based.
function renderLookupControls(lookupToolName, criteriaIndex) {
  // update oCriteriaRows; create the array if it hasn't already been created
  // (keyed on the lookupToolName) and then add a row to the array for this criteriaIndex
  if (!(oCriteriaRows[lookupToolName])) {
    oCriteriaRows[lookupToolName] = new Array();
  }
  oCriteriaRows[lookupToolName][criteriaIndex] = 'true';

  var elRowContainer = document.getElementById(lookupToolName + "_Container_" + criteriaIndex);
  var newHtml = oLookupTemplates.render('lookupRow', [lookupToolName, criteriaIndex]);

  // if this isn't the first row, add logic selector control
  if (criteriaIndex > 0) {
    var whichLogic = 'or';
    if (currentSearchParams.length > 0 && criteriaIndex <= (currentSearchParams.length - 1)) {
      whichLogic = currentSearchParams[criteriaIndex].logic;
    }
    newHtml += oLookupTemplates.render((whichLogic == 'or' ? 'logicSelectorOr' : (whichLogic == 'and' ? 'logicSelectorAnd' : 'logicSelectorNot')),
        [getRootLookupControlKey(lookupToolName), criteriaIndex]);
  } else {
    newHtml += oLookupTemplates.render('emptyElement', [lookupToolName, criteriaIndex]);
  }

  for (lookupControlKey in oLookupToolControls[lookupToolName]) {
    lookupControl = oLookupToolControls[lookupToolName][lookupControlKey];

    // do we have currentSearchParams?  If so, does the paramId start with the current control id?  If so, special handling
    var handleAsCurrentSearchParam = false;
    if (currentLookupToolName == lookupToolName && currentSearchParams.length > 0 &&
        criteriaIndex <= (currentSearchParams.length - 1) &&
        currentSearchParams[criteriaIndex].paramId.indexOf(lookupControl.id) == 0) {
      handleAsCurrentSearchParam = true;
    }

    // is the control hidden or shown?  This defaults to what lookupControl.styleDisplay is unless this is a currentSearchParam
    var displayIt = lookupControl.styleDisplay; // default

    if (currentLookupToolName == lookupToolName && currentSearchParams.length > 0) {
      if (handleAsCurrentSearchParam) {
        displayIt = "";
      } else {
        displayIt = "none";
      }
    }

    if (displayIt == "none") {
      newHtml += oLookupTemplates.render('lookupControlElementStartHidden', [lookupControl.id, criteriaIndex, lookupControl.cssContainerClass]);
    } else {
      newHtml += oLookupTemplates.render('lookupControlElementStart', [lookupControl.id, criteriaIndex, lookupControl.cssContainerClass]);
    }

    // what cssControlClass should be used?
    var cssControlClassToUse = lookupControl.cssControlClass;
    if (criteriaIndex == 0 && lookupControl.firstCssControlClass != "") {
      cssControlClassToUse = lookupControl.firstCssControlClass;
    }

    // what's the value to be used?  from the currentSearchParams or the default?
    var useDefaultControlValue = true;
    if (handleAsCurrentSearchParam) {
      useDefaultControlValue = false;
    }

    if (lookupControl.matchTypeSelector == 'true') {
      var whichMatchType = 'c';
      if (handleAsCurrentSearchParam) {
        whichMatchType = currentSearchParams[criteriaIndex].matchType;
      }
      newHtml += oLookupTemplates.render((lookupControl.controlValues.length > 1 ? 'altMatchTypeSelectorRow' : 'matchTypeSelectorRow'),
          [lookupControl.name, lookupControl.id, criteriaIndex,
          (whichMatchType == 'c' ? "selected='true'" : ""),
          (whichMatchType == 's' ? "selected='true'" : ""),
          (whichMatchType == 'a' ? "selected='true'" : "")]);
    }

    // more than one controlValues in this control? if so, render HTML select control, otherwise, render text input box
    if (lookupControl.controlValues.length > 1) {
      newHtml += oLookupTemplates.render('lookupSelectControl',
          [lookupControl.name, lookupControl.id, criteriaIndex, lookupControl.onchange, lookupControl.cssControlStyle, cssControlClassToUse]);
      for( var n = 0; n < lookupControl.controlValues.length; n++) {
        if (lookupControl.controlValues[n].datasource ) {
          for (var i = 0; oSharedDataSources[lookupControl.controlValues[n].datasource] &&
               i < oSharedDataSources[lookupControl.controlValues[n].datasource].length; i++) {
            sharedLookupControlValue = oSharedDataSources[lookupControl.controlValues[n].datasource][i];
            if (currentLookupToolName == lookupToolName && currentSearchParams.length > 0 && criteriaIndex <= (currentSearchParams.length - 1) &&
                currentSearchParams[criteriaIndex].paramId == lookupControl.id &&
                sharedLookupControlValue.value == currentSearchParams[criteriaIndex].value) {
              newHtml += oLookupTemplates.render('lookupSelectOption', [sharedLookupControlValue.value, sharedLookupControlValue.display, "selected='true'"]);
            } else {
              newHtml += oLookupTemplates.render('lookupSelectOption', [sharedLookupControlValue.value, sharedLookupControlValue.display, ""]);
            }
          }
        } else {
          // add the control value if there are no firstRowTypes or if the corresponding value from
          // the first row is contained within the firstRowTypes
          var renderThisControlValue = false;
          if (criteriaIndex == 0) {
            // render the control value if this is the first row
            renderThisControlValue = true;
          } else if (lookupControl.controlValues[n].firstRowTypes == "") {
            // render the control value if there are now firstRowTypes specified for this control value
            renderThisControlValue = true;
          } else {
            // check the value of the corresponding control in the first row against the
            // list of firstRowTypes for this control value.  Found it? render the control value.
            var elFirstRowControl = document.getElementById(lookupControl.id + "_CONtrol_0");
            var testValue = elFirstRowControl.options[elFirstRowControl.selectedIndex].value;
            if (lookupControl.controlValues[n].firstRowTypes.indexOf(testValue) > -1) {
              renderThisControlValue = true;
            }
          }
          if (renderThisControlValue) {
            var isOptionSelected = false;
            if (currentLookupToolName == lookupToolName && currentSearchParams.length > 0 && criteriaIndex <= (currentSearchParams.length - 1)) {
              if (currentSearchParams[criteriaIndex].paramId.indexOf(lookupControl.id + "_" + lookupControl.controlValues[n].value) == 0) {
                isOptionSelected = true;
              } else if (currentSearchParams[criteriaIndex].value == lookupControl.controlValues[n].value) {
                isOptionSelected = true;
              }
            }
            newHtml += oLookupTemplates.render('lookupSelectOption', [lookupControl.controlValues[n].value, lookupControl.controlValues[n].display, (isOptionSelected ? "selected='true'" : "")]);
          }
        }
      }
      newHtml += oLookupTemplates.render('lookupSelectControlEnd');
    } else {
      var controlValueText = lookupControl.controlValues[0].value;
      if (currentLookupToolName == lookupToolName && currentSearchParams.length > 0 && criteriaIndex <= (currentSearchParams.length - 1)
          && currentSearchParams[criteriaIndex].paramId == lookupControl.id) {
        controlValueText = currentSearchParams[criteriaIndex].value;
      }
      // replace double quotes with entity and prepare the value fragment for the template
      var controlValueText = controlValueText.replace(/\"/g, "&quot;");
      var valueFragment = (controlValueText ? "value=\"" + controlValueText + "\" " : "");
      newHtml += oLookupTemplates.render('lookupTextControl',
          [lookupControl.name, lookupControl.id, criteriaIndex,
          (lookupControl.controlValues[0].size ? "size='" + lookupControl.controlValues[0].size + "' " : ""),
          valueFragment,
          lookupControl.cssControlStyle,
          (lookupControl.controlValues[0].onfocus ? "onfocus='" + lookupControl.controlValues[0].onfocus + "' " : ""),
          cssControlClassToUse]);
    }

    newHtml += oLookupTemplates.render('lookupControlElementEnd');
  }

  newHtml += oLookupTemplates.render('lookupRowEnd');

  // render add/remove controls
  if (oMultiCriteriaLookup[lookupToolName] ) {
    if (criteriaIndex > 0) {
      newHtml += oLookupTemplates.render('addRemoveCriteriaRow', [lookupToolName, criteriaIndex]);
    } else {
      newHtml += oLookupTemplates.render('addRemoveCriteriaRowFirst', [lookupToolName, criteriaIndex]);
    }
  }

  elRowContainer.innerHTML = newHtml;
  elRowContainer.style.display = ''; // show the row container element
}

// show first row hidden element which, by showing it, acts as a spacer to move the
// controls on the first row to the right so they line up with added rows which
// have a logic selector on the far left
function adjustFirstRow(lookupToolName) {
  document.getElementById(lookupToolName + "_emptyelement_0").style.display = 'inline';
}

// this function responds to user click to add a row of criteria based on the
// first row selection
function addCriteria(lookupToolName) {
  var newCriteriaIndex = 0;
  // calculate the index of the new row based on what's in oCriteriaRows
  if (oCriteriaRows[lookupToolName]) {
    newCriteriaIndex = oCriteriaRows[lookupToolName].length;
  }

  adjustFirstRow(lookupToolName);

  renderLookupControls(lookupToolName, newCriteriaIndex);

  // artificially trigger a "change" on the first control of this row so we get the
  // correct fields to show
  for (lookupControlKey in oLookupToolControls[lookupToolName]) {
    lookupControl = oLookupToolControls[lookupToolName][lookupControlKey];
    lookupSelectChanged(lookupControl.id, newCriteriaIndex);
    break;
  }
}

// this function responds to user click to remove a row of criteria, removeIndex
// indicates the row to remove.
function removeCriteria(lookupToolName, removeIndex) {
  // update the oCriteriaRows object array and hide the element containing the row to be removed
  oCriteriaRows[lookupToolName][removeIndex] = 'false';
  var elRowContainer = document.getElementById(lookupToolName + "_Container_" + removeIndex);
  elRowContainer.style.display = 'none';
  elRowContainer.innerHTML = "";
}

// this function resets the specified form to it's default state
function resetTool(lookupToolName) {
  eval("lookupToolClear" + lookupToolName + "()");
  // reset oCriteriaRows which contains the list of rows of criteria for a lookup tool and also the currentSearchParams array
  oCriteriaRows[lookupToolName] = null;
  currentSearchParams = new Array();
  // find and clear the row container elements
  var n = 0;
  while (true) {
    var elRowContainer = document.getElementById(lookupToolName + "_Container_" + n);
    if (elRowContainer) {
      ++n;
      elRowContainer.style.display = 'none';
      elRowContainer.innerHTML = "";
    } else {
      break;
    }
  }
  // draw the first row of controls again
  renderLookupControls(lookupToolName, 0);

  // reset multi-ecid picker
  hideMultiECIDSelector(true, true);

  updateMultiECIDSelectorOption(true);
}

// this function draws a series of invisible divs that will hold rows of criteria as they are added
function drawEmptyRows(lookupToolName, howmany) {
  for (var n = 0; n < howmany; n++) {
    document.writeln(oLookupTemplates.render('emptyRowContainer', [lookupToolName, n]));
  }
}

// the purpose of this function is to generate a value object (key, value, match type)
// for a set of controls (criteria row) in a lookup tool.  The function may recursively
// call itself to achieve this if necessary
function getValueObjectForThisRow(lookupToolName, controlKey, rowIndex, rootControlKey) {
  oLookupToolControl = oLookupToolControls[lookupToolName][controlKey];
  var elControl = document.getElementById(controlKey + "_CONtrol_" + rowIndex);
  if (oLookupToolControl.leaf) {
    var o = new Object();
    o.key = oLookupToolControl.name;
    if (elControl.options) {
      o.value = elControl.options[elControl.selectedIndex].value;
    } else {
      o.value = elControl.value;
    }
    if (oLookupToolControl.matchTypeSelector == 'true') {
      var elMatchType = document.getElementById(controlKey + "_MatchType_CONtrol_" + rowIndex);
      o.matchType = elMatchType.options[elMatchType.selectedIndex].value;
    }
    if (rowIndex > 0) {
      var elLogic = document.getElementById(rootControlKey + "_lookupLogic_" + rowIndex);
      o.logic = elLogic.options[elLogic.selectedIndex].value;
    }
  } else {
    return getValueObjectForThisRow(lookupToolName, controlKey + "_" + elControl.options[elControl.selectedIndex].value,
        rowIndex, rootControlKey);
  }
  return o;
}

// the purpose of this function is to scan the named lookup tool and extract the
// user's selections for that tool creating HTML that has input elements that
// represent the user's selections  Put the HTML into the innerHTML of the element for the form that will be submitted
function createDynamicSubmitFormElements(lookupToolName) {
  var el = document.getElementById(lookupToolName + "_FORM");
  var retHtml = "";

  var aValsToSet = new Object();
  
  var nRowCounter = 0;
  var nPopulatedRowCounter = 0;
  while (true) {
    // does the row exist in the array?
    if (oCriteriaRows[lookupToolName][nRowCounter]) {
      // is the row active or deleted?
      if (oCriteriaRows[lookupToolName][nRowCounter] == 'true') {
        var rootControlKey = getRootLookupControlKey(lookupToolName);
        o = getValueObjectForThisRow(lookupToolName, rootControlKey, nRowCounter, rootControlKey);
        aValsToSet[o.key + "_" + nPopulatedRowCounter] = o.value;
        retHtml += "<input type='hidden' name='" + o.key + "_" + nPopulatedRowCounter + "' value=''/>" +
            (o.matchType ? "<input type='hidden' name='matchType_" + nPopulatedRowCounter + "_" + o.key + "' value='" + o.matchType + "'/>": "") +
            (o.logic ? "<input type='hidden' name='logic_" + nPopulatedRowCounter + "_" + o.key + "' value='" + o.logic + "'/>" : "");
        // make sure we have a valid search
        if (submitFormError == "" && o.value == "") {
          bError = false;
          if (o.matchType) {
            if (o.matchType != "a") {
              bError = true;
            }
          } else {
            bError = true;
          }
          if (bError) {
            submitFormError = "Error. A field you are searching with is empty.";
            document.getElementById(rootControlKey + "_CONtrol_" + nRowCounter).focus();
          }
        }
        for (n = 0; n < textFieldDefaultPrompts.length; n++) {
          if (textFieldDefaultPrompts[n] == o.value) {
            bError = true;
            submitFormError = "Error. A field you are searching with hasn't been filled in.";
            break;
          }
        }
        
        ++nPopulatedRowCounter;
      }
    } else {
      // no more rows exist to look at, break out of loop
      break;
    }
    ++nRowCounter;
  }

  // is there an election cycle selector for this tool?
  var elElectionCycleSelector = document.getElementById(lookupToolName + "_lookupElectionCycleSelectorId");
  if (elElectionCycleSelector != null) {
    var selectValue = elElectionCycleSelector.options[elElectionCycleSelector.selectedIndex].value;
    if (selectValue == 'multi') {
      // multiple election cycles
      var elMultiECIDCB = null;
      var n = 0;
      var foundMultiECID = false;
      while (true) {
        elMultiECIDCB = document.getElementById("multiElectionCyclePickerId" + n);
        if (elMultiECIDCB == null)
          break;
        if (elMultiECIDCB.checked) {
          retHtml += "<input type='hidden' name='electionCycleId' value='" + elMultiECIDCB.value + "'/>";
          foundMultiECID = true;
        }
        ++n;
      }
      if (!foundMultiECID) {
        submitFormError = "You must select at least one election cycle.";
      }
    } else {
      retHtml += "<input type='hidden' name='electionCycleId' value='" + selectValue + "'/>";
    }
  }

  retHtml += "<input type='hidden' name='LTN' value='" + lookupToolName + "'/>";

  el.innerHTML = retHtml;
  
  // set the values
  for (valueKey in aValsToSet) {
    document.forms[lookupToolName + "Form"].elements[valueKey].value = aValsToSet[valueKey];
  }
}

// the purpose of this function is to generate the markup for an HTML select containing the election cycles
function getElectionCycleSelector(lookupToolName) {
  var useSearchedElectionCycle = false;
  if (searchedElectionCycle != "" && currentSearchParams.length > 0 && lookupToolName == currentLookupToolName) {
    useSearchedElectionCycle = true;
  }
  var html = "<select id='" + lookupToolName + "_lookupElectionCycleSelectorId' size='1' onchange='lookupECIDChanged(\"" + lookupToolName + "\")'>";
  if (lookupToolName == "campaignFinance") {
    html += "<option value='multi'>multi-cycles</option>";
  }
  for (var n = 0; n < aElectionCycles.length; n++) {
    html += "<option value='" + aElectionCycles[n].id + "' ";
    if (useSearchedElectionCycle) {
      if (aElectionCycles[n].id == Number(searchedElectionCycle))
        html += "selected='true'";
    } else if (aElectionCycles[n].current) {
      html += "selected='true'";
    }
    html += ">" + aElectionCycles[n].display + "</option>";
  }
  return html + "</select>";
}

// function updates the multi option in the election cycle picker and provides a warning if necessary
function updateMultiECIDSelectorOption(checkforwarning) {
  if (currentLookupToolName == "campaignFinance") {
    var control = document.getElementById("id_campaignFinance_controlType_CONtrol_0");
    if (control) {
      // if the first row control type value is individuals or disbursements then allow for multi ECID selector
      var elECIDSelector = document.getElementById("campaignFinance_lookupElectionCycleSelectorId");
      var searchtype = control.options[control.selectedIndex].value;
      
      var oldSelectedIndex = elECIDSelector.selectedIndex; // remember the old selector
      
      var oldHadMulti = elECIDSelector.options[0].value == "multi";
      
      // create a new set of options
      var newOptions = new Array();
      
      // add multi-cycle if appropriate
      if (searchtype == "indivLookupType" || searchtype == "disburseLookupType") {
        newOptions[0] = new Option("multi-cycles", "multi", false, false);
      } else {
        // first type is NOT indiv or disbursements, make sure we don't have multi ecid and warn
        // the user if they were using the multi selector
        if (oldHadMulti) {
          var multiWasSelected = false;
          if (elECIDSelector.options[oldSelectedIndex].value == "multi") {
            multiWasSelected = true;
            if (checkforwarning && checkforwarning == true) {
              alert("Multiple election cycle searching is not possible unless either 'individual donor' or 'disbursements' is chosen for the first line.");
            }
          }
          hideMultiECIDSelector(true, multiWasSelected);
        }
      }
      
      // create the rest of the options...
      for (var n = 0; n < aElectionCycles.length; n++) {
        // disbursements has fewer cycles
        if (searchtype == "disburseLookupType" && n > (numberOfDisbursementsECIDs - 1)) {
          // adjust the old selected index if it isn't applicable any more and break out of the loop
          if (oldHadMulti && oldSelectedIndex > numberOfDisbursementsECIDs)
            oldSelectedIndex = 1;
          if (!oldHadMulti && oldSelectedIndex > (numberOfDisbursementsECIDs - 1))
            oldSelectedIndex = 0;
          break;
        }
        newOptions[newOptions.length] = new Option(aElectionCycles[n].display, aElectionCycles[n].id, false, false);
      }
      
      // hide or show the appropriate checkboxes on the popup multi ecid selector
      var popupDisplayStyle = "";
      if (searchtype == "disburseLookupType") {
        popupDisplayStyle = "none";
      }
      for (var n = numberOfDisbursementsECIDs; n < aElectionCycles.length; n++) {
        var el = document.getElementById("multiECIDCBContainer" + n);
        if (el != null) {
          el.style.display = popupDisplayStyle;
          if (popupDisplayStyle == "none") {
            // also clear out the checkbox
            var elCB = document.getElementById("multiElectionCyclePickerId" + n);
            elCB.checked = false;
          }
        }
      }
      
      // erase the old options
      for (n = elECIDSelector.options.length - 1; n >= 0; n--) {
        elECIDSelector.options[n] = null;
      }
      
      // set the new options
      for (n = 0; n < newOptions.length; n++) {
        elECIDSelector.options[n] = newOptions[n];
      }
      
      // update the selectedIndex to what it used to be if possible
      if (oldHadMulti) {
        if (elECIDSelector.options[0].value == "multi") {
          elECIDSelector.selectedIndex = oldSelectedIndex; // the old one had multi, the current one does too, selected is the same
        } else {
          // the old one had multi, the current doesn't, set the new selected to the old - 1 unless it was 0
          elECIDSelector.selectedIndex = (oldSelectedIndex == 0 ? 0 : oldSelectedIndex - 1);
        }
      } else {
        if (elECIDSelector.options[0].value == "multi") {
          // the old one didn't have multi, the current one does, set the new selected to the old + 1
          elECIDSelector.selectedIndex = oldSelectedIndex + 1;
        } else {
          // the old one didn't have multi, the new one doesn't either, selected is the same
          elECIDSelector.selectedIndex = oldSelectedIndex;
        }
      }
      
      // update the display of multi selected cycles if appropriate
      if (elECIDSelector.options[elECIDSelector.selectedIndex].value == "multi") {
        goLookupElectionCycles();
      }
    } // condition on if we have the control
  } // condition on lookup tool being campaignFinance
}

// called when user selects multiple cycles option from election cycle selector
function lookupECIDChanged(lookupToolName) {
  var el = document.getElementById(lookupToolName + "_lookupElectionCycleSelectorId");
  if (el.selectedIndex == 0 && el.options[el.selectedIndex].value == 'multi') {
    popupMultiECIDSelector();
  } else {
    hideMultiECIDSelector(true, false);
  }
}

// show the multi election cycle ID selector control
function popupMultiECIDSelector() {
  var el = document.getElementById(currentLookupToolName + "_lookupElectionCycleSelectorId");
  var popup = document.getElementById("multiElectionCyclePicker");
  var fromLeft = el.offsetLeft;
  //var fromTop = el.offsetTop + 25;
  var IE = document.all?true:false;
  if (IE) {
    fromLeft = el.offsetLeft+el.offsetParent.offsetLeft;
    //fromTop = el.offsetTop+el.offsetParent.offsetTop+25;
  }
  // setting the top offset is unnecessary; top positioning is taken care of through HTML/CSS
  popup.style.left = fromLeft+'px';
  popup.style.visibility = "visible";
}

// hide the multi election cycle ID selector.
// If doReset is true, then reset the multi ecid picker too
// If resetSelector is true, then the election cycle drop list selector is reset.
function hideMultiECIDSelector(doReset, resetSelector) {
  // hide the multi cycle picker
  var popup = document.getElementById("multiElectionCyclePicker");
  if (popup != null)
    popup.style.visibility = "hidden";
  if (doReset) {
    setAllLookupElectionCycles(false);
    var el = document.getElementById(currentLookupToolName + "_SubmitSpanId");
    el.innerHTML = "";
  }
  if (resetSelector) {
    // clear election cycle if there is one
    var elElectionCycleSelector = document.getElementById(currentLookupToolName + "_lookupElectionCycleSelectorId");
    if (elElectionCycleSelector) {
      if (elElectionCycleSelector.options[0].value == "multi") {
        elElectionCycleSelector.selectedIndex = 1;
      } else {
        elElectionCycleSelector.selectedIndex = 0;
      }
    }
  }
}

// this function renders the HTML area showing the selected election cycles and an edit link
function drawSelectedElectionCycles(selectedElectionCycles) {
  var el = document.getElementById(currentLookupToolName + "_SubmitSpanId");
  var newHtml = oLookupTemplates.render('submitSpanStart');

  // only show first 3 cycles.  if more than 3 cycles, show first 3 and append ellipsis.  if no cycles selected, display mesage.
  if(selectedElectionCycles.length > 3) { var max = 3; var ellipsis = '...'; }
  else if(selectedElectionCycles.length == 0) { var max = 0; var ellipsis = '(none selected)'; }
  else { var max = selectedElectionCycles.length; var ellipsis = ''; }

  for (n = 0; n < max; n++) {
    for (l = 0; l < aElectionCycles.length; l++) {
      if (aElectionCycles[l].id == selectedElectionCycles[n]) {
        newHtml += (n == 0 ? "" : ", ") + aElectionCycles[l].display;
        break;
      }
    }
  }

  newHtml += ellipsis+oLookupTemplates.render('submitSpanEnd');
  el.innerHTML = newHtml;
}

// when user clicks "go" button on the multi-election cycle picker, figure out what they selected
function goLookupElectionCycles() {
  var elElectionCycleSelector = document.getElementById(currentLookupToolName + "_lookupElectionCycleSelectorId");
  if (elElectionCycleSelector.options[elElectionCycleSelector.selectedIndex].value == "multi") {
    var el = null;
    var n = 0;
    var selectedElectionCycles = new Array();
    while (true) {
      el = document.getElementById("multiElectionCyclePickerId" + n);
      if (el == null)
        break;
      if (el.checked) {
        selectedElectionCycles[selectedElectionCycles.length] = el.value;
      }
      ++n;
    }
    hideMultiECIDSelector(false, false);

    drawSelectedElectionCycles(selectedElectionCycles);
  }
}

// when user clicks select all or clear all on the multi-election cycle picker
function setAllLookupElectionCycles(isChecked) {
  var el = null;
  var n = 0;
  while (true) {
    el = document.getElementById("multiElectionCyclePickerId" + n);
    ++n;
    if (el == null)
      break;
    
    // if we're checking the box AND this box isn't displayed, don't check it
    if (isChecked) {
      var elSpan = document.getElementById("multiECIDCBContainer" + (n - 1));
      if (elSpan != null && elSpan.style.display == "none")
        continue;
    }
    
    el.checked = isChecked;
  }
}

// this function hides the currently visible lookup tool tab and then shows the one named in the parameter
function showLookupTab(lookupToolName) {
  for( lookupToolNameKey in oLookupToolControls ) {
    var el = document.getElementById(lookupToolNameKey + "_OuterContainerBox");
    var elTabBox = document.getElementById(lookupToolNameKey + "_TabBox");
    if (lookupToolNameKey == lookupToolName) {
      el.style.display = '';
      elTabBox.className = "subtab-on";
    } else {
      if (el.style.display != 'none')
        el.style.display = 'none';
      elTabBox.className = "subtab-off";
    }
  }
  // special case where instructions are shown or hidden based on the campaignFinance tab being shown
  if (lookupToolName == "campaignFinance") {
    document.getElementById("campFinInstructionsId").style.display = '';
  } else {
    document.getElementById("campFinInstructionsId").style.display = 'none';
  }

  hideMultiECIDSelector(true, true);

  currentLookupToolName = lookupToolName;

  updateMultiECIDSelectorOption(true);
}

// this function draws the standard cycle based lookup/search tool submit controls
function drawStandardCycleSubmissionControls(lookupToolName) {
  var bIncludeElectionCycleSelector = true;
  var submitFunctionName = '';

  if (lookupToolName == 'campaignFinance') {
    submitFunctionName = 'submitCampaignFinanceLookup';
  } else if (lookupToolName == 'lobbySearch') {
    bIncludeElectionCycleSelector = false;
    submitFunctionName = 'submitLobbySearchLookup';
  } else if (lookupToolName == 'candidateSearch') {
    submitFunctionName = 'submitCandidateSearchLookup';
  } else if (lookupToolName == 'pacSearch') {
    submitFunctionName = 'submitPacSearchLookup';
  }

  if (bIncludeElectionCycleSelector) {
    document.writeln(getElectionCycleSelector(lookupToolName));
  }

  document.writeln("<input class='input_btn' style='margin-top:1px;' type='image' border='0' alt='Go' src='images/btn_pml_go.gif' onclick='" + submitFunctionName + "(\"" + lookupToolName + "\")'/>");
  document.writeln("<input class='input_btn' style='margin-top:1px;' type='image' border='0' alt='Clear' src='images/btn_pml_clear.gif' onclick='resetTool(\"" + lookupToolName + "\")'/>");
}

// this function invoked when the user changes the match type selector on the first row and we need to
// enable or disable box four (campfin lookup tool)
function matchTypeSelectorChanged(selector, lookupToolId, criteriaIndex) {
  var matchTypeSelectorValue = selector.options[selector.selectedIndex].value;
  // enable or disable the corresponding control
  var el = document.getElementById(lookupToolId + "_CONtrol_" + criteriaIndex);
  if (matchTypeSelectorValue == 'a') {
    el.disabled = true;
    if (el.type == "text") {
      el.value = "";
    } else {
      el.selectedIndex = 0;
    }
  } else {
    el.disabled = false;
  }
}

// handle form submission by pressing enter
function checkForKeySubmit(e) {
  var c;
  if (e && e.which) {
    c = e.which;
  } else {
    c = event.keyCode;
  }
  if (c == 13) {
    if (currentLookupToolName == "campaignFinance") {
      submitCampaignFinanceLookup(currentLookupToolName);
    } else if (currentLookupToolName == "pacSearch") {
      submitPacSearchLookup(currentLookupToolName);
    } else if (currentLookupToolName == "candidateSearch") {
      submitCandidateSearchLookup(currentLookupToolName);
    } else if (currentLookupToolName == "lobbySearch" ) {
      submitLobbySearchLookup(currentLookupToolName);
    }
    return false;
  }
  return true;
}

var savedTextValue = '';
// whenever user leaves a text field on a search form, save the value
function saveTextValue(textfield) {
  if (textfield.value != "")
    savedTextValue = textfield.value;
}

