////////////////////////////////////////////////////////////////////
//
//  DEVELOPMENT HISTORY
//
//  Javascript used to validate user input for search
//  criteria.  Action will either be save to local disk
//  or an inventory search request.  The old action and
//  target are saved and restored after finishing the
//  request
//
//  $Id: ValidateSearchCriteria.js,v 1.66 2009/06/11 12:17:24 jmason Exp $
//  $Log: ValidateSearchCriteria.js,v $
//  Revision 1.66  2009/06/11 12:17:24  jmason
//  Enter PR: 3673
//  Removed erroneous code comments.
//
//  Revision 1.65  2009/06/10 19:34:38  jmason
//  Enter PR: 3673
//  Added more date checking to getTemporalInput.
//
//  Revision 1.64  2009/06/02 17:03:01  whawkins
//  Enter PR: 4752
//  Merging the 5.2 branch back to the trunk.
//
//  Revision 1.61.4.6  2009/05/28 12:08:00  jmason
//  Enter PR: 4295
//  Removed extra );
//
//  Revision 1.61.4.5  2009/05/27 12:22:18  jmason
//  Enter PR: 4295
//  Update the message for subscription searches, removing the part of the
//  message alerting the user that he/she will be contacted by someone from
//  CLASS to assist in completing the standing order specification for orders
//  that specify a longitudinal range that exceeds 80 degrees. Return false
//  from the subscription search section to enforce the constraints on
//  bounding boxes for standing orders.
//
//  Revision 1.61.4.4  2009/05/14 19:39:32  whawkins
//  Enter PR: 4752
//  Merged 5.1 PR and 5.1.1 code to the 5.2 branch.
//
//  Revision 1.61.4.3  2009/05/06 18:16:16  jwise
//  Enter PR: 4334
//  Removed code to disallow 0 as a valid cycle
//
//  Revision 1.61.4.2  2009/05/06 17:46:51  jwise
//  Enter PR: 4407
//  Added Max_sum_hits to Order Now message
//
//  Revision 1.61.4.1  2009/03/04 15:27:06  jmason
//  Enter PR: 3673
//  Modified checkDate and GetDay functions to separate functionality and
//  added more error checking. Modified getTemporalInput to call updated
//  checkDate and GetDay functions and added more error checking.
//
//  Revision 1.63  2009/03/04 15:17:33  jmason
//  Enter PR: 3673
//  Recommitting v1.61 to the trunk since v1.62 for CCR 3673 should have
//  been in the 5.2 branch.
//
//  Revision 1.61  2009/01/14 21:23:40  whawkins
//  Enter PR: 3564
//  Updated files per code review comments.
//
//  Revision 1.60  2009/01/13 02:51:35  mhamilto
//  Enter PR: 3897
//  Check both size and hits to determine if no quick search results found.
//
//  Revision 1.59  2009/01/06 22:52:13  whawkins
//  Enter PR: 3564
//  Replaced LiveMap with an Openlayers and geoserver combination.
//  Initial checkin.
//
//  Revision 1.58  2008/07/11 19:16:18  adrew
//  Enter PR: 3468
//  Please use please.
//
//  Revision 1.57  2008/07/03 17:15:41  adrew
//  Enter PR: 3468
//  Changes from code review.  See validation record.
//
//  Revision 1.56  2008/06/26 15:07:16  adrew
//  Enter PR: 3468
//  documentation
//
//  Revision 1.55  2008/06/03 15:57:50  adrew
//  Enter PR: 3468
//  Additions - expand search criteria message for size of zero
//
//  Revision 1.54  2008/06/02 15:58:17  adrew
//  Enter PR: 3468
//  Added validation.
//
//  Revision 1.53  2008/05/30 21:10:10  adrew
//  Enter PR: 3468
//  Use AJAX to submit quick search request.  Allows for processing inv results while
//  on same page.
//
//  Revision 1.52  2008/03/07 15:04:07  kmoore
//  Enter PR: 3504
//  If searching for cycle, make sure date/time fields are blank.
//
//  Revision 1.51  2008/03/04 21:01:26  kmoore
//  Enter PR: 3504
//  If this search is for time type of time_cycle, make sure cycle field is
//  filled in.
//
//  Revision 1.50  2008/01/23 14:44:31  kmoore
//  Enter PR: 3038
//  New function to strip all spaces from a string
//
//  Revision 1.49  2008/01/22 20:16:58  kmoore
//  Enter PR: 3028
//  For subscriptions, call function to validate text input boxes (if any exist)
//  on the search criteria page
//
//  Revision 1.48  2008/01/15 15:33:45  jmason
//  Enter PR: 2098
//  Updated val_ds_name to include validation of beginning
//  orbit number.
//
//  Revision 1.47  2007/12/21 23:35:55  kmoore
//  Enter PR: 3038
//  Validation of key-in text fields for search criteria page.
//
//  Revision 1.46  2007/10/31 17:39:21  kmoore
//  Enter PR: 2951
//  - limit_search check changed from 'true' to 'Y'
//  - change max_lat_val to max_lat_range in order to match database
//  - change max_lon_val to max_lon_range in order to match database
//
//  Revision 1.45  2007/10/23 13:30:10  kmoore
//  Enter PR: 3113
//  Remove "Between" check with time check.
//
//  Revision 1.44  2007/09/26 15:56:41  kmoore
//  Enter PR: 3113
//  Check start_time less than end_time only if start_date and end_date are
//  the same day.  This will allow a time interval that spans midnight.
//
//  Revision 1.43  2007/06/22 19:46:20  wlu
//  Enter PR: 2533
//  using search_opt to find out DSN/GID search
//
//  Revision 1.42  2007/06/19 19:04:36  jmason
//  Enter PR: 2433
//  Added code to open the subscription printer friendly in new window.
//
//  Revision 1.41  2007/06/06 16:48:33  wlu
//  Enter PR: 2533
//  Modified val_ds_name() function to also verify granule id.
//
//  Revision 1.40  2007/01/08 17:31:26  whawkins
//  Enter PR: 2282
//  Remove the javascript that sets all GVAR_IMG satellites when
//  none are selected for subscriptions.  Also remove an unused line
//  from DeliveryCriteria.properties.
//
//  Revision 1.39  2007/01/05 18:52:46  jwise
//  Enter PR: 2366
//  Replaced getspatialinput() flag argument that was inadvertently removed
//
//  Revision 1.38  2006/12/08 17:22:14  jwise
//  Enter PR: 2366
//  Removed code in support of temporary Area of Interest solution for Pre-GVAR
//
//  Revision 1.37  2006/12/04 17:06:40  kmoore
//  Enter PR: 2380
//  Don't allow a blank (or spaces only) subscription name.
//
//  Revision 1.36  2006/09/08 11:23:48  adrew
//  Enter PR: 2430
//  Validate text input in the subscription interface.
//
//  Revision 1.35  2006/08/02 15:08:50  jwise
//  Enter PR: 2397
//  Fixed issue with Area of Interest ordering
//
//  Revision 1.34  2006/08/02 13:25:49  jwise
//  Enter PR: 2397
//  Fixed issue with Area of Interest Search
//
//  Revision 1.33  2006/07/05 16:44:01  jwise
//  Enter PR: 1705
//  Fixed issue with Dataset Name search & Area of Interest
//
//  Revision 1.31  2006/06/21 07:48:54  jwise
//  Enter PR: 1705
//
//  Enabling PRE_GVAR Data
//
//  Revision 1.30  2006/05/10 18:04:22  whawkins
//  Enter PR: 2271
//  Changed "Satellites" to "Satellite" in this file to stop a javascript error.
//
//  Revision 1.29  2005/11/02 16:06:35  kmoore
//  Enter PR: 2026
//  Entered wrong PR number.  Also moved previous comments to where they
//  should have been put.
//
//  Revision 1.28  2005/11/02 16:00:08  kmoore
//  Enter PR: 1756 <- wrong PR#
//  For GVAR_IMG subscription data, SubscriptionBuilder sets specific channels
//  based on the satellite.  It does this without checking to see if any
//  satellite was specified.  Since selecting "no satellites" is the same
//  thing as selecting "all satellites", for GVAR only, set the satellite
//  selection to all if none were selected.
//
//  Revision 1.27  2005/04/10 02:47:34  pschafer
//  Enter PR: 899
//  Disabled point line search for some datatypes.
//
//  Revision 1.26  2004/12/20 17:35:07  kmoore
//  Enter PR: 899
//  Point Search invalid for standard geographic search.
//  Removed ^M from every line.
//
//  Revision 1.25  2004/12/15 19:59:54  gwatson
//  Enter PR: 899
//	Revision 1.25 2004/11/22 gwatson
//	Enter PR: 899 & 1492
//	Enforced a minimum difference between lat & lon pairs
//	in the getSpatialInput function.
//
//  Revision 1.24  2004/10/19 19:10:31  kmoore
//  Enter PR: 1560
//  Remove leading and trailing spaces before performing regular expression validation
//  on dataset name.  Update the input value on the form so that the dataset name
//  passed to inventory server has the spaces stripped.
//
//  Revision 1.23  2004/09/24 19:08:46  kmoore
//  Enter PR: 1532
//  When executing switch_view, make sure datatype_family and search_opt parameters
//  are passed.
//
//  Revision 1.22  2004/08/31 18:07:46  kmoore
//  Enter PR: 1498
//  For the "Switch View" button on the search page, use the current URL,
//  plus "&search_opt=".  This is necessary in order for the login link to work.
//
//  Revision 1.21  2004/08/10 19:52:28  kmoore
//  Enter PR: 726
//  Change of plans.  Do not convert to upper case for inventory server.
//  Inventory server will take care of finding the dataset name regardless
//  of case.
//
//  Revision 1.20  2004/08/10 16:42:30  kmoore
//  Enter PR: 726
//  Do Convert dataset name to upper case for regular expression checking
//  and inventory search, but don't change it on the user's form.
//
//  Revision 1.19  2004/08/09 12:06:48  kmoore
//  Enter PR: 726
//  Change error message.  Convert dataset name to upper case.
//
//  Revision 1.18  2004/06/29 17:56:46  kmoore
//  Enter PR: 1432
//  Correct spelling errors in error message.
//
//  Revision 1.17  2004/02/25 15:54:06  kmoore
//  Enter PR: 726
//  Added functionality to validate dataset names for searching.
//  Use regular expressions.
//
//  Revision 1.16  2003/10/07 21:34:00  kmoore
//  Enter PR: 307
//  Put subscription changes back in that were temporarily removed in
//  version 1.11.
//
//  Revision 1.15  2003/10/07 13:25:40  adrew
//  Enter PR: 985
//  correct spelling and clarify alerts
//
//  Revision 1.14  2003/10/03 20:07:41  adrew
//  Enter PR: 985
//  Provide alternative to java map applet
//
//  Revision 1.13  2003/10/03 19:05:51  kmoore
//  Enter PR: 729
//  Display "searching" message on the search results window while search is
//  taking place.
//
//  Revision 1.12  2003/09/29 19:51:42  pschafer
//  Enter PR: 1085
//  Fixed the line of code that determines if the time span for each day is
//  selected.
//
//  Revision 1.11  2003/09/10 18:49:46  kmoore
//  Enter PR: 1063
//  Temporarily remove changes for subscriptions.
//
//  Revision 1.10  2003/09/08 15:28:21  pschafer
//  Enter PR: 870
//  Fixed the issue with the start time allowed to be greater than the
//  end time for each day.
//
//  Revision 1.9  2003/07/31 17:40:19  wlu
//  Enter PR: 870
//  rewrite function parse_time().
//
//  Revision 1.8  2003/07/09 17:39:01  kmoore
//  Enter PR: 307
//  Add functionality to validate search criteria on subscriptions search page.  Only need to check the longitude.
//
//  Revision 1.7  2003/07/03 13:55:37  pschafer
//  Enter PR: 870
//  Added parsing time function, Wu Lu.
//
//  Revision 1.6  2003/06/30 20:55:49  pschafer
//  Enter PR: 870
//  Added parsing time function, wlu
//
//  Revision 1.5  2003/06/23 20:50:08  adrew
//  Enter PR: 846
//  Validate dates correctly.
//
//  Revision 1.4  2003/06/23 19:00:01  adrew
//  Enter PR:  970
//  Artifact of test environments.  The results named window
//  should be coupled with an envronment identifier.  This will
//  enable testers to have multiple results windows.
//
//  Revision 1.3  2003/01/06 17:51:41  adrew
//  Enter PR: 735
//  Added comments
//
//
//
////////////////////////////////////////////////////////////////////

function SubSubmit(form, action)
{
      // save original - set in HTML
      var oldForm = form.action;
      var oldTarget = form.target;

      form.action = action;

      // Only check the text box when not 'cancel'
      if (action != "subscriptions") {
        var num = form.elements.length;
        for (var i = 0; i < num; i++) {
           // NOTE NOTE NOTE NOTE
           // for now this is the only text field on those
           // pages - I don't want to refer to the widget by
           // name as we have a tendency to change names and then
           // the safety net is gone.
           // KAM:  The field being checked here is the host directory
           //       on the sub delivery page: The text field on the
           //       sub search page is checked via SubValidateSubmit().
           if (form.elements[i].type == 'text' ||
               form.elements[i].type == 'textarea' ) {

             // In case we want to support backslashes
             // var re = new RegExp("[^\\-/a-zA-Z0-9_\\\\]");

             //  Only allow alphanumeric, forward slash, hyphen, underscore
             //  and dot.
             var re = new RegExp("[^\\-/a-zA-Z0-9_.]");
             form.elements[i].value =
                 remove_leading_trailing_spaces(form.elements[i].value);

             var t =  re.test(form.elements[i].value);

             // Complain about all others
             if (t == true) {
                  alert ("Only alphanumeric input accepted.  Please correct '"
                     + form.elements[i].value + "'");
                 return (false);
            }
          }
        }
      }
      // User requested printer friendly page
      if (action == "sub_ascii") {
          var winName = "datawin" + location.hostname.substring(0,location.hostname.indexOf ("."));
          DataWindow = window.open("", winName);
          DataWindow.focus();
          form.target=winName;
      }
      else {
          form.action = action;
      }
    form.submit();

    // restore original values
    form.action = oldForm;
    form.target = oldTarget;
}

function SubValidateSubmit(form, action)
{
      // save original - set in HTML
      var oldForm = form.action;
      var oldTarget = form.target;

      if (getSpatialInput(form,2) == false) {
         return (false);
      }

      //Make sure the user has entered a non-blank subscription name
      //on the subscription search criteria page
      form.subhead_sub_description.value=
         remove_leading_trailing_spaces(form.subhead_sub_description.value);
      if (form.subhead_sub_description.value.length == 0){
         alert("Please enter a Subscription name");
         return (false);
      }

      //Call function to validate text input boxes (if any exist) on search criteria page
      //validate_fields() is found in search.xsl
      var rc=validate_fields();
      if (rc != true) return rc;

      // User requested printer friendly page
      if (action == "sub_ascii") {
          var winName = "datawin" + location.hostname.substring(0,location.hostname.indexOf ("."));
          DataWindow = window.open("", winName);
          DataWindow.focus();
          form.target=winName;
      }

      form.action = action;
      form.submit();

      // restore original values
      form.action = oldForm;
      form.target = oldTarget;
}

function ValidateSubmit(form, action)
{

   // save original - set in HTML
   var oldForm = form.action;
   var oldTarget = form.target;

if (action == "search_dsname" || action == "save_dsname") {
   if (val_ds_name(form) == false) {
      return(false);
   }
   if (action == "save_dsname")
       action="save";
}
else {
   if (getTemporalInput(form) == false) {
      return(false);
   }
   if (getSpatialInput(form,1) == false) {
      return (false);
   }
}

     //Call function to validate text input boxes (if any exist) on search criteria page
     //validate_fields() is found in search.xsl
     var rc=validate_fields();
     if (rc != true) return rc;

   // User requested an inventory search
   if (action == "search" || action == "search_dsname") {
     var winName = "datawin" + location.hostname.substring(0,
          location.hostname.indexOf ("."));
     DataWindow = window.open("", winName);
     DataWindow.document.write("<b>One moment please.  Inventory search in progress...</b>");
     DataWindow.focus();
     form.target=winName;
  }
  else {
  // user requested save to disk of search criteria
  form.action = action;
  }

  form.submit();

  // restore original values
  form.action = oldForm;
  form.target = oldTarget;
}

//----------------------------------------------------------------------------
// getTemporalInput(form)
//----------------------------------------------------------------------------
function getTemporalInput (form) {

   if (form.temporal_search_type) {
      if (form.temporal_search_type.value == "time_cycle") {
         //Want to search by cycle.  Cycle must have a value.
         if (! form.Cycle ) {
            alert ("Internal error - no hidden input named 'Cycle'.");
            return(false);
         }
         form.start_date.value = '';
         form.start_time.value = '';
         form.end_date.value = '';
         form.end_time.value = '';
         return( true);
      }
   }
   // Otherwise assume we're searching by date and time

   if (form.start_date.type == 'hidden') {
      // change this to the format expected
      // in the Java client's XML request
     form.start_date.value = form.start_year.options[form.start_year.selectedIndex].value + '-' + form.start_month.options[form.start_month.selectedIndex].value + '-01';
     form.end_date.value = form.end_year.options[form.end_year.selectedIndex].value + '-' + form.end_month.options[form.end_month.selectedIndex].value + '-28';
   }
   //alert('Dates: ' + form.start_date.value + ", " + form.end_date.value);
   //alert('Range: ' + form.end_date.value - form.start_date.value);
   // now validate all

   if (form.start_date.value == '') {
      if (form.end_date.value == '') {
         alert ("Please enter the temporal criteria (Start Date and End Date)");
         return (false);
      }
      else {
         form.start_date.value = form.end_date.value;
      }
   }
   else {
      if (form.end_date.value == '') {
         form.end_date.value = form.start_date.value;
      }
   }

   //GetDay is going to return number of days since 1970-01-01.
   //Positive number represents days after 1970-01-01.
   //Negative number represents days before 1970-01-01.
   //false means the date failed verification
   var startDay = GetDay(form.start_date.value);
   if (startDay === false) {
      //use === (is exactly equal to (value and type)) to ensure the value is false and not zero
      return false;
   }
   else if (startDay < -24836) {
      //-24837 = 1902/01/01
      alert("The following date is not valid: " + form.start_date.value + ".\nDates before 1902-01-01 are not valid.\n\nPlease enter a valid date.");
      return false;
   }
   else if (startDay > 24856) {
      //24855 = 2038/01/19 Y2K38 (Unix Millennium bug) (03:14:07 UTC)
      alert("The following date is not valid: " + form.start_date.value + ".\nDates after 2038-01-19 are not valid.\n\nPlease enter a valid date.");
      return false;
   }

   var endDay = GetDay(form.end_date.value);
   if (endDay === false) {
      //use === (is exactly equal to (value and type)) to ensure the value is false and not zero
      return false;
   }
   else if (endDay < -24836) {
      //-24837 = 1902/01/01
      alert("The following date is not valid: " + form.end_date.value + ".\nDates before 1902-01-01 are not valid.\n\nPlease enter a valid date.");
      return false;
   }
   else if (endDay > 24856) {
      //24855 = 2038/01/19 Y2K38 (Unix Millennium bug) (03:14:07 UTC)
      alert("The following date is not valid: " + form.end_date.value + ".\nDates after 2038-01-19 are not valid.\n\nPlease enter a valid date.");
      return false;
   }

   if (endDay < startDay) {
      alert("End date is before the start date.");
      return(false);
   }

   var diff = Math.abs(Number(startDay) - Number(endDay));
   if (diff > form.max_days_val.value) {
       alert ('You have indicated a range of ' + diff +
              ' days to search.  The maximum number is ' +
              form.max_days_val.value + '.');
      return(false);
   }

   // time validation
   if ( form.start_time ) {
      if ( ! parse_time(form.start_time, "start") ) return (false);
      if ( ! parse_time(form.end_time, "end") ) return (false);
      if ( (startDay == endDay) ) {
         if (form.start_time.value > form.end_time.value) {
            alert("End time is before the start time on the same day.");
            return (false);
         }
      }

   } // time validation ends

   return (true);
}

//-----------------------------------------------------------------
// parse_time(time_input_control)
//
// Check value of HH, MM, SS. If nothing is input, time will be
// set as "00:00:00". wlu
//------------------------------------------------------------------
function parse_time (start_end_time, timetype) {

   var str_time = start_end_time.value;
   if (str_time == '')  {
      if (timetype == 'start') start_end_time.value = '00:00:00';
      if (timetype == 'end') start_end_time.value = '23:59:59';
      return (true);
   }

   var t;
   if ((t = /^(([01][0-9]|2[0-3]):([0-5]\d):([0-5]\d))$/.test(str_time)) == true)
   {
      return (true);
   } else {
      alert('Please enter a valid ' + timetype + ' time using the format HH:MM:SS .');
      return (false);
   }
}

//----------------------------------------------------------------------------
//checkDate (strDate)
//strDate: string representing a date in the format: YYYY-MM-DD
//Determines whether a string representing a date is in one of the following
//formats: YYYY-MM-DD
//----------------------------------------------------------------------------
function checkDate (strDate) {
    //Regular expression for YYYY-MM-DD
    if ((d = /^(\d\d\d\d)([-])(\d\d)(\2)(\d\d)$/.exec(strDate)) != null) {
        var bValid = false;
        with (new Date(d[1], d[3]-1, d[5])) {
            bValid = ((getDate()==d[5]) && (getFullYear()==d[1]) && (getMonth()==(d[3]-1)));
        }
        if (bValid) {
            return true;
        }
        else {
            alert("The following date is not valid: " + d[0] + ".\n\nPlease enter a valid date.");
            return false;
        }
    }
    else {
        alert("The following date is not valid: " + strDate + ".\n\nPlease enter the date in the following format: \nYYYY-MM-DD");
        return false;
    }
} //checkDate

//----------------------------------------------------------------------------
//GetDay (strDate)
//strDate: string representing a date in the format: YYYY-MM-DD
//Calculates the number of days since 1970-01-01 by calculating the number
//of milliseconds from Jan 1, 1970 and dividing by 86400000 (number  of
//milliseconds in a day).
//Positive values are after 1970; negative values are before 1970.
//----------------------------------------------------------------------------
function GetDay (strDate) {
    if (checkDate (strDate))  {
        //tokenize the date string using - (regular expression) as the delimiter
        var d = strDate.split (/[-]/);
        var DateObj = new Date (d[0], d[1]-1, d[2]);
        //return number of days since 1970-01-01
        //equals number of milliseconds since 1970-01-01 / milliseconds in a day
        //86400000 = number milliseconds in a day
        return (Math.ceil (DateObj.getTime()/86400000));
    }
    else {
        return false;
    }
} //GetDay

//----------------------------------------------------------------------------
// getSpatialInput(form)
// flag=1 -> online search
// flag=2 -> subscription search)
//----------------------------------------------------------------------------
function getSpatialInput (form, flag) {
   //alert(form.limit_search.value);
      //Check to see if boundary checks are required
      if (form.limit_search.value.toUpperCase() == 'Y') {
         //Check to see if this is a global search
         if (form.nlat.value ==  90 && form.slat.value ==  -90 &&
             form.elon.value == 180 && form.wlon.value == -180) {
             return (true);
         }
         else {
           if (flag == 1) {
            //Check the allowable spatial range
            var lat_range = Math.abs(form.nlat.value - form.slat.value);
            if (lat_range > form.max_lat_range.value) {
                alert ('You have indicated a latitude range of ' + lat_range +
                    ' degrees to search.  The maximum number is ' +
                    form.max_lat_range.value + ', unless you wish to perform a global search, in which case the coordinates may be 90, -90, -180, 180.');
             return(false);
            }

            var wlon = parseFloat(form.wlon.value);
            var elon = parseFloat(form.elon.value);
            if (wlon > elon)
                wlon = wlon - 360;
            var lon_range = Math.abs(wlon - elon);
            if (lon_range > form.max_lon_range.value) {
               alert ('You have indicated a longitude range of ' + lon_range +
                    ' degrees to search.  The maximum number is ' +
                    form.max_lon_range.value + ', unless you wish to perform a global search, in which case the coordinates may be 90, -90, -180, 180.');
               return(false);
            }
           } // flag==1, online search
           else {
               // Subscription search.  Only check longitude.
               // Give warning, but allow it if they want it.
               // As of v5.2 (CCR 4295), do NOT allow...must enforce the 
               // constraints on bounding boxes for standing orders.

               var wlon = parseFloat(form.wlon.value);
               var elon = parseFloat(form.elon.value);
               if (wlon > elon)
                   wlon = wlon - 360;
               var lon_range = Math.abs(wlon - elon);
               if (lon_range > 80) {
                  alert (
                     'You have indicated a longitude range of ' + lon_range +
                     ' degrees for your subscription.  ' +
                     'The maximum number of degrees that can be used for ' +
                     'an automatically generated subscription is 80, ' +
                     'unless you wish to perform a global search, ' +
                     'in which case the coordinates may be ' +
                     '-90, 90, -180, 180.');
                  return(false);
               }
           } // flag==2, subscription search
         }
      } //Boundary check

        // The minimum lat/lon difference is enforced if applicable.
	// For data families which have a value of minDiff, they do not support point/line search
        // and require mininum lat/lon difference.
        // For data families which have no value of minDiff or value of 0.0, point/line search is
        // allowed.
        if ((form.minDiff != null) && (form.minDiff.value > 0)) {
        var minDiff = form.minDiff.value;

	// Variables for min-width check
	var nlat = form.nlat.value;
	var slat = form.slat.value;
	var elon = form.elon.value;
	var wlon = form.wlon.value;

	//Parse intputs into floats
	nlat = parseFloat(nlat);
	slat = parseFloat(slat);
	elon = parseFloat(elon);
	wlon = parseFloat(wlon);

	// Calculate the difference of the form values
        // If elon == wlon, it's a global search.
        // If elon < wlon, it searches on 360-(wlon-elon)=elon+360-wlon.
	var latDiff = Math.abs(nlat - slat);
	var lonDiff = (elon < wlon) ? elon + 360 - wlon: (elon - wlon);

	// If the latitude difference is less than the minimum, spread it:
	if (latDiff < minDiff) {
		latDiff = (minDiff - latDiff)/2;  //Find the difference between actual and optimal differences
		nlat += latDiff;  // Add half the difference to the upper bound
		slat = slat - latDiff;  // Subract half the difference from the lower bound
	   	// make sure that the new values don't exceed their limits
		if (nlat > 90) {
			slat = slat - latDiff;
			nlat = 90;
		}

		if (slat < -90) {
			nlat += latDiff;
			slat = -90;
		}

		//pass the values to the rounding function to round to 2 significant digits
		nlat = RoundAccuracy(nlat, 2);
		slat = RoundAccuracy(slat, 2);
	   	// assign the new values to the form fields
		form.nlat.value = nlat;
    	        form.slat.value = slat;
	}

	// If the longitude difference is less than the minimum, spread it:
	if (lonDiff < minDiff) {
		lonDiff = (minDiff - lonDiff)/2;  // Find the difference between actual and optimal differences
		elon += lonDiff;  // Add half the difference to the upper bound
		wlon = wlon - lonDiff;  // Subract half the difference from the lower bound

		if (wlon < -180) {
			elon += lonDiff;
			wlon = -180;
		}

		//pass the values to the rounding function to round to 2 significant digits
		elon = RoundAccuracy(elon, 2);
		wlon = RoundAccuracy(wlon, 2);
		// assign the new values to the form fields
		form.elon.value = elon;
	        form.wlon.value = wlon;
	}
	}// The minimum lat/lon difference is enforced if applicable

   return (true);
}

/********************************************
RoundAccuracy() rounds a value to a certain number of significant digits.
RoundAccuracy accepts two parameters (num & acc).
num is the value to be rounded
acc is the accuracy (# of significant digits) to round to
********************************************/
function RoundAccuracy(num, acc){
    var factor = Math.pow(10, acc);
    return Math.round(num*factor)/factor;
}

//----------------------------------------------------------------------------
// val_ds_name: test dataset name/granule id/beginning orbit number value
// matching required pattern
// form - form object
//----------------------------------------------------------------------------
function val_ds_name(form) {

   var dsn_gid_orb = form.search_opt.value;
   var txtinput;
   var pattern;
   var target = "";

    if ((dsn_gid_orb != null) && (dsn_gid_orb == 'GID')) {
        txtinput = form.granule_id;
        pattern = form.gid_pattern;
        target = "granule id";
    }
    else if ((dsn_gid_orb != null) && (dsn_gid_orb == 'ORB')) {
        txtinput = form.orbit_number;
        pattern = form.orb_pattern;
        target = "beginning orbit number";
    }
    else {
        txtinput = form.dataset_name;
        pattern = form.dsname_pattern;
        target = "dataset name";
    }

   if (txtinput.value.length == 0) {
      alert ("Please enter the " + target + " you wish to search for");
      return false;
   }

   //Check dataset name or granule id against regular expression

   if (getSpatialInput(form,1) == false) {
      return (false);
   }
   if (pattern == null || pattern.value.length == 0) {
      // No pattern, therefore no checking
      alert("No pattern to check against");

      return true;
   }
   txtinput.value = remove_leading_trailing_spaces(txtinput.value);

   var regex = pattern.value;
   var testx = txtinput.value.toUpperCase();
   var reg = new RegExp(regex);

   if (reg.test(testx))
      return true;
   else {
      alert("Please enter the " + target +" using the format shown below the entry box.");
      return false;
   }
}

//----------------------------------------------------------------------------
// remove_leading_trailing_spaces
//    myString - input string that must be stripped of leading and trailing spaces
//----------------------------------------------------------------------------
function remove_leading_trailing_spaces(myString) {
   var tmp = "";
   var i=0;
   var end=myString.length-1;

   //Look for trailing spaces
   while (end >= 0 && myString.charAt(end) == ' ') {
      --end;
   }

   //Skip leading spaces
   while (i <= end && myString.charAt(i) == ' ') {
      ++i;
   }

   //Copy after leading spaces
   while (i <= end) {
      tmp += myString.charAt(i);
      ++i;
   }

   return(tmp);
}

//----------------------------------------------------------------------------
// strip_spaces
//    myString - input string that must be stripped of all spaces
//----------------------------------------------------------------------------
function strip_spaces(myString) {
   var tmp = "";
   var i=0;
   var end=myString.length-1;

   //Copy string, leaving out spaces
   while (i <= end) {
      if (myString.charAt(i) != ' ')
          tmp += myString.charAt(i);
      ++i;
   }

   return(tmp);
}

//----------------------------------------------------------------------------
// val_text:  validate text input on search criteria page
//
//   user_input: text that was entered into the text box
//   type:       type of text validation to perform
//   params:     parameters to use in the validation, delimited by '=':
//                 regularExpress
//                 regularExpress=minValue
//                 regularExpress=minValue=maxValue
//   name:       name of the text box to use for error response to user
//----------------------------------------------------------------------------
function  val_text(user_input, type, params, name) {
   var rc=1;

   //alert (  "val_text("+user_input+","+type+","+params+","+name+")"  );
   if (type=='numrange') {
      param_list = params.split("=");
      var reg = new RegExp(param_list[0]);
      var min,max;
      var i,j;

      if (param_list.length > 1) {
         min=Number(param_list[1]);
         if (param_list.length > 2) {
            max=Number(param_list[2]);
         }
      }

      //Check user input against regular expression
      rc = reg.test(user_input);
      if (!rc) {
         var msg = name + ":  Positive numbers or number ranges only, such as '1,5,10-20,100,110-120'.";
         if (param_list.length > 2)
              msg += "  \nNumber range = " + min + "-" + max + ".";
         else if (param_list.length > 1)
               msg += "  Minumum number = " + min + ".";
         alert(msg);
         return rc;
      }
      // if we have min/max values to test, test them
      if (param_list.length > 1) {
         parsed_commas = user_input.split(",");
         for (i=0; i < parsed_commas.length; i++){
            parsed_dashes = parsed_commas[i].split("-");
            for (j=0; j < parsed_dashes.length; j++) {
               if (parsed_dashes[j].length > 0) {
                  if (parsed_dashes[j] < min || parsed_dashes[j] > max) {
                     alert (name + ":  Minimum value is " + min + ",  maximum value is " + max);
                     return 0;
                  }
               }
            }
         }
      }
   }
   else {
      var reg = new RegExp(params);
      rc = reg.test(user_input);
      if (!rc) {
         alert(name + " failed validation");
      }
   }
   return rc;
}



//----------------------------------------------------------------------------
// switch_view
//    form - form object
//    view - view to switch to (SC or DSN)
//----------------------------------------------------------------------------
function switch_view(form,view) {
   /* This is the cleaner, form posting method that we'd
      like to get back to.

      The problem occurs when you do a switch_view, then click on login.
      Login simply switches nsaa to saa in the URL, then there is no
      datatype family or search_opt parameters, and search doesn't have
      data it needs to populate the form.

   form.search_opt.value=view;
   form.action="search";
   form.submit();
   */

   var url = location.href;
   var newURL;
   var qm  = url.indexOf("?");
   var df_str;

   // If there are no parameters, append the necessities
   if (qm < 0) {
      newURL = url + "?"
                   + "datatype_family=" + form.datatype_family.value
                   + "&search_opt="     + view;
   }
   else {
      // Still need to check for datatype_family
      var df  = url.indexOf("datatype_family");
      if (df < 0)
         df_str  = "&datatype_family=" + form.datatype_family.value;
      else
         df_str  = "";

      // If there is already a search_opt parameter, replace it
      var opt = url.indexOf("&search_opt");
      if (opt < 0)
         newURL = url + df_str + "&search_opt=" + view;
      else
         newURL = url.substring(0,opt) + df_str + "&search_opt=" + view;
   }

   window.location.href = newURL;
}


//----------------------------------------------------------------------------
//   Use AJAX to support the Quick Search /Order Now functionality.
//----------------------------------------------------------------------------

var xmlHttp = null;

//----------------------------------------------------------------------------
//   quickSearch - run when user clicks the order now button a search page
//
//----------------------------------------------------------------------------
function quickSearch(form, action) {

  // AJAX access
  try  {
     xmlHttp=new XMLHttpRequest();
  } catch (exp) {
      try {
           xmlHttp=new ActiveXObject("Microsoft.XMLHTTP");
      } catch (exp) {
           alert ("The Order Now function requires XMLHTTP.  Your browser does not support it.");
           return;
      }
  }

  // set call to process the output
  xmlHttp.onreadystatechange=processResults;

  // going to post to orderNow - see sitemap for processing details
  xmlHttp.open ("POST", "../prod/orderNow", true);
  xmlHttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');

  if (action == "search_dsname") {
    if (val_ds_name(form) == false) {
      return(false);
    }
  } else {

     // validate temporal criteria
     if (getTemporalInput(form) == false) {
         return(false);
     }

     // Validate spatial criteria
     // NOTE: this must be called prior to translating the form input
     // as in addition to validating it gets input from the applet.
     if (getSpatialInput(form,1) == false) {
        return (false);
      }
  }

  //Call function to validate text input boxes (if any exist) on search criteria page
  //validate_fields() is found in search.xsl
  var rc=validate_fields();
    if (rc != true) return rc;

  // need to translate the form data
  var formData = getFormData (form);

  // post the orderNow
  xmlHttp.send(formData);

  // busy hour glass for the pointer
  document.body.style.cursor = "wait";
}

//----------------------------------------------------------------------------
//   getFormData - takes all the form data from the search page and
//     translates to forward on to orderNow  (see sitemap for pipeline processing)
//----------------------------------------------------------------------------
function getFormData (form) {

  // query string - all translated
  var qs="";
  var node = "null";
  var nodeRef = "";

  // go through all form input
  for (var e=0; e<form.elements.length; e++) {

     node = form.elements[e];

     // ensure a reference to the node.
     nodeRef = node.name;
     if (nodeRef == null) nodeRef = node.id;

     var tag_name = node.tagName.toLowerCase();

     if (tag_name == "input") {
        if (node.type.toLowerCase() == "radio" || node.type.toLowerCase() == "checkbox") {
            if (node.checked) {
                   // add only the choosen ones
                qs+=nodeRef+"="+escape(node.value)+"&";
            }
        } else {  // this would be text, hidden, password
           qs+=nodeRef+"="+encodeURIComponent(node.value)+"&";
        }
     }

     else if (tag_name == "select") {
        var option = null;
        for (var o = 0; o < node.options.length; o++) {
            option = node.options[o];
            if (option.selected) {
                qs+=nodeRef+"="+escape(option.value)+"&";
            }
        }
     }

     else if (tag_name == "textarea") {
        qs+=nodeRef+"="+encodeURIComponent(node.value)+"&";
     }
  }
  return (qs);
}


//----------------------------------------------------------------------------
//   processResults - handles output from the orderNow processing
//          (see sitemap for pipeline processing)
//----------------------------------------------------------------------------
function processResults() {

  //  reset the pointer
  document.body.style.cursor = "default";
  if (xmlHttp.readyState != 4) return;
  if (xmlHttp.status != 200)
  {
     alert("Problem retrieving results.");
     return;
  }
  var results = xmlHttp.responseXML.documentElement;

  //  get message from Inventory server - must be a problem.
  try {
    var message =  results.getElementsByTagName("message")[0].firstChild.data;
    alert (message);
    return;
  } catch (e) {
       // no error message from the server
       var hits =  results.getElementsByTagName("hits")[0].firstChild.data;
       var total =  results.getElementsByTagName("total")[0].firstChild.data;
       var max = results.getElementsByTagName("max")[0].firstChild.data;
       try {
           var size =  results.getElementsByTagName("size")[0].firstChild.data;
           if ( (size == 0) && (hits == 0) ) {
               alert ("No results found.  Expand your search criteria.");
               return;
           }
           window.location.href = "shopping_cart";
       } catch (e) {
           if (hits > 0) 
              alert ("You cannot order " + hits + 
                     " datasets at once. The maximum number allowed for this type of data is " + max + ". Please narrow the search criteria." );
           else 
               alert("Problem retrieving results.");
           return;
       }
  }
}
