// Printer Yield Search Engine
// Copyright (C) 2007 Hewlett-Packard Company
//

// Note: Much of this file is now duplicated in utilities.js so
//       at the next convenience the duplicated methods should be
//       removed from this file and the containing pages should be
//       tested.

var abbreviations = new Array();
var localizedStrings = new Array();
var ignoreWords = '|hp|printer|series|';
var forceWord = true;
var defaultPageLength = 10;
var pageSearchType = "series";

// Should we display a message for expanded search terms
var showExpandedTerms = false;
var showAbbreviatedTerms = true;

var nonNumericSearchList = new Array();
var numericSearchList = new Array();
var numericSearchParam = "";

var reNumberFromString = new RegExp("[^0-9]*([0-9]+)[^0-9]*");

var SI_COL_NAME    = 0;
var SI_COL_GROUP   = 1;
var SI_COL_COUNTRY = 2;
var SI_COL_LANG    = 3;
var SI_COL_SERIES  = 4;
var SI_COL_TYPE    = 5;
var SI_COL_URL     = 6;

// Check to see if the localized strings have been loaded
if (typeof(localizations) == 'undefined')
  {
    throw "localizations missing";
  }

// Figure out what the current locale is by parsing the URL
// http://h10060.www1.hp.com/pageyield/us/en/results.html
// http://h10060.www1.hp.com/pageyield/us/en/cartResults.html
// http://h10060.www1.hp.com/pageyield/emea_middle_east/en/results.html
var reLocale = new RegExp("^.*/(.+)/(..)/(cartResults|results).html(\\?.*)?$");
var resultArray = reLocale.exec(window.location);

var locale = "us_en";
if (   null != resultArray
    && resultArray.length > 2)
  {
    locale = resultArray[1] + "_" + resultArray[2];
  }

// Now find the proper abbreviations, ignoreWords, localizedStrings, and
// forceWord
abbreviations    = localizations[locale][abbreviationsID   ];
localizedStrings = localizations[locale][localizedStringsID];
ignoreWords      = localizations[locale][ignoreWordsID     ];
forceWord        = localizations[locale][forceWordID       ];

var fuzzySearchList = new Array();

var debug = false;

var wordsIgnored  = new Array();
var wordsExpanded = new Array();

// This method implements replaceable placeholders to come from
// other parameters to the method.  An example string would be "one {0} two {1}"
// which might be used this way:
//
// document.write("one {0} two {1}".format(objectZero, objectOne));
//
String.prototype.format = function()
  {
    var str = this;
    for(var i = 0; i < arguments.length; i++)
      {
        var re = new RegExp('\\{' + (i) + '\\}','gm');
        str = str.replace(re, arguments[i]);
      }

    return str;
  }

// This method removes white space (any ASCII character 32 and lower)
// from the beginning or end of the string.
String.prototype.trim = function()
  {
    var str = this;

    var leftIndex = 0;
    var rightIndex = str.length-1;
    while (str.charCodeAt(leftIndex) <= 32)
      {
        leftIndex++;
      }

    // Short circuit for strings that are all whitespace
    if (leftIndex == rightIndex+1)
      return("");

    while (str.charCodeAt(rightIndex) <= 32)
      {
        rightIndex--;
      }

    return(str.substring(leftIndex, rightIndex+1));
  }

String.prototype.toInt = function()
  {
    var str = this;
    var resultArray = reNumberFromString.exec(str);

    if (null == resultArray)
      return(0);

    return(resultArray[1]);
  }

String.prototype.decode = function()
  {
    var str = this;
    str = unescape(str);
    str = str.replace(/\+/g, " ");

    return(str);
  }

String.prototype.encode = function()
  {
    return(escape(this));
  }

// This method determines if the array already contains the passed
// object.  It returns true if it does and false if it does not.
Array.prototype.contains = function(obj)
  {
    for (var x = 0; x < this.length; x++)
      if (this[x] == obj)
        return(true);

    return(false);
  }

// Take the incoming searchString and parse it into
// an array of clean search terms.  Clean means that
// all of the "ignore words" have been removed and all
// abbreviations have been expanded.  Also, no empty elements
// are allowed in the final list.
//
// Side Effects:
//   This method adds elements to both wordsExpanded and wordsIgnored as
//   it cleans the list so that the program can report on what has
//   occurred if it wants to.
//
// Returns:
//   Array of strings to search for
function getCleanSearchList (searchString)
  {
    // Remove any ignored words
    var searchList = searchString.split(' ');

    // Clean up the search list by removing any undefined and empty
    // elements, removing ignored words, expanding abbreviations.
    var newSearchList = Array();
    for (var x = 0; x < searchList.length; x++)
      {
        var currSrchWrd = searchList[x].toLowerCase();

        // See if it should be ignored
        if (ignoreWords.indexOf("|" + currSrchWrd + "|") > -1)
          {
            wordsIgnored.push(searchList[x]);
            continue;
          }

        if (typeof(abbreviations[currSrchWrd]) != 'undefined')
          {
            wordsExpanded.push(searchList[x]);
            newSearchList.push(abbreviations[currSrchWrd]);
            continue;
          }

        if (currSrchWrd.length > 0)
          newSearchList.push(currSrchWrd);
      }

    return(newSearchList);
  }

function showSpan (spanID)
  {
    var span = document.getElementById(spanID);
    if (null != span)
      span.style.display = 'inline';
  }

function hideSpan (spanID)
  {
    var span = document.getElementById(spanID);
    if (null != span)
      span.style.display = 'none';
  }

function writeSpan (spanID, replacementString)
  {
    var span = document.getElementById(spanID);
    if (null != span)
      span.innerHTML = replacementString;
  }

/*
parseUri JS v0.1, by Steven Levithan (http://badassery.blogspot.com)
Splits any well-formed URI into the following parts (all are optional):
----------------------
• source (since the exec() method returns backreference 0 [i.e., the entire match] as key 0, we might as well use it)
• protocol (scheme)
• authority (includes both the domain and port)
    • domain (part of the authority; can be an IP address)
    • port (part of the authority)
• path (includes both the directory path and filename)
    • directoryPath (part of the path; supports directories with periods, and without a trailing backslash)
    • fileName (part of the path)
• query (does not include the leading question mark)
• anchor (fragment)
*/
function parseUri (sourceUri)
  {
    var uriPartNames = ["source","protocol","authority","domain","port","path","directoryPath","fileName","query","anchor"];
    var uriParts = new RegExp("^(?:([^:/?#.]+):)?(?://)?(([^:/?#]*)(?::(\\d*))?)?((/(?:[^?#](?![^?#/]*\\.[^?#/.]+(?:[\\?#]|$)))*/?)?([^?#/]*))?(?:\\?([^#]*))?(?:#(.*))?").exec(sourceUri);
    var uri = {};

    for(var i = 0; i < 10; i++)
      {
        uri[uriPartNames[i]] = (uriParts[i] ? uriParts[i] : "");
      }

    // Always end directoryPath with a trailing backslash if a path was present in the source URI
    // Note that a trailing backslash is NOT automatically inserted within or appended to the "path" key
    if(uri.directoryPath.length > 0)
      {
        uri.directoryPath = uri.directoryPath.replace(/\/?$/, "/");
      }

    return uri;
  }

function makeUrl (params)
  {
    // First make up a query string using the passed params
    var query = "?";
    for (var key in params)
      {
        var value = null;
        switch (typeof(params[key]))
          {
            case "function": break;
            case "object":   break;
            case "number":
              value = params[key];
              break;
            case "string":
              value = params[key].encode();
              break;
          }

        if (   null != value
            && key != "_")
          {
            if (query.length > 1)
              query += "&";

            query += key;
            query += "=";
            query += value;
          }
      }

    document.write("new query = '" + query + "'<br>");

    return(window.location.pathname + query);
  }

// Parses the passed URL and returns an array
// of the parameters.  For example, if the URL is
// http://test/test?hello=there&you=fool
// then the query string is hello=there&you=fool
// and the resulting array looks like this:
// [0] = "hello=there&you=fool"
// ["hello"] = "there"
// ["you"] = "fool"
//
function parseQueryString (sourceUri)
  {
    var URLParams = parseUri(sourceUri)["query"];

    if (URLParams.length == 0)
      {
        // No search terms
        return([""]);
      }

    // We found something, parse it and add whatever we found to the
    // output array
    var queryArray = new Array();
    queryArray['_'] = URLParams;

    URLParams = "&" + URLParams;

    re = new RegExp("&(([^=]+)=([^&]*))?", "g");
    var resultArray = re.exec(URLParams);

    if (   null == resultArray
        || resultArray.length <= 1
        || typeof(resultArray[1]) == 'undefined'
        || resultArray[1].length == 0)
      {
        // No parseable params found, just return
        // whatever string we did find.
        return(queryArray);
      }

    var lastIndex = 0;
    var error = false;
    while (!error)
      {
        if (resultArray.index != lastIndex)
          {
            // There shouldn't be any unmatched characters between
            // the current match and the last one
            error = true;
            document.write("error 1<br>");
          }
        else
          {
            // if [1] is undefined, that means it was an empty (either a
            // bogus "&" at the end, or "&&", two together.
            if (typeof(resultArray[1]) != 'undefined')
              {
                // We found a param, add it to the array
                queryArray[resultArray[2]] = resultArray[3].decode();
              }
          }

        if (re.lastIndex >= URLParams.length)
          {
            break; // We're done!
          }
        else
          {
            lastIndex = re.lastIndex;
          }

        resultArray = re.exec(URLParams);
        if (resultArray == null)
          {
            error = true;
            document.write("error 2<br>");
          }
      }

    if (debug && error)
      document.write("Error parsing URL!<br>");

    return(queryArray);
  }

function writeLocalizedFormStrings ()
  {
    // Check to see if the localized strings have been loaded
    if (typeof(localizations) == 'undefined')
      {
        throw "localizations missing";
      }

    /* ToDo: Remove this code, no longer necessary.
    writeSpan("searchFormTitle",   localizedStrings["searchFormTitle"]);
    writeSpan("searchAgainPrompt", localizedStrings["searchAgainPrompt"]);
    */
  }

function writeSearchResultsHeader (foundList,
                                   searchList,
                                   wordsIgnored,
                                   wordsExpanded,
                                   listStart,
                                   pageLength)
  {
    writeLocalizedFormStrings();

    writeSpan("searchingWithTerms",
              localizedStrings["searchingWithTerms"].format(searchList.join(", ")));

    if (foundList.length == 1)
      writeSpan("numberOfResultsFound", localizedStrings["OneResultFound"]);
    else
      writeSpan("numberOfResultsFound",
                localizedStrings["numberOfResultsFound"].format(foundList.length));

    if (foundList.length > 0)
      {
        var end = listStart+pageLength-1;
        if (end > foundList.length)
          end = foundList.length;
        writeSpan("displayingResults",
                  localizedStrings["displayingResults"].format(listStart, end));
      }
    else
      writeSpan("displayingResults", "");

    var ignoreAndAbbreviatedSearchTerms = ""
    if (   wordsIgnored.length > 0
        && showAbbreviatedTerms
        && 0 == foundList.length)
      {
        ignoreAndAbbreviatedSearchTerms += localizedStrings["ignoreSearchTerms"]
                                          .format("<i>" + wordsIgnored.join(", ") + "</i>");

        ignoreAndAbbreviatedSearchTerms += "<br/>";
      }

    if (wordsExpanded.length > 0 && showExpandedTerms)
      {
        ignoreAndAbbreviatedSearchTerms += localizedStrings["abbreviatedSearchTerms"]
                                          .format(wordsExpanded.join(", "));

        ignoreAndAbbreviatedSearchTerms += "<br/>";
      }

    if (ignoreAndAbbreviatedSearchTerms.length > 0)
      {
        writeSpan("ignoreAndAbbreviatedSearchTerms", ignoreAndAbbreviatedSearchTerms);

        showSpan("extraInfoBlock");
      }
    else
      {
        hideSpan("extraInfoBlock");
      }
  }

function writeSearchResultsFooter (foundList,
                                   listStart,
                                   pageLength)
  {
    // Turn on next and/or previous buttons if necessary
    if (listStart > 1)
      showSpan("previous");
    else
      hideSpan("previous");

    if (listStart+pageLength-1 < foundList.length)
      showSpan("next");
    else
      hideSpan("next");

    if (foundList.length == 0)
      {
        writeSpan("searchError", localizedStrings["noResultsFound"]);
      }
  }

function writeCartsSearchResults (foundList,
                                  searchList,
                                  wordsIgnored,
                                  wordsExpanded,
                                  params)
  {
    var listStart = 1;
    if (   typeof(params.start) != 'undefined'
        && !isNaN(parseInt(params.start)))
      listStart = parseInt(params.start);

    var pageLength = defaultPageLength;
    if (   typeof(params.n) != 'undefined'
        && !isNaN(parseInt(params.n)))
      pageLength = parseInt(params.n);

    writeSearchResultsHeader(foundList,
                             searchList,
                             wordsIgnored,
                             wordsExpanded,
                             listStart,
                             pageLength);

    var inkHTMLString = "";
    var tonerHTMLString = "";
    var pvpHTMLString = "";

    // Now we can finally display the search results
    for (var x = listStart-1; x < foundList.length; x++)
      {
        var cartHtmlString = "";

        cartHtmlString += "&raquo; <a href='" + foundList[x][SI_COL_URL] + "'>";
        cartHtmlString += foundList[x][SI_COL_NAME];
        cartHtmlString += "</a><br/>";

        if (foundList[x][SI_COL_TYPE] == "InkJet")
          {
            inkHTMLString += cartHtmlString;
          }

        if (   foundList[x][SI_COL_TYPE] == "MonoLaser"
            || foundList[x][SI_COL_TYPE] == "ColorLaser")
          {
            tonerHTMLString += cartHtmlString;
          }

        if (foundList[x][SI_COL_TYPE] == "PVP")
          {
            pvpHTMLString += cartHtmlString;
          }

        if (x-listStart+3 > pageLength)
          break; // Stop processing list.
      }

    var resultHTMLString = "";

    if (inkHTMLString.length > 0)
      {
        resultHTMLString += "<strong>";
        resultHTMLString += localizedStrings["InkCartridges"];
        resultHTMLString += ":</strong>\n";
        resultHTMLString += "<div style='margin-left: 5px; margin-bottom:20px;'>";
        resultHTMLString += inkHTMLString;
        resultHTMLString += "</div>";
        resultHTMLString += "\n";
      }

    if (tonerHTMLString.length > 0)
      {
        resultHTMLString += "<strong>";
        resultHTMLString += localizedStrings["TonerCartridges"];
        resultHTMLString += ":</strong>\n";
        resultHTMLString += "<div style='margin-left: 5px; margin-bottom:20px;'>";
        resultHTMLString += tonerHTMLString;
        resultHTMLString += "</div>";
        resultHTMLString += "<br>\n";
      }

    if (pvpHTMLString.length > 0)
      {
        resultHTMLString += "<strong>";
        resultHTMLString += localizedStrings["PhotoValuePacks"];
        resultHTMLString += ":</strong>\n";
        resultHTMLString += "<div style='margin-left: 5px;'>";
        resultHTMLString += pvpHTMLString;
        resultHTMLString += "</div>";
        resultHTMLString += "\n";
      }

    writeSpan("searchResults", resultHTMLString);

    writeSearchResultsFooter(foundList,
                             listStart,
                             pageLength);
  }


function writeSeriesSearchResults (foundList,
                                   searchList,
                                   wordsIgnored,
                                   wordsExpanded,
                                   params)
  {
    var listStart = 1;
    if (   typeof(params.start) != 'undefined'
        && !isNaN(parseInt(params.start)))
      listStart = parseInt(params.start);

    var pageLength = defaultPageLength;
    if (   typeof(params.n) != 'undefined'
        && !isNaN(parseInt(params.n)))
      pageLength = parseInt(params.n);

    writeSearchResultsHeader(foundList,
                             searchList,
                             wordsIgnored,
                             wordsExpanded,
                             listStart,
                             pageLength);

    var resultHTMLString = "";

    // Now we can finally display the search results
    for (var x = listStart-1; x < foundList.length; x++)
      {
        resultHTMLString += "<li value='" + (x+1) + "'>";
        if (foundList[x][SI_COL_TYPE] == "MonoLaser")
          resultHTMLString += localizedStrings["MonoLaser"];

        if (foundList[x][SI_COL_TYPE] == "ColorLaser")
          resultHTMLString += localizedStrings["ColorLaser"];

        if (foundList[x][SI_COL_TYPE] == "InkJet")
          resultHTMLString += localizedStrings["InkJet"];

        resultHTMLString += " &gt; ";
        resultHTMLString += foundList[x][SI_COL_GROUP];
        resultHTMLString += "<br/>";
        resultHTMLString += "&raquo; <a href='" + foundList[x][SI_COL_URL] + "'>";
        resultHTMLString += foundList[x][SI_COL_NAME];
        resultHTMLString += "</a>";
        resultHTMLString += "</li>";

        if (x-listStart+3 > pageLength)
          break; // Stop processing list.
      }

    writeSpan("searchResults", resultHTMLString);

    writeSearchResultsFooter(foundList,
                             listStart,
                             pageLength);
  }

// This function creates a url that sends the user to the next page. It
// then redirects the user to that URL. This function should not be
// called if there is not another page of results as it does not have a
// way to test that.
function nextPage ()
  {
    var params = parseQueryString(window.location);

    var listStart = 1;
    if (   typeof(params.start) != 'undefined'
        && !isNaN(parseInt(params.start)))
      listStart = parseInt(params.start);

    var pageLength = defaultPageLength;
    if (   typeof(params.n) != 'undefined'
        && !isNaN(parseInt(params.n)))
      pageLength = parseInt(params.n);

    listStart += pageLength;

    params.start = listStart;

    window.location = makeUrl(params);
  }

// This function creates a url that sends the user to the previous page.
// It then redirects the user to that URL. This function will not
// redirect them to a previous page if we are on the first page.
function prevPage ()
  {
    var params = parseQueryString(window.location);

    var listStart = 1;
    if (   typeof(params.start) != 'undefined'
        && !isNaN(parseInt(params.start)))
      listStart = parseInt(params.start);

    if (1 == listStart) // We are already on page one
      return;

    var pageLength = defaultPageLength;
    if (   typeof(params.n) != 'undefined'
        && !isNaN(parseInt(params.n)))
      pageLength = parseInt(params.n);

    listStart -= pageLength;
    if (listStart < 1) listStart = 1;

    params.start = listStart;

    window.location = makeUrl(params);
  }

// This is a utility function used to help sort the search list to get
// the right items to the top. It does this by comparing the series
// number in the search index to the series number that we are searching
// for. The items are sorted in descnding order by the distance between
// the real series number and the one they are searching for (which will
// bring exact matches to the top, and arrange the others in a
// relatively reasonable order).
// a and b are always searchIndex entries.
function bySeriesNumber (a, b)
  {
    var searchNumber = numericSearchList[0];

    // Calculate the absolute distance from each number
    // to the search number.  Sort by that distance.
    var aNumber = Math.abs(a[SI_COL_SERIES].toInt() - searchNumber) + 1;
    var bNumber = Math.abs(b[SI_COL_SERIES].toInt() - searchNumber) + 1;

    if (a[SI_COL_SERIES].toLowerCase() == numericSearchParam)
      aNumber = 0; // Exact match

    if (b[SI_COL_SERIES].toLowerCase() == numericSearchParam)
      bNumber = 0; // Exact match

    return(aNumber - bNumber);
  }

// Find the search results on the page
function showSearchResults ()
  {
    // Check to see if the localized strings have been loaded
    if (typeof(localizations) == 'undefined')
      {
        throw "localizations missing";
      }

    // Parse out the search term
    var params = parseQueryString(window.location);

    if (typeof(params.searchType) == 'undefined')
      {
        if (searchIndex[0][SI_COL_URL].substring(0, 4) == "cart")
          params.searchType = "cartridge";
        else
          params.searchType = "series";
      }

    var searchTermCount = 0;

    // Do we have any parameters at all?
    if (typeof(params.searchString) != 'undefined')
      {
        var searchList = getCleanSearchList(params.searchString.decode());
        searchTermCount = searchList.length;

        // Get the search field from the page and update it
        if (params.searchType == "series")
          {
            var searchField = document.getElementById("searchString");
            searchField.value = searchList.join(" ");
          }
        else
          {
            var searchOtherField = document.getElementById("searchOtherString");
            if (null != searchOtherField)
              searchOtherField.value = searchList.join(" ");
          }

        // Get the page length from the page and updated it
        var pageLength = document.getElementById("pageLength");
        if (   null != pageLength
            && typeof(params.n) != 'undefined'
            && !isNaN(parseInt(params.n)))
          {
            pageLength.value = parseInt(params.n);
          }

        if (debug)
          {
            document.write("searchTermCount = " + searchTermCount + "<br><br>");
          }

        // This is the list of items that the search returned, if any
        var foundList = new Array();
        var finalSearchIndex = new Array();

        // If we ended up with something to search for
        if (searchTermCount > 0)
          {
            if (debug)
              {
                document.write("The search index has " + searchIndex.length + " entries.<br>");
                document.write("The search list has " + searchList.length + " entries.<br><br>");
              }

            fuzzySearchList = buildFuzzySeriesList();

            // Pull out any numeric items for special consideration
            // Then we find all items that match all non-numeric
            // parameters (or all items if there are no non-numeric items).
            // If we find more than one numeric item, then just run the
            // search since they are just being silly.
            re = new RegExp("^[^0-9]*([0-9]+)[^0-9]*$");

            nonNumericSearchList = new Array();
            numericSearchList = new Array();
            for (var x = 0; x < searchList.length; x++)
              {
                resultArray = re.exec(searchList[x]);

                if (null != resultArray)
                  {
                    numericSearchList.push(resultArray[1]);
                    numericSearchParam = searchList[x].toLowerCase();
                  }
                else
                  nonNumericSearchList.push(searchList[x]);
              }

            // Save off the search list, because we might munge it
            // below.
            var savedSearchList = searchList;

            if (numericSearchList.length == 1)
              {
                // Set up the next search block to only search using the
                // non-numeric items from the user's search list.
                searchList = nonNumericSearchList;

                // Peel off the search number
                var searchNumber = numericSearchList[0];

                // Remove the numeric item from the required match count
                // used for non-numeric processing below.
                searchTermCount--;

                // Find all items that match the number REs
                // Then search through that small list for the
                // other search params
                finalSearchIndex = new Array();

                for (var x = 0; x < fuzzySearchList.length; x++)
                  {
                    var nextRE = fuzzySearchList[x][1];
                    var resultArray = nextRE.exec(searchNumber);

                    if (null != resultArray)
                      {
                        if (!finalSearchIndex
                            .contains(searchIndex[fuzzySearchList[x][2]]))
                          finalSearchIndex.push(searchIndex[fuzzySearchList[x][2]]);
                      }
                  }

                finalSearchIndex.sort(bySeriesNumber);
              }
            else
              finalSearchIndex = searchIndex;

            // From here on we are searching through finalSearchIndex
            if (nonNumericSearchList.length > 0)
              {
                // Find items that have all search terms
                var currString = "";
                for (var x = 0; x < finalSearchIndex.length; x++)
                  {
                    var foundCount = 0;
                    if (forceWord)
                      currString = (" " + finalSearchIndex[x][SI_COL_NAME] + " ").toLowerCase();
                    else
                      currString = (finalSearchIndex[x][SI_COL_NAME]).toLowerCase();

                    var rc = 0;
                    for (y = 0; y < searchList.length; y++)
                      {
                        // See if the search word matches the printer "type"
                        if (finalSearchIndex[x][SI_COL_TYPE].toLowerCase()
                               == searchList[y])
                          {
                            // Include this one.
                            foundCount = searchTermCount;
                            break;
                          }

                        if (forceWord)
                          rc = currString.indexOf(" " + searchList[y] + " ");
                        else
                          rc = currString.indexOf(searchList[y]);

                        if (rc > -1)
                          foundCount++;

                        if (debug)
                          {
                            document.write("Searching for '" + " " + searchList[y] + " " + "' in '" + currString + "'.<br>");
                            document.write(currString.indexOf(" " + searchList[y] + " ") + "<br>");
                            document.write("found count = " + foundCount + "<br><br>");
                          }
                      }

                    if (foundCount == searchTermCount)
                      {
                        foundList.push(finalSearchIndex[x]);
                      }
                  }
              }
            else if (numericSearchList.length > 0)
              {
                // The user *only* searched for a number.
                // So we only do the fuzzy search.
                foundList = finalSearchIndex;
              }

            // From this point on we only use foundList.
            if (params.searchType == "series")
              writeSeriesSearchResults(foundList,
                                        savedSearchList,
                                        wordsIgnored,
                                        wordsExpanded,
                                        params);
            else
              writeCartsSearchResults(foundList,
                                      savedSearchList,
                                      wordsIgnored,
                                      wordsExpanded,
                                      params);
          }
        else
          {
            if (params.searchType == "series")
              writeSeriesSearchResults(new Array(),
                                        new Array(),
                                        wordsIgnored,
                                        wordsExpanded,
                                        params);
            else
              writeCartsSearchResults(new Array(),
                                      new Array(),
                                      wordsIgnored,
                                      wordsExpanded,
                                      params);
          }
      }
  }

function doSubmit (theForm)
  {
    var re = new RegExp("([^\\?]+)(\\?.*)?");
    var resultArray = re.exec(window.location);

    var baseURL = resultArray[1];

    // Get the search field from the page
//    var searchField = document.getElementById("searchString");
    var searchString = theForm.searchString.value.trim();

    pageSearchType = theForm.searchType;

    var pageLength = theForm.n; //document.getElementById("pageLength");
    if (null != pageLength)
      {
        if (!isNaN(parseInt(pageLength.value)))
          pageLength = parseInt(pageLength.value);
        else
          pageLength = null;
      }
    else
      {
        pageLength = null;
      }

    if (searchString.length == 0)
      {
        alert(localizedStrings["pleaseTypeBeforeSubmit"]);
        searchField.value = "";
        searchField.focus();
        return(false);
      }

    if (theForm.searchType.value == "series")
      window.location = "results.html?searchString="
                      + escape(theForm.searchString.value.trim())
                      + (null == pageLength ? "" : "&n="+pageLength)
                      + "&searchType=series";
    else
      window.location = "cartResults.html?searchString="
                      + escape(theForm.searchString.value.trim())
                      + (null == pageLength ? "" : "&n="+pageLength)
                      + "&searchType=cartridge";

    return(false);
  }

// This is a simple worker function to isolate adding fuzzy item arrays
// to the passed list.
//
// list must be one of these three
// fuzzyListMostSpecific
// fuzzyListMedium
// fuzzyListBroad
function appendFuzzyItem (prefix, suffix, foundNumber, indexNumber, list)
  {
    var fuzzyExpression = new RegExp("^[^0-9]*((" + prefix + ")" + suffix + ")[^0-9]*$");

    var newFuzzyItem = new Array();
    newFuzzyItem[0] = foundNumber;
    newFuzzyItem[1] = fuzzyExpression;
    newFuzzyItem[2] = indexNumber;

    list.push(newFuzzyItem);
  }

// This method builds the fuzzy search list.  This list is used to provide
// a lookup table of series numbers to allow us to find series based on
// "near" series numbers the user has provided.
function buildFuzzySeriesList ()
  {
    var re2 = new RegExp("^("
                       + "(([0-9][0-9])00)"
                       + "|(([0-9][0-9][1-9])0)"
                       + "|(([0-9][0-9])[0-9][0-9])"
                       + "|(([0-9])00)"
                       + "|(([0-9][1-9])0)"
                       + "|(([0-9])[0-9][0-9])"
                       + "|(([0-9])0)"
                       + "|(([0-9][1-9]))"
                       + "|(([0-9]))"
                       + ")$"
                       );

    var fuzzyList = new Array();

    for (var x = 0; x < searchIndex.length; x++)
      {
        var nextSeriesNumber = searchIndex[x][SI_COL_SERIES];

        // Split up the series lists x/y/z
        var seriesList = nextSeriesNumber.split("/");

        for (var y = 0; y < seriesList.length; y++)
          {
            // Now look at each series number an pull
            // the number part out.
            var resultArray = reNumberFromString.exec(seriesList[y]);

            // Ignore any bogus cartridges that have no numeric part
            if (null == resultArray)
              {
                if (debug)
                  {
                    document.write("Unable to parse index string: " + seriesList[y]);
                    document.write("<br/>");
                  }
                continue;
              }

            var foundNumber = resultArray[1];

            if (debug)
              {
                document.write(searchIndex[x][SI_COL_SERIES] + " == " + foundNumber);
                document.write("<br/>");
              }

            // Now convert the found number into a RE
            resultArray = re2.exec(foundNumber);

            if (debug)
              {
                document.write("     :" + resultArray);
                document.write("<br/>");
              }

            // nn00
            if (   typeof(resultArray[3]) != 'undefined'
                && resultArray[3].length > 0)
              {
                appendFuzzyItem(resultArray[3],
                                "[0-9][0-9]",
                                foundNumber,
                                x,
                                fuzzyList);
              }
            // nnn0
            else if (   typeof(resultArray[5]) != 'undefined'
                     && resultArray[5].length > 0)
              {
                appendFuzzyItem(resultArray[5],
                                "[0-9]",
                                foundNumber,
                                x,
                                fuzzyList);
                appendFuzzyItem(resultArray[5].substring(0,2),
                                "[0-9][0-9]",
                                foundNumber,
                                x,
                                fuzzyList);
              }
            // nnxx
            else if (   typeof(resultArray[7]) != 'undefined'
                     && resultArray[7].length > 0)
              {
                appendFuzzyItem(resultArray[7],
                                "[0-9][0-9]",
                                foundNumber,
                                x,
                                fuzzyList);
              }
            // n00
            else if (   typeof(resultArray[9]) != 'undefined'
                     && resultArray[9].length > 0)
              {
                appendFuzzyItem(resultArray[9],
                                "[0-9][0-9]",
                                foundNumber,
                                x,
                                fuzzyList);
              }
            // nn0
            else if (   typeof(resultArray[11]) != 'undefined'
                     && resultArray[11].length > 0)
              {
                appendFuzzyItem(resultArray[11],
                                "[0-9]",
                                foundNumber,
                                x,
                                fuzzyList);
                appendFuzzyItem(resultArray[11].substring(0,1),
                                "[0-9][0-9]",
                                foundNumber,
                                x,
                                fuzzyList);
              }
            // nnx
            else if (   typeof(resultArray[13]) != 'undefined'
                     && resultArray[13].length > 0)
              {
                appendFuzzyItem(resultArray[13],
                                "[0-9][0-9]",
                                foundNumber,
                                x,
                                fuzzyList);
              }
            // n0
            else if (   typeof(resultArray[15]) != 'undefined'
                     && resultArray[15].length > 0)
              {
                appendFuzzyItem(resultArray[15],
                                "[0-9]",
                                foundNumber,
                                x,
                                fuzzyList);
              }
            // nx
            else if (   typeof(resultArray[17]) != 'undefined'
                     && resultArray[17].length > 0)
              {
                appendFuzzyItem(resultArray[17],
                                "",
                                foundNumber,
                                x,
                                fuzzyList);
              }
            // x
            else if (   typeof(resultArray[19]) != 'undefined'
                     && resultArray[19].length > 0)
              {
                appendFuzzyItem(resultArray[19],
                                "",
                                foundNumber,
                                x,
                                fuzzyList);
              }
          }
      }

    return(fuzzyList);
  }

function doFocus ()
  {
    writeLocalizedFormStrings();

    // Get the search field from the page
    var searchField = document.getElementById("searchString");
    searchField.focus();
  }

