
// clear all cookies when you start any type of search (gene, structure, age)
function clearSearchCookies() {
    var allTableIds = [
        "gene_list_table", // gene search
        "h_list_table",    // structure search
        "a_list_table",
        "v_list_table",
        "pfc_list_table",
        "pvc_list_table",
        "age0_list_table", // age search
        "age3_list_table",
        "age12_list_table",
        "age48_list_table",
        "substruct2AgesListTable", // substructure search, 2 ages for same substruct
        "2SubstructsListTable"];   // substructure search, 2 substructs at same age

    var tableId;
    for (var i = 0; i < allTableIds.length; ++i) {
      tableId = allTableIds[i];
      document.cookie = tableId + '=;; path=/';
    }
}

//-------------------------------------------
// Gene search (text input)
//-------------------------------------------
function searchWidget(searchBoxName, searchButtonName, searchPath) {
    this.searchBoxName = searchBoxName;
    this.searchButtonName = searchButtonName;
    this.searchPath = searchPath;
    var self = this;

    clearSearchCookies();
    setupSearch();

    function setupSearch() {
        var searchBox = document.getElementById(self.searchBoxName);
        var searchBtn = document.getElementById(self.searchButtonName);
        if (searchBox !== null)
            searchBox.onkeyup = doEnter;
        if (searchBtn !== null)
            searchBtn.onclick = doSearch;
    }

    function doSearch() {
        var term = document.getElementById(self.searchBoxName).value;
        if (term.length == 0) {
            alert("Please enter some value for which to search.");
        } else {
            term = encodeURIComponent(term);
            window.location = "/" + self.searchPath + "/gene.html?gene_term=" + term + "&searchSym=t&searchAlt=t&searchName=t&searchHom=t&searchEntrez=t&searchNCBI=t";
        }
    }

    function doEnter(evt) {
        var returnKey = 13;

        var key;
        if (window.event)
            key = window.event.keyCode;
        else
            key = evt.which;

        if (key == returnKey) {
            doSearch();
        }
    }
}

//------------------------------------------------
// Structure and Age search
//------------------------------------------------
/*
 * Function used to implement "Select All" and "Clear All" pushbuttons
 *
 * parentId - id of parent container of the checkboxes
 * setOrClear - true to select all checkboxes, false to unselect all checkboxes
 */
function setAllCheckboxes(parentId, setOrClear) {
    var parent = $(parentId);
    var checkBoxes = parent.getElementsBySelector('[type="checkbox"]');
    var len = checkBoxes.length;
    for (var i = 0; i < len; ++i) {
        checkBoxes[i].checked = setOrClear;
    }

    return false; // cancel any further button actions
}

/*
 * Support function of the "Go" search button for the Structure/Age searches
 *
 * returns an array of values of all checkboxes that are selected (checked)
 * for a given parent container id.
 *
 * If all checkboxes are selected, then the array will contain only a single
 * value, '*'
 *
 * If no values are found, an empty array is returned.
 */
function getAllCheckedValues(parentId) {
    var values = new Array();

    var parent = $(parentId);
    var checkBoxes = parent.getElementsBySelector('[type="checkbox"]');
    var len = checkBoxes.length;
    for (var i = 0; i < len; ++i) {
        if (checkBoxes[i].checked === true) {
            values.push(checkBoxes[i].value);
        }
    }

    // Business rule:
    // everything was checked, use '*' in lieu of all values
    if (values.length === checkBoxes.length) {
        values = new Array(1);
        values[0] = "*";
    }

    return values;
}

/*
 * Construct a structure search url, then load the document represented by the url
 *
 * searchPath - base url
 * hippocampusPrefix - id of <div class="accordion_content">; this is used as checkbox parent container's id prefix
 * amygdalaPrefix - id of <div class="accordion_content">; this is used as checkbox parent container's id prefix
 * ventralStriatumPrefix - id of <div class="accordion_content">; this is used as checkbox parent container's id prefix
 * visualCortexPrefix - id of <div class="accordion_content">; this is used as checkbox parent container's id prefix
 *
 */
function searchByStructure(searchPath, hippocampusPrefix, amygdalaPrefix, ventralStriatumPrefix, visualCortexPrefix) {
    var ageSuffix = "_ages"; // checkbox parent container's id suffix
    var geneSuffix = "_genes"; // checkbox parent container's id suffix

    var hippocampus = new structureObj(hippocampusPrefix + ageSuffix, hippocampusPrefix + geneSuffix);
    var amygdala = new structureObj(amygdalaPrefix + ageSuffix, amygdalaPrefix + geneSuffix);
    var ventralStriatum = new structureObj(ventralStriatumPrefix + ageSuffix, ventralStriatumPrefix + geneSuffix);
    var visualCortex = new structureObj(visualCortexPrefix + ageSuffix, visualCortexPrefix + geneSuffix);

    // Business rule:
    // make sure at least one structure has at least one selection for ages and one selection for genes,
    // or else not enough terms specified to conduct a search
    var selectionsMissing = false;
    if (hippocampus.getAges().length === 0 || hippocampus.getGenes().length === 0) {
        if (amygdala.getAges().length === 0 || amygdala.getGenes().length === 0) {
            if (ventralStriatum.getAges().length === 0 || ventralStriatum.getGenes().length === 0) {
                if (visualCortex.getAges().length === 0 || visualCortex.getGenes().length === 0) {
                    selectionsMissing = true;
                }
            }
        }
    }
    if (selectionsMissing) {
        alert("You must make at least one selection from 'Refine search by Age'" + "\n"
              + "and one selection from 'Refine search by Gene' before a search can conducted.");
        return false;
    }

    clearSearchCookies();

    // build search url args
    var urlArgs = buildStructureSearchArgs(hippocampus, amygdala, ventralStriatum, visualCortex);

    // redirect to structure search url
    window.location = "/" + searchPath + "/structure.html?" + urlArgs;

    return false;
}

/*
 * Want args for a given structure to look like this:
 *    amygdala=ages:0,3,48;genes:CALB1,HTR2C,LOC721855&hippocampus...&ventralstriatum...
 * Special case, if all ages or genes selected, the value is '*". Example:
  *    amygdala=ages:*;genes:*
 *
 */
function buildStructureSearchArgs(hippocampus, amygdala, ventralStriatum, visualCortex) {
    // ---- private functions ----
    function buildOneStructureArg(structName, ages, genes, order_param, odir_param) {
        var newAges = new Array();
        var args = "";

        if (ages.length === 1 && ages[0] === "*") {
            // don't do anything if the "*" wildcard is found
            newAges = ages;
        }
        else {
            // strip off the text, leaving just the integer month value
            for (var i = 0; i < ages.length; ++i) {
                newAges.push(parseInt(ages[i]));
            }
        }
        args += structName + "=ages:";
        args += newAges.join(",");
        args += ";genes:";
        args += genes.join(",");

        args += "&" + order_param + "=genesymbol"
        args += "&" + odir_param + "=asc"

        return args;
    }
    // ---- end private functions ----

    var hArgs = ""; // hippocampus args
    var aArgs = ""; // amygdala args
    var vArgs = ""; // ventral striatum args
    var pvcArgs = ""; // primary visual cortex args
    var allArgs = "";

    var hAges = hippocampus.getAges();
    var hGenes = hippocampus.getGenes();
    var aAges = amygdala.getAges();
    var aGenes = amygdala.getGenes();
    var vAges = ventralStriatum.getAges();
    var vGenes = ventralStriatum.getGenes();
    var pvcAges = visualCortex.getAges();
    var pvcGenes = visualCortex.getGenes();

    // build hippocampus args
    if (hAges.length > 0 && hGenes.length > 0) {
        hArgs = buildOneStructureArg("hippocampus", hAges, hGenes, "h_order", "h_odir");
    }

    // build amygdala args
    if (aAges.length > 0 && aGenes.length > 0) {
        aArgs = buildOneStructureArg("amygdala", aAges, aGenes, "a_order", "a_odir");
    }

    // build ventral striatum args
    if (vAges.length > 0 && vGenes.length > 0) {
        vArgs = buildOneStructureArg("ventralstriatum", vAges, vGenes, "v_order", "v_odir");
    }

    // build primary visual cortex args
    if (pvcAges.length > 0 && pvcGenes.length > 0) {
        pvcArgs = buildOneStructureArg("primaryvisualcortex", pvcAges, pvcGenes, "pvc_order", "pvc_odir");
    }

    // append args together
    if (hArgs != "") allArgs += hArgs;
    if (aArgs != "") allArgs += "&" + aArgs;
    if (vArgs != "") allArgs += "&" + vArgs;
    if (pvcArgs != "") allArgs += "&" + pvcArgs;

    return allArgs;
}

/*
 * Structure object
 *
 * Used to represent the Ages and Genes to be searched
 * for each respective structure
 *
 * agesParentId - <div> id of the parent container for the Ages checkboxes
 * genesParentId - <div> id of the parent container for the Genes checkboxes
 */
function structureObj(agesParentId, genesParentId) {
    var ages;  // array
    var genes; // array

    ages = getAllCheckedValues(agesParentId);
    genes = getAllCheckedValues(genesParentId);

    this.getAges = function() {
        return ages;
    };

    this.getGenes = function() {
        return genes;
    };

}

/*
 * Construct a age search url, then load the document represented by the url
 *
 * searchPath - base url
 * age0_Prefix - id of <div class="accordion_content">; this is used as checkbox parent container's id prefix
 * age3_Prefix - id of <div class="accordion_content">; this is used as checkbox parent container's id prefix
 * age12_Prefix - id of <div class="accordion_content">; this is used as checkbox parent container's id prefix
 * age48_Prefix - id of <div class="accordion_content">; this is used as checkbox parent container's id prefix
 *
 */
function searchByAge(searchPath, age0_Prefix, age3_Prefix, age12_Prefix, age48_Prefix) {
    var structureSuffix = "_structs"; // checkbox parent container's id suffix
    var geneSuffix = "_genes"; // checkbox parent container's id suffix

    var age0 = new ageObj(age0_Prefix + structureSuffix, age0_Prefix + geneSuffix);
    var age3 = new ageObj(age3_Prefix + structureSuffix, age3_Prefix + geneSuffix);
    var age12 = new ageObj(age12_Prefix + structureSuffix, age12_Prefix + geneSuffix);
    var age48 = new ageObj(age48_Prefix + structureSuffix, age48_Prefix + geneSuffix);

    // Business rule:
    // make sure at least one age has at least one selection for structures and one selection for genes,
    // or else not enough terms specified to conduct a search
    var selectionsMissing = false;
    if (age0.getStructs().length === 0 || age0.getGenes().length === 0) {
        if (age3.getStructs().length === 0 || age3.getGenes().length === 0) {
            if (age12.getStructs().length === 0 || age12.getGenes().length === 0) {
                if (age48.getStructs().length === 0 || age48.getGenes().length === 0) {
                    selectionsMissing = true;
                }
            }
        }
    }
    if (selectionsMissing) {
        alert("You must make at least one selection from 'Refine search by Structure'" + "\n"
              + "and one selection from 'Refine search by Gene' before a search can conducted.");
        return false;
    }

    clearSearchCookies();

    // build search url args
    var urlArgs = buildAgeSearchArgs(age0, age3, age12, age48);

    // redirect to structure search url
    window.location = "/" + searchPath + "/age.html?" + urlArgs;

    return false;
}

/*
 * Want args for a given age to look like this:
 *    age0=structs:amygdala,ventralstriatum;genes:CALB1,HTR2C,LOC721855
 * Special case, if all structs or genes selected, the value is '*". Example:
 *    age3=structs:*;genes:*
 *
 */
function buildAgeSearchArgs(age0, age3, age12, age48) {
    // ---- private functions ----
    function buildOneStructureArg(ageName, structs, genes, order_param, odir_param) {
        var args = "";

        args += ageName + "=structs:";
        args += structs.join(",");
        args += ";genes:";
        args += genes.join(",");

        args += "&" + order_param + "=genesymbol"
        args += "&" + odir_param + "=asc"

        return args;
    }
    // ---- end private functions ----

    var age0_Args = "";
    var age3_Args = "";
    var age12_Args = "";
    var age48_Args = "";
    var allArgs = "";

    var genesArray;
    var structsArray;

    // build age 0 months args
    structsArray = age0.getStructs();
    genesArray = age0.getGenes();
    if (structsArray.length > 0 && genesArray.length > 0) {
        age0_Args = buildOneStructureArg("age0", structsArray, genesArray, "age0_order", "age0_odir");
    }

    // build age 3 months args
    structsArray = age3.getStructs();
    genesArray = age3.getGenes();
    if (structsArray.length > 0 && genesArray.length > 0) {
        age3_Args = buildOneStructureArg("age3", structsArray, genesArray, "age3_order", "age3_odir");
    }

    // build age 12 months args
    structsArray = age12.getStructs();
    genesArray = age12.getGenes();
    if (structsArray.length > 0 && genesArray.length > 0) {
        age12_Args = buildOneStructureArg("age12", structsArray, genesArray, "age12_order", "age12_odir");
    }

    // build age 48 months args
    structsArray = age48.getStructs();
    genesArray = age48.getGenes();
    if (structsArray.length > 0 && genesArray.length > 0) {
        age48_Args = buildOneStructureArg("age48", structsArray, genesArray, "age48_order", "age48_odir");
    }

    // append args together
    if (age0_Args != "") allArgs += age0_Args;
    if (age3_Args != "") allArgs += "&" + age3_Args;
    if (age12_Args != "") allArgs += "&" + age12_Args;
    if (age48_Args != "") allArgs += "&" + age48_Args;

    return allArgs;
}

/*
 * Age object
 *
 * Used to represent the Structures and Genes to be searched
 * for each respective structure
 *
 * structsParentId - <div> id of the parent container for the Structures checkboxes
 * genesParentId - <div> id of the parent container for the Genes checkboxes
 */
function ageObj(structsParentId, genesParentId) {
    var structs;  // array
    var genes; // array

    structs = getAllCheckedValues(structsParentId);
    genes = getAllCheckedValues(genesParentId);

    this.getStructs = function() {
        return structs;
    };

    this.getGenes = function() {
        return genes;
    };
}

/* ---------------------------------------------------------------
 *  Create all the accordions for Structure, Age search
 * ---------------------------------------------------------------
 */
function loadAccordions() {
  var topStructureAccordion = new accordion('structure_vertical_container');
  var topAgeAccordion = new accordion('age_vertical_container');

  // nested - nested vertical accordion
  // make sure you have a style defined for each accordion in search.css
  var nestedHippocampus = new accordion('nested_hippocampus', {
      classNames : {
          toggle : 'vertical_accordion_toggle',
          toggleActive : 'vertical_accordion_toggle_active',
          content : 'vertical_accordion_content'
      }
  });

  var nestedAmygdala = new accordion('nested_amygdala', {
      classNames : {
          toggle : 'vertical_accordion_toggle',
          toggleActive : 'vertical_accordion_toggle_active',
          content : 'vertical_accordion_content'
      }
  });
  var nestedVentralStriatum = new accordion('nested_ventralstriatum', {
      classNames : {
          toggle : 'vertical_accordion_toggle',
          toggleActive : 'vertical_accordion_toggle_active',
          content : 'vertical_accordion_content'
      }
  });
  var nestedPrimaryVisualCortex = new accordion('nested_primaryvisualcortex', {
      classNames : {
          toggle : 'vertical_accordion_toggle',
          toggleActive : 'vertical_accordion_toggle_active',
          content : 'vertical_accordion_content'
      }
  });

    var nestedAge0 = new accordion('nested_age0', {
        classNames : {
            toggle : 'vertical_accordion_toggle',
            toggleActive : 'vertical_accordion_toggle_active',
            content : 'vertical_accordion_content'
        }
    });
    var nestedAge3 = new accordion('nested_age3', {
        classNames : {
            toggle : 'vertical_accordion_toggle',
            toggleActive : 'vertical_accordion_toggle_active',
            content : 'vertical_accordion_content'
        }
    });
    var nestedAge12 = new accordion('nested_age12', {
        classNames : {
            toggle : 'vertical_accordion_toggle',
            toggleActive : 'vertical_accordion_toggle_active',
            content : 'vertical_accordion_content'
        }
    });
    var nestedAge48 = new accordion('nested_age48', {
        classNames : {
            toggle : 'vertical_accordion_toggle',
            toggleActive : 'vertical_accordion_toggle_active',
            content : 'vertical_accordion_content'
        }
    });
}

/* -----------------------------------
 * functions to read UI widget values for Substructure search
 * -----------------------------------
 */
  function readMeasureWidget(formId, radioGroupId) {
      var checked = $(formId).getInputs('radio', radioGroupId).find(function(rb) {return rb.checked;});
      return checked.value;
  };

  function readPrimaryStructureWidget(selectId) {
      var value = $(selectId).getValue();

      return value;
  };

  /*
   * primaryStructure - primary structure abbreviation (i.e. VISp, DG, STRv)
   * postfix - "_A" or "_B", identifies substructure search type
   *
   * returns cellId for the substructure, or undefined if substructure not selected.
   */
  function readSubStructureWidget(primaryStructure, postfix) {
    var cellId;

    var table_id = primaryStructure + postfix;
    // to make this function work on both grid and tree tables, it is easier to use the same classname,
    // 'selectedCell' for both types of tables.
    var cells = $(table_id).select('.selectedCell');
    var theCell = cells[0];
    if (theCell !== undefined) {
        cellId = cells[0].readAttribute("cell");
    }

    return cellId;
  };

function readAgeWidget(selectId) {
    var value = $(selectId).getValue();

    return value;
};

function readMagnitudeWidget(lowId, highId) {
    var low = $(lowId).getValue();
    var high = $(highId).getValue();

    var value = low + "," + high;

    return value;
};

function readAgeLogicWidget(formId, radioGroupId) {
      var checked = $(formId).getInputs('radio', radioGroupId).find(function(rb) {return rb.checked;});
      return checked.value;
  };

function readSubstructLogicWidget(formId, radioGroupId) {
      var checked = $(formId).getInputs('radio', radioGroupId).find(function(rb) {return rb.checked;});
      return checked.value;
  };

/* -----------------------------------
 * Utility functions for Substructure search
 * -----------------------------------
 */

/*
 * Update display value for substructure (text that looks like, 'Substructure: CA3, pyram (400480)')
 *
 * description - new substructure descriptive text, usually formatted like 'foo, bar'
 * postfix - chars appended to a CSS id to differentiate it from duplicate ids for parallel HTML layouts
 */
function updateSubstructureDescription(descriptionId, description) {
    var elem = document.getElementById(descriptionId);
    elem.innerHTML = description;
};

/*
 * Update helpful text that tells user how to select a substructure.
 * The text varies depending if the substructure selection widget is a grid table or a tree
 *
 * tableType - "grid" or "tree"
 * textId - tag attribute id of the text object
 */
function updateSubstructSelectText(tableType, textId) {
    if (tableType === "grid") {
        $(textId).innerHTML = "(select a substructure by clicking in a table cell below)";
    }
    else if (tableType === "tree") {
        $(textId).innerHTML = "(click on a substructure name below)";
    }
}
/*
 * For grid tables, gets the row and column names of the clicked cell, which defines the substructure
 * description.
 * For tree tables, gets just the row name of the clicked cell.
 *
 * selectedTable - DOM element of the clicked <table>
 * selectedRow - DOM element of the clicked <tr> cell
 * selectedCell - DOM element of the clicked <td> cell
 * isGrid - true if substructure choices displayed in grid table, false if displayed in a tree table
 *
 * return - formatted string, <row name>, <column name> </br>(<id: >)
 *        - If there is an error, return "none"
 */
function getSubstructureDescription(selectedTable, selectedRow, selectedCell, isGrid) {
    // edge case #1: click on table border will have undefined values
    if (selectedCell === undefined || selectedRow === undefined) {
        return "none";
    }

    // determine x,y coord of clicked cell
    var x = selectedCell.cellIndex;
    var y = selectedRow.rowIndex;

    // find row, column header names
    var columnHeader = selectedTable.rows[0].cells[x];
    var rowHeader = selectedTable.rows[y].cells[0];

    // edge case #2: click on table border yields undefined columnHeader
    if (columnHeader === undefined || rowHeader === undefined) {
        return "none";
    }

    // cell id
    var cellId = selectedCell.readAttribute('cell');

    var substructureDescription;
    if (isGrid === true) {
        // edge case #3: for struct CA, if rowHeader is 'CA4', then don't append the columnHeader
        if (rowHeader.innerHTML === "CA4") {
            substructureDescription = rowHeader.innerHTML + "<br/>(" + cellId + ")";
        }
        else {
            substructureDescription = rowHeader.innerHTML + ", " + columnHeader.innerHTML + "<br/>(" + cellId + ")";
        }
    }
    else {
        substructureDescription =  rowHeader.innerHTML + "<br/>(" + cellId + ")";
    }

    return substructureDescription;
};

/*
 * Finds the new clicked cell, removing highlight from previous cell and adding it to the new cell.
 * Does nothing if the clicked cell is in the row or column headers, or if the cell is disabled.
 * The actual highlighting is done by adding/removing the 'selectedCell' CSS class name.
 *
 * event - original click event on the <td> cell
 *
 * return - DOM element of the <td> cell, or null if the click is on an disabled cell
 */
function selectNewCell(event) {
  // We need to ignore clicks to row, column header cells.
  var isRowHeader;
  var isColHeader;
  var isDisabled;
  var selectedCell = Event.element(event);
  var rowHeaderAttrib = selectedCell.readAttribute("rowheader");
  var colHeaderAttrib = selectedCell.readAttribute("columnheader");
  var isDisabled = selectedCell.hasClassName("disabledCell")
  isRowHeader = (rowHeaderAttrib === "true") ? "true" : "false";
  isColHeader = (colHeaderAttrib === "true") ? "true" : "false";

  if (isRowHeader === "true" || isColHeader === "true" || isDisabled === true) {
      return null;
  }

  // go up from clicked <td> to find the <table> element
  var clickedTable = event.findElement('table');

  // search child nodes of <table> that have class=selectedCell
  var oldselectedCell = clickedTable.select('.selectedCell');
  if (oldselectedCell.length !== 0) {
      // if class found, remove it
      oldselectedCell[0].removeClassName("selectedCell");
  }

  // mark the new clicked cell
  selectedCell.addClassName("selectedCell");

  return selectedCell;
};

  /*
 * Finds the new clicked node, removing highlight from previous node and adding it to the new node.
 * Does nothing if the clicked node is disabled.
 * The actual highlighting is done by adding/removing the 'selectedCell' CSS class name.
 *
 * event - original click event on the <td> node
 *
 * return - DOM element of the <td> node, or null if the click is on an disabled cell
 */
function selectNewNode(event) {
  // We need to ignore clicks to disabled nodes.
  var isDisabled;
  var selectedNode = Event.element(event);
  var isDisabled = selectedNode.hasClassName("disabledTreeCell")
  if (isDisabled === true) {
      return null;
  };

  // go up from clicked <td> to find the <table> element
  var clickedTable = event.findElement('table');

  // search child nodes of <table>, looking for nodes with class=selectedCell
  var oldselectedNode = clickedTable.select('.selectedCell');
  if (oldselectedNode.length !== 0) {
      // if class found, remove it
      oldselectedNode[0].removeClassName("selectedCell");
  }

  // mark the new clicked cell
  selectedNode.addClassName("selectedCell");

  return selectedNode;
};

//------------------------------------------------
//    SubStructure Search - functions called when "Go" button pressed
//------------------------------------------------

function searchBySubstruct2Ages(searchPath, postfix) {
    var measure = this.readMeasureWidget("form_measurement" + postfix, "measurement" + postfix);
    var primaryStructure = readPrimaryStructureWidget("primary_structure" + postfix);
    var subStructure = readSubStructureWidget(primaryStructure, postfix);
    var age1 = this.readAgeWidget("age1" + postfix);
    var age2 = this.readAgeWidget("age2" + postfix);
    var magnitude1 = this.readMagnitudeWidget("magLow1" + postfix, "magHigh1" + postfix);
    var magnitude2 = this.readMagnitudeWidget("magLow2" + postfix, "magHigh2" + postfix);
    var ageLogic = this.readAgeLogicWidget("form_age_logic" + postfix, "ageLogic" + postfix)
    var urlArgs = "";
    urlArgs += "primarystruct=" + primaryStructure;
    urlArgs += "&substruct=" + subStructure;
    urlArgs += "&measure=" + measure;
    urlArgs += "&age1=" + age1;
    urlArgs += "&age2=" + age2;
    urlArgs += "&magnitude1=" + magnitude1;
    urlArgs += "&magnitude2=" + magnitude2;
    urlArgs += "&boolean=" + ageLogic;

    if (subStructure === undefined || subStructure === null) {
        alert("Please select a substructure");
    }
    else {
        clearSearchCookies();

        // redirect to anatomic search url
        window.location = "/" + searchPath + "/twoages.html?" + urlArgs;
    }
};

function searchBy2Substructs(searchPath, postfix) {
    var measure = this.readMeasureWidget("form_measurement" + postfix, "measurement" + postfix);
    var primaryStructure1 = readPrimaryStructureWidget("primary_structure1" + postfix);
    var subStructure1 = readSubStructureWidget(primaryStructure1 + "1", postfix);
    var primaryStructure2 = readPrimaryStructureWidget("primary_structure2" + postfix);
    var subStructure2 = readSubStructureWidget(primaryStructure2 + "2", postfix);
    var age = this.readAgeWidget("age" + postfix);
    var magnitude1 = this.readMagnitudeWidget("magLow1" + postfix, "magHigh1" + postfix);
    var magnitude2 = this.readMagnitudeWidget("magLow2" + postfix, "magHigh2" + postfix);
    var substructLogic = this.readSubstructLogicWidget("form_substruct_logic" + postfix, "substructLogic" + postfix)
    var urlArgs = "";
    urlArgs += "primarystruct1=" + primaryStructure1;
    urlArgs += "&substruct1=" + subStructure1;
    urlArgs += "&primarystruct2=" + primaryStructure2;
    urlArgs += "&substruct2=" + subStructure2;
    urlArgs += "&measure=" + measure;
    urlArgs += "&age=" + age;
    urlArgs += "&magnitude1=" + magnitude1;
    urlArgs += "&magnitude2=" + magnitude2;
    urlArgs += "&boolean=" + substructLogic;

    if (subStructure1 === undefined || subStructure1 === null || subStructure2 === undefined || subStructure2 === null) {
        alert("Please select substructures for both Structure 1 and Structure 2");
    }
    else {
        clearSearchCookies();

        // redirect to anatomic search url
        window.location = "/" + searchPath + "/twosubstructs.html?" + urlArgs;
    }
}