#!/usr/bin/perl -w
# 2013 public domain Wesley Ebisuzaki
#
# main guts for g2subset
#  this version has support for wgrib 1.9.4
#    subsetting by region, point and regridding
#
sub g2sub_main {

#(local definitions)-----------------------------------------
open (LOAD, "< /proc/loadavg");
$loadavg=<LOAD>;
close(LOAD);
$loadavg =~ s/ .*$//;
if ($loadavg > 19) {
   print "Status: 503 server is busy\n";
   print "Content-TYPE: text/html\n\n";
   print "<head> <title>Error</title></head>\n";
   print "<h2 align=\"center\">Error</h2>\n";
   print "<p align=\"center\"> Sorry, machine is overloaded ($loadavg), please come back later.<br>\n";
   print "</body>\n";
   exit 0;
}

#(webserver definitions)-------------------------------------
$wgrib2="/home/wd23ja/bin/wgrib2.1.9.4b2";
$logfile="/home/wd23ja/logs/g2subset.log";
$ENV{'PATH'} = "/bin:/usr/bin:/home/wd23ja/bin";
$ENV{IFS} = '';

#(code)-----------------------------------------------------

$dir=$_[0];
$version="1.3.6.development";
$script_name=$0;
$script_name =~ s/.*\///;
$script_url = "$ENV{'SERVER_NAME'}$ENV{'SCRIPT_NAME'}";

$pid = getppid;
$query=$ENV{'QUERY_STRING'};
if (defined($ENV{'REMOTE_HOST'})) {
    $REMOTE_HOST=$ENV{'REMOTE_HOST'};
} else {
    $REMOTE_HOST=$ENV{'REMOTE_ADDR'};
}

# auto-flush stdout

$old_handle = select (STDOUT);
$| = 1; # perform flush after each write to STDOUT
select ($old_handle); 

if (! -x $wgrib2) { &error_page("Missing wgrib2 ",'Network Problem #2'); exit 0;}

&read_g2subrc("$dir");

@q = split('&', $query, 10000);
$qn{'file'} = '';
$qn{'dir'} = '';

foreach $_ (@q) {
   if ($_ ne '') {
      ($name,$value) = split('=', $_, 2);
      if (!defined($value)) { $value=''; }
      $qn{$name} = $value;
      # remove any funny characters: ? " ' * /
      $value =~ s/[?"'*\/]//g;
      $safeqn{$name} = $value;
   }
}

# file name: a-z A-Z 0-1 . _ +
if (defined($qn{'file'})) { $qn{'file'} =~ s/[^-a-zA-Z0-9._+]//g; }

# make sure subdirectory parameter is ok: a-z A-Z 0-9 ._ + .
$subdir='';
if (defined $qn{'dir'}) { 
    $subdir = $qn{'dir'};
}
if ($subdir ne '') {
    $subdir =~ s/%2[fF]/\//g;
    $subdir =~ s/[^-a-zA-Z0-9\/+_.]//g;
    $subdir =~ s/\/\.\.*/\//g;
    if (substr($subdir,0,1) ne '/') { &error_page("illegal directory: $subdir"); exit 7; }
    $_=$dir;
    foreach $t (@dirs) {
       $_="$_/$t";
       if (! -d $_ || ! -x $_ || ! -r $_) {
           &error_page("illegal directory: $subdir");
           exit 6;
       }
    }
}
$url_subdir=$subdir;
$url_subdir =~ s/\//%2F/g;

# read local configuration file
&read_g2subrc("$dir/$subdir");

# in case not defined in local definition section

if (!defined($ncol)) { $ncol=4; }
if (!defined($forecast)) { $forecast=''; }
if (!defined($months)) { $months=''; }
if (!defined($days)) { $days=''; }
if (!defined($hours)) { $hours=''; }
if (!defined($gribfilter)) { $gribfilter=''; }
if (!defined($nosubregion)) { $nosubregion=''; }
if (!defined($nopoints)) { $nopoints=''; }
if (!defined($noregrid)) { $noregrid=''; }
if (!defined($var)) { $var = ''; }
if (!defined($lev)) { $lev = ''; }
if (!defined($REMOTE_HOST)) { $REMOTE_HOST='none'; }

$wgrib_flag = '';
$date_code='d=';
if (defined($forecast) && $forecast ne '') {
   $wgrib_flag = '-verf';
   $date_code='vt=';
}

if ($qn{'file'} eq '') {
   &page1;
}
else {
   &page2
}
exit 0;

# ------------- page 1 -----------------


sub page1 {


if (! -d "$dir$subdir" ) {
    &error_page('Network',"Problem: $subdir");
    exit 5;
}

&page1_html_start($title);

if ($subdir ne '') {
   $_=$subdir;
   chomp;
   print "<font color=red>Directory:&nbsp&nbsp&nbsp;</font>$subdir<br>";
}

open (DIRS, "cd $dir$subdir ; find . -type d -name '[a-zA-Z0-9]*' -maxdepth 1 -perm +5 -print | sort -n |");

$dir_count=0;
while (<DIRS>) {
    chomp;
    if ($dir_count++ == 0) {
        $col = int(60 / length($_));
	if ($col eq 0) { $col=1; }
	print "<br>\n<font color=red>Subdirectory</font>\n<p><table border=0><tr>\n";
    }
    $_ =~ s/^\.\///;
    print "<td>&nbsp&nbsp&nbsp;<a href=\"http://$script_url?dir=$url_subdir%2F$_\">$_</a>";
#    if (-r "$dir$subdir/$_/.info") {
#	open(TMP,"< $dir$subdir/$_/.info");
#        $_ = <TMP>;
#	print "<td>&nbsp;&nbsp;&nbsp; $_";
#	close(TMP);
#    }
    print "</td>\n";
    if ($dir_count % $col eq 0) { print "</tr><tr>\n"; }
}
    print "</tr><tr>";
close(DIRS);
if ($dir_count > 0) { print "</table>"; }

if (defined($files_pat)) {
   open (Files, "cd $dir$subdir ; find . -type f -maxdepth 1 -perm +4 -name '[a-zA-Z0-9]*' -print | egrep \''$files_pat'\' | egrep -v '\.(inv|inv-verf)\$' | sort -n |");
}
else {
   open (Files, "cd $dir$subdir ; find . -type f -name '[a-zA-Z0-9]*' -maxdepth 1 -perm +4 -print | egrep -v '\.(inv|inv-verf)\$' | sort -n |");
}

$file_count=0;
$col=1;

# make file listing

print "\n<form action=\"http://$script_url\" method=\"get\">\n";

while (<Files>) {
   chomp;
   $_ =~ s/^\.\///;
   $file=$_;
   if ($file_count == 0) {
      print "<p><font color=red>\n"; print "Select a file (size in bytes)";
      print "</font><p>\n";
      print "<select name=\"file\">\n";
   }
   $size = -s "$dir$subdir/$file";
   print "<option value=\"$file\">$file ($size)</option>\n";

   $file_count++;
}
if ($file_count != 0) {
   print "</select>\n";
}

close(Files);

if ($file_count == 0 && $dir_count == 0) {
   print "</form>&nbsp<br>&nbsp<br>&nbsp<br>";
   print "<font color=red>No files or directories found</font><br>";
   &credits;
   exit 0;
}

if ($file_count == 0) {
   print "</form><br><font color=red>Select subdirectory from above list.</font>";
   print "<small> <p align=left>";
   &credits;
   exit 0;
}

if ($gribfilter ne '') {
   print "<hr>";
   print "<p><font color=brown>Step 2 (optional). Select levels/fields/times in the subset.</font><br>";
   print "<h1 align=center> <font color=red>Levels/Variables/Time</font></h1>\n";
   print "<p>Many times you may only want a section of a huge data\n";
   print "file. Rather than transferring the entire file, this section will\n";
   print "allow you to select some or all of the levels, variables, and \n";
   print "dates of a GRIB2 file. The available selections will depend on the configuration.\n";

   if ($levs ne "") {
      @_ = split(' ', $levs, 1000);
      print "<p><font color=red>Select the levels desired:<br>";
      print "</font>\n";
      print "<input type=\"checkbox\" name=\"all_lev\"> all\n";
      print "&nbsp;&nbsp; ";
      foreach $_ (@_) {
         $tmp = $_;
         $tmp =~ s/_/&nbsp;/g;
         print "<input type=\"checkbox\" name=\"lev_$_\">&nbsp;$tmp";
         print "&nbsp;&nbsp; ";
      }
   }

   if ($vars ne "") {
      @_ = split(' ', $vars, 1000);
      print "<p><font color=red>\n";
      print "Select the variables desired:<br>";
      print "</font>\n";
      print "<input type=\"checkbox\" name=\"all_var\"> all\n";
      print "&nbsp;&nbsp; "; 
      foreach $_ (@_) {
         $_ =~ s/_/&nbsp;/g;
         print "<input type=\"checkbox\" name=\"var_$_\">&nbsp;$_";
         print "&nbsp;&nbsp; ";
      }
   }
   if ($forecast ne "" && ($months ne "" || $days ne "" || $hours ne "")) {
       print "&nbsp;&nbsp;<br> <font color=red>\n";
       print "<br>Using forecast verification time<br>\n";
       print "</font>\n";
   }

   if ($months ne '') {
       print "<font color=red>\n";
       print "<p>Select the months desired:<br>\n";
       print "</font>\n";
       print "<input type=\"checkbox\" name=all_mon>all\n";
       print "<input type=\"checkbox\" name=mon_01>jan\n";
       print "<input type=\"checkbox\" name=mon_02>feb\n";
       print "<input type=\"checkbox\" name=mon_03>mar\n";
       print "<input type=\"checkbox\" name=mon_04>apr\n";
       print "<input type=\"checkbox\" name=mon_05>may\n";
       print "<input type=\"checkbox\" name=mon_06>jun\n";
       print "<input type=\"checkbox\" name=mon_07>jul\n";
       print "<input type=\"checkbox\" name=mon_08>aug\n";
       print "<input type=\"checkbox\" name=mon_09>sep\n";
       print "<input type=\"checkbox\" name=mon_10>oct\n";
       print "<input type=\"checkbox\" name=mon_11>nov\n";
       print "<input type=\"checkbox\" name=mon_12>dec\n";
   }
   if ($days ne '') {
      print "<p><font color=red>Select the days of month desired:<br></font>\n";
      print "<input type=\"checkbox\" name=all_day>all\n";
      for ($i = 0; $i <= 31; $i++) {
         $_ = $i;
         if ($i <= 9) { $_ = "0$i"; }
         print "<input type=\"checkbox\" name=day_$_>$i \n";
      }
   }

   if ($hours ne '') {
      @_ = split(' ', $hours, 1000);
      print "<p><font color=red>Select the hours desired:<br>";
      print "</font>\n";
      print "<input type=\"checkbox\" name=all_hor> all\n";
      print "&nbsp;&nbsp; ";
      foreach $_ (@_) {
         $_ =~ s/_/&nbsp;/g;
         print "<input type=\"checkbox\" name=hor_$_>&nbsp;$_";
         print "&nbsp;&nbsp; ";
      }
   }
}

   if ($gribfilter ne '' && ($nosubregion eq '' ||  $nopoints eq '' || $noregrid eq '')) {

      print "<hr><p><font color=brown>Step 3 (optional). Select regional subet.</font><br>";
      print "<h1 align=center><font color=red>Regional Subset: ";

      if ($nopoints eq '') { print "Points"; }
      if ($nosubregion eq '') { print ", Subregion"; }
      if ($noregrid eq '') { print ", Regrid"; }
      print "</font></h1>";

      print "<p>Regional subsetting can speed up downloads by only transferring newer grid points.<br>";
      print "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;";
      print "<font color=red>points</font> makes a grib2 file using nearest neighbor interpolation (within range km)<br>";
      print "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;";
      print "<font color=red>lat-lon list</font> = lon1:lat1:lon2:lat2:..:lonN:latN &nbsp;&nbsp;&nbsp;lat &lt; 0 for southern hemisphere <br>";
      print "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;";
      print "<font color=red>range km</font> = nearest neighbor has to be within range km to be used<br>";
      print "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;";
      print "<font color=red>point (text)</font> makes text file with nearest-neighbor grid value (unlimited range)<br>";
      print "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;";
      print "<font color=red>subregion</font> makes a regional subset using the original projection (cookie cutter)<br>";
      print "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;";
      print "<font color=red>regrid</font> interpolates to a new grid, can convert grid to earth relative winds. ";
      print "<a href=\"http://www.cpc.ncep.noaa.gov/products/wesley/regrid_grib_filter.html\">documentation</a><br>";
      print "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;";
      print "<font color=red>interpolation</font> bilinear interpolation is a weighted average of surrounding points<br>";
      print "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;";
      print "<font color=red>winds</font> the regridded winds will be earth or grid relative winds<br>";
      print "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;";
      print "<font color=red>earth relative winds</font> U winds are to the east and V winds are to the north<br>";
      print "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;";
      print "<font color=red>grid relative winds</font> U winds are from grid point (i,j) to grid point (i+1,j)<br>";
      print "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;";
      print "<font color=red>if X=latlon</font> then Y=Lon0:nLon:dlon and Z=Lat0:nLat:dLat<br>";
      print "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;";
      print "<font color=red>if X=lambert/gaussian/mercator/nps/ncep</font> see <a href=\"http://www.cpc.ncep.noaa.gov/products/wesley/regrid_grib_filter.html\">documentation</a><br>";


      print "<p>";

      print "<table>";
      print "<tr>";

      print "<td>";
print '<input type="radio" name="subset" value="none" checked>original grid';
      print "</td>";

      print '<td></td>';
      print '<td></td>';
      print '<td></td>';
      print '<td></td>';
      print '<td></td>';
      print '<td></td>';
      print '<td></td>';
      print '<td></td>';
      print '<td></td>';
      print '<td></td>';

      print "</tr>\n";

      if ($nopoints eq '') {

          print "<tr>";
          print "<td>";
          print '<input type="radio" name="subset" value="points">points';
          print "</td>";

          print '<td align="right">';
          print "lon-lat list&nbsp</td><td colspan=4><input type=\"text\" name=\"lon_lat_list\" value=\"120:30:222:-30\"size=25>";
          print "</td>";

          print '<td align="right">';
          print "range km&nbsp</td><td><input type=\"text\" name=\"km\" value=\"500\"size=4>";
          print '<td></td>';
          print '<td></td>';

          print '<td></td>';
          print '<td></td>';

          print "</tr>\n";

          print "<tr>";
          print "<td>";
          print '<input type="radio" name="subset" value="points_text">point (';
          print "<a href=\"http://www.cpc.ncep.noaa.gov/products/wesley/wgrib2/default_inv.html\">text</a>)";
          print "</td>";

          print '<td align="right">';
          print "lon&nbsp</td><td><input type=\"text\" name=\"lon1\" value=\"120\"size=4>";
          print "</td>";

          print '<td align="right">';
          print "lat&nbsp</td><td><input type=\"text\" name=\"lat1\" value=\"45\"size=4>";
          print "</td>";

          print '<td></td>';
          print '<td></td>';
          print '<td></td>';
          print '<td></td>';
          print '<td></td>';
          print '<td></td>';
          print '<td></td>';
          print "</tr>\n";
      }

      if ($nosubregion eq '') {

          print "<tr>";
          print "<td>";
          print '<input type="radio" name="subset" value="subregion">subregion';
          print "</td>";

          print '<td align="right">';
          print "left&nbsp;lon</td><td><input type=\"text\" name=\"leftlon\" value=\"0\"size=4>";
          print "</td>";

          print '<td align="right">';
          print "right&nbsp;lon </td><td><input type=\"text\" name=\"rightlon\" value=\"360\"size=4>";
          print "</td>";

          print '<td align="right">';
          print "top&nbsp;lat </td><td><input type=\"text\" name=\"toplat\" value=\"40\"size=4>";
          print "</td>";

          print '<td align="right">';
          print "bottom&nbsp;lat </td><td><input type=\"text\" name=\"bottomlat\" value=\"-40\"size=4><br>";
          print "</td>";
          print '<td></td>';
          print '<td></td>';

          print "</tr>";
      }
      if ($noregrid eq '') {

          print "<tr>";
          print "<td>";
          print '<input type="radio" name="subset" value="regrid">regrid ';
          print "</td>";

          print '<td align="right">';
          print " &nbsp&nbsp;&nbsp;interpolation</td>";
          print "<td><select name=\"new_grid_interpol\">\n";
          print "<option value=\"bilinear\"> bilinear</option>\n";
          print "<option value=\"neighbor\"> neighbor</option>\n";
          print "<option value=\"bicubic\"> bicubic</option>\n";
          print "</select></td>\n";

          print '<td align="right">';
          print " &nbsp&nbsp;&nbsp;winds </td>";
          print "<td><select name=\"new_grid_winds\">\n";
          print "<option value=\"earth\"> earth</option>\n";
          print "<option value=\"grid\"> grid</option>\n";
          print "</select></td>\n";

          print '<td align="right">';
          print " &nbsp&nbsp;&nbsp;X </td><td><input type=\"text\" name=\"new_grid_X\" value=\"latlon\"size=8>";
          print "</td>";


          print '<td align="right">';
          print " &nbsp&nbsp;&nbsp;Y </td><td><input type=\"text\" name=\"new_grid_Y\" value=\"0:360:1\"size=8>";
          print "</td>";

          print '<td align="right">';
          print " &nbsp&nbsp;&nbsp;Z </td><td><input type=\"text\" name=\"new_grid_Z\" value=\"-90:181:1\"size=8>";
          print "</td>";
          print "<td></td>";
          print "</tr>";
      }
      print "</table>";
   }


  print "<hr><p><font color=brown>Step 4 (mandatory). Download or generate URL. The URL is needed for scripting the downloads.</font><br>";
   print "<h1 align=center><font color=red>Download, show URL</font></h1>";

   print "<p><input type=\"checkbox\" name=showurl value=\"\"> Show the URL for scripting the download or to see the wgrib2 command used to process the data,";

   print "<br><p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;";
   print "<input type=\"submit\" value=\"Start download\"> <input type=\"reset\">";
   print "<input type=\"hidden\" name=\"dir\" value=\"$subdir\">";

   print "</form>"; &credits;

   exit 0;
}



# ------------- page 2 -----------------

sub page2 {

   if (defined($qn{'showurl'})) {
       &html_start("URL for Data Transfer: $title");
       print "<h1 align=center> <font color=red>Scripting file retrievals</font></h1>\n";
       print "<p> If you download many files through this web interface, you will want to ";
       print "automate the process.  You can do this by writing a simple script with a loop around the ";
       print "file retrieval command.";
       print "  This is better than clicking until your mouse is broken.\n";

#      remove the showurl piece of the URL
       $q2=$query;
       $q2 =~ s/&showurl=//;

#      remove unneeded arguments from URL subset options
       if ($q2 =~ /&subset=none&/) {
          $q2 =~ s/&lon_lat_list=[^&]*//;
          $q2 =~ s/&lat1=[^&]*//;
          $q2 =~ s/&lon1=[^&]*//;
          $q2 =~ s/&km=[^&]*//;
          $q2 =~ s/&bottomlat=[^&]*//;
          $q2 =~ s/&toplat=[^&]*//;
          $q2 =~ s/&leftlon=[^&]*//;
          $q2 =~ s/&rightlon=[^&]*//;
          $q2 =~ s/&new_grid_X=[^&]*//;
          $q2 =~ s/&new_grid_Y=[^&]*//;
          $q2 =~ s/&new_grid_Z=[^&]*//;
          $q2 =~ s/&new_grid_interpol=[^&]*//;
       }
       if ($q2 =~ /&subset=points&/) {
          $q2 =~ s/&lat1=[^&]*//;
          $q2 =~ s/&lon1=[^&]*//;
          $q2 =~ s/&bottomlat=[^&]*//;
          $q2 =~ s/&toplat=[^&]*//;
          $q2 =~ s/&leftlon=[^&]*//;
          $q2 =~ s/&rightlon=[^&]*//;
          $q2 =~ s/&new_grid_X=[^&]*//;
          $q2 =~ s/&new_grid_Y=[^&]*//;
          $q2 =~ s/&new_grid_Z=[^&]*//;
          $q2 =~ s/&new_grid_interpol=[^&]*//;
       }
       if ($q2 =~ /&subset=points_text&/) {
          $q2 =~ s/&lon_lat_list=[^&]*//;
          $q2 =~ s/&km=[^&]*//;
          $q2 =~ s/&bottomlat=[^&]*//;
          $q2 =~ s/&toplat=[^&]*//;
          $q2 =~ s/&leftlon=[^&]*//;
          $q2 =~ s/&rightlon=[^&]*//;
          $q2 =~ s/&new_grid_X=[^&]*//;
          $q2 =~ s/&new_grid_Y=[^&]*//;
          $q2 =~ s/&new_grid_Z=[^&]*//;
          $q2 =~ s/&new_grid_interpol=[^&]*//;
       }
       if ($q2 =~ /&subset=subregion&/) {
          $q2 =~ s/&lon_lat_list=[^&]*//;
          $q2 =~ s/&lat1=[^&]*//;
          $q2 =~ s/&lon1=[^&]*//;
          $q2 =~ s/&km=[^&]*//;
          $q2 =~ s/&new_grid_X=[^&]*//;
          $q2 =~ s/&new_grid_Y=[^&]*//;
          $q2 =~ s/&new_grid_Z=[^&]*//;
          $q2 =~ s/&new_grid_interpol=[^&]*//;
       }
       if ($q2 =~ /&subset=regrid&/) {
          $q2 =~ s/&lon_lat_list=[^&]*//;
          $q2 =~ s/&lat1=[^&]*//;
          $q2 =~ s/&lon1=[^&]*//;
          $q2 =~ s/&km=[^&]*//;
          $q2 =~ s/&bottomlat=[^&]*//;
          $q2 =~ s/&toplat=[^&]*//;
          $q2 =~ s/&leftlon=[^&]*//;
          $q2 =~ s/&rightlon=[^&]*//;
       }
#      change & to &amp; for display html display
       $q2 =~ s/&/&amp;/g;

       print "<br>&nbsp;<br>URL for downloading the file=<br>\n<font color=\"red\">http://$script_url?$q2</font><br>";
       print "<p>File retrieval command line for downloading file using the cURL command:<br>";
       print "<p><font color=\"red\">curl \"http://$script_url?$q2\" -o my_file</font>\n";
       print "<p>File retrieval command line for downloading file using the wget command:<br>";
       print "<p><font color=\"red\">wget -O my_file \"http://$script_url?$q2\"</font>\n";


       print "<p> <a href=\"http://www.cpc.ncep.noaa.gov/products/wesley/scripting_grib_filter.html\">information about scripting downloads</a>.";
#       &credits;
#       exit;
    }

# check if file exists

   $name = $qn{'file'};
   $lname="$dir$subdir/$name";

   if ( ! -f $lname) {
      print "Status: 404 data file not present\n";
      print "Content-type: text/html\n\n";
      print '<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">';
      print "<html><head><title>data file is not present; $lname</title></head><body bgcolor=\"#ffffff\">";
      print "<p align=center>Data file is not present: $lname</p>";
      &credits;
      exit;
   }

#  generate the wgrib2 filter
   $filter='';
   $filter2='';

   if ($gribfilter ne '') {
      $var_filter='';
      $lev_filter='';
      $hor_filter='';
      $day_filter='';
      $mon_filter='';
      foreach $_ (keys(%qn)) {
         $_ = &unhex($_);

#        get rid of nasty characters
#        allow ( ) in level fields
         tr/:;|"'\\//d;
         /^lev_/ && do {
#           convert ( -> \(  and ) -> \) and ^ -> \^
	    $_ =~ s/\(/\\(/g;
	    $_ =~ s/\)/\\)/g;
	    $_ =~ s/\^/\\^/g;
	    $lev_filter = join '', $lev_filter, '|', substr($_,4);
            };

#        get rid of nasty characters
         tr/:;|"'()\\//d;
   
#         /^lev_/ && do {$lev_filter = join '', $lev_filter, '|', substr($_,4);
         /^var_/ && do {$var_filter = join '', $var_filter, '|', substr($_,4);};
         /^hor_/ && do {$hor_filter = join '', $hor_filter, '|', substr($_,4,2);};
         /^day_/ && do {$day_filter = join '', $day_filter, '|', substr($_,4,2);};
         /^mon_/ && do {$mon_filter = join '', $mon_filter, '|', substr($_,4,2);};
      } 
   
      if (defined $qn{'all_var'}) { $var_filter=''; }
      if (defined $qn{'all_lev'}) { $lev_filter=''; }
      if (defined $qn{'all_day'}) { $day_filter=''; }
      if (defined $qn{'all_mon'}) { $mon_filter=''; }
      if (defined $qn{'all_hor'}) { $hor_filter=''; }

      if ($months eq '') { $mon_filter=''; }
      if ($days eq '') { $day_filter=''; }
      if ($hours eq '') { $hor_filter=''; }

      if ( $var_filter eq "|" ) { $var_filter=''; }
      if ( $lev_filter eq "|" ) { $lev_filter=''; }
      if ( $day_filter eq "|" ) { $day_filter=''; }
      if ( $mon_filter eq "|" ) { $mon_filter=''; }
      if ( $hor_filter eq "|" ) { $hor_filter=''; }

      if ( $var_filter ne "" ) {
         $filter=join '', $filter, ' -match \':(',substr($var_filter,1),'):\'';
         $filter2=join '', $filter2, ' | egrep \':(',substr($var_filter,1),'):\'';
      }
      if ( $lev_filter ne "" ) {
         $lev_filter =~ s/_/ /g;
         $filter=join '', $filter, ' -match \':(',substr($lev_filter,1),'):\'';
         $filter2=join '', $filter2, ' | egrep \':(',substr($lev_filter,1),'):\'';
      }
      if ( $hor_filter ne "" ) {
         $filter=join '', $filter, ' -match \':', $date_code, '........(',substr($hor_filter,1),')\'';
         $filter2=join '', $filter2, ' | egrep \':', $date_code, '........(',substr($hor_filter,1),')\'';
      }
      if ( $day_filter ne "" ) {
         $filter=join '', $filter, ' -match \':', $date_code, '......(',substr($day_filter,1),')\'';
         $filter2=join '', $filter2, ' | egrep \':', $date_code, '......(',substr($day_filter,1),')\'';
      }
      if ( $mon_filter ne "" ) {
         $filter=join '', $filter, ' -match \':', $date_code, '....(',substr($mon_filter,1),')\'';
         $filter2=join '', $filter2, ' | egrep \':', $date_code, '....(',substr($mon_filter,1),')\'';
      }
      if ($filter2 ne '') { $filter2=substr($filter2,3); }
   }

#  Generate wgrib2 arguements to write data to stdout

   $output_type = '-inv /dev/null -grib -';

   $subset = '';
   if ($qn{'subset'} eq 'points') {
      $lon_lat_list=$qn{'lon_lat_list'};
      $lon_lat_list =~ s/%3[aA]/:/g;
      $lon_lat_list =~ s/[^-+.0-9:]//g;

      $km=$qn{'km'};
      $km =~ s/[^-+.e0-9]//g;
      $output_type = "-inv /dev/null -irr_grid $lon_lat_list $km -";
      $subset = 1;
   }
   if ($qn{'subset'} eq 'points_text') {
      $lat1=$qn{'lat1'};
      $lon1=$qn{'lon1'};
      $km=$qn{'km'};
      $lat1 =~ s/[^-+.e0-9]//g;
      $lon1 =~ s/[^-+.e0-9]//g;
      $km =~ s/[^-+.e0-9]//g;
      $output_type = "-crlf -v -s -v0 -start_ft -lon $lon1 $lat1";
      $subset = 1;
   }

   if (defined $qn{'subregion'} || $qn{'subset'} eq 'subregion') {
      $lonW=$qn{'leftlon'};
      $lonE=$qn{'rightlon'};
      $latN=$qn{'toplat'};
      $latS=$qn{'bottomlat'};

      $lonW =~ s/[^-+.e0-9]//g;
      $lonE =~ s/[^-+.e0-9]//g;
      $latN =~ s/[^-+.e0-9]//g;
      $latS =~ s/[^-+.e0-9]//g;

      if ($latN < $latS) {
          &error_page("North latitude < south lat");
          exit;
      }
      $output_type = "-inv /dev/null -set_grib_type same -small_grib $lonW:$lonE $latS:$latN -";
      $subset = 1;
   }
   if ($qn{'subset'} eq 'regrid') {
      $arg_interpol='';
      if ($qn{'new_grid_interpol'} eq 'neighbor') { $arg_interpol='-new_grid_interpolation neighbor'; }
      if ($qn{'new_grid_interpol'} eq 'bicubic') { $arg_interpol='-new_grid_interpolation bicubic'; }

      $arg_winds='-new_grid_winds earth';
      if ($qn{'new_grid_winds'} eq 'grid') { $arg_winds='-new_grid_winds grid'; }

      $arg_x=$safeqn{'new_grid_X'};
      $arg_y=$safeqn{'new_grid_Y'};
      $arg_z=$safeqn{'new_grid_Z'};
      if ($arg_x eq 'ncep' && $arg_y eq 'grid') {
	  if (! ($arg_z =~ /^t?[0-9]+$/))   { &error_page("undefined ncep grid"); exit 0;}
      }
      else {
          $arg_x =~ s/%3[aA]/:/g;
          $arg_y =~ s/%3[aA]/:/g;
          $arg_z =~ s/%3[aA]/:/g;
          $arg_x =~ s/[^-+.0-9a-z:]//g;
          $arg_y =~ s/[^-+.0-9e:]//g;
          $arg_z =~ s/[^-+.0-9e:]//g;
      }
      $output_type = "-inv /dev/null -set_grib_type same $arg_winds $arg_interpol -new_grid $arg_x $arg_y $arg_z -";
      $subset = 1;
   }

#  two cases
#    1: run the file through wgrib
#    2: just cat the file

   if ($filter ne '' || $subset ne '') {

#     two cases
#     1: no inventory file
#     2: inventory file

      if (-r "$lname.inv$wgrib_flag") {
         if ($filter2 eq '') {
            $cmd="$wgrib2 $lname $output_type";
         }
         else {
            $cmd="cat $lname.inv$wgrib_flag | $filter2 | $wgrib2 $lname -i $output_type";
         }
      }
      else {
         $cmd="$wgrib2 $lname $wgrib_flag $filter $output_type";
      }
# debug
# &error_page("$cmd\n");
# exit;
      if (defined($qn{'showurl'})) {
#         remove pathnames and remove trickery with stdout
          $cmd =~ s/-$/OUT.GRB/;
          $cmd =~ s/-inv \/dev\/null / /;
          $cmd =~ s/\/\S*\///g;
          print "<p>This web service is a wrapper for wgrib2.  This is the command used to process the grib data.<br><font color=red>$cmd</font></p>\n";
          print "<br><br><br><br>";
          &credits;
          exit;
      }

      print "Status: 200 OK\n";
         print "Content-Transfer-Encoding: binary\n";
      if ($qn{'subset'} eq 'points_text') {
         print "Content-Disposition: attachment; filename=\"$name.txt\" \n";
	 print "Content-Description: text file\n";  
         print "Content-type: text/plain \n\n";
      }
      else {
         print "Content-Disposition: attachment; filename=\"$name\" \n";
	 print "Content-Description: grib2 file\n";  
         print "Content-type: application/octet-stream \n\n";
      }
      system "$cmd 2>/dev/null";
   }
   else {
#&error_page("$cmd\n");
#exit;
      if (defined($qn{'showurl'})) {
          print "<p>no command is used to filter the grib data:</p>\n";
          &credits;
          exit;
      }

      $nbyte = -s $lname;
      print "Status: 200 OK\n";
      print "Content-Transfer-Encoding: binary\n";
      print "Content-Disposition: attachment; filename=\"$name\" \n";
      print "Content-Description: grib2 file\n";
      print "Content-Length: $nbyte\n";
      print "Content-type: application/octet-stream \n\n";
      system "cat $lname";
   }

# log entry
   open (Logfile, ">>$logfile");
   $date=`date '+%d/%b/%Y:%T'`;
   substr($date,-1,1)='';
   print Logfile "$REMOTE_HOST - - [$date -$pid] \"good_copy:$script_name $name $filter\n";
   close(Logfile);

   exit 0;
}

sub error_page {
#
# print out an error page (HTML)
#
   print "Status: 500 server error\n";
   &html_start("Error");
   print "<font color=red><h2 align=\"center\">Error</h2></font>\n";
   print "<p align=\"center\"> $_[0]\n";
   if (defined ( $_[1]) && $_[1] ne '') {
     print "<p align=\"center\"> $_[1]\n";
   }
   &credits;
}


sub page1_html_start {
#
# print out page 1 html header
#

   &html_start("Grib2 Subset Data Transfer: $_[0]");
   print "<h2 align=center>Grib2 Subset Data Transfer: $_[0]</h2>";
   print "<p>Create a subset of a grib2 file for faster downloading. Designed for easy scripting.<br>";
   print "<p><font color=brown>Step 1 (mandatory). Select a file.</font><br>";
   return;
}

sub html_start {
   print "Content-type: text/html\n\n";
   print '<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">';
   print "<html><head><title>$_[0]</title></head><body bgcolor=\"#ffffff\">";
   return;
}



sub credits {
   print "<p align=left><small>";
   print "g2sub $version, for comments about the script: Wesley.Ebisuzaki\@noaa.gov, Jun.Wang\@noaa.gov<br>";
   print "</small></body></html>\n";
   return;
}

#
#  unhexes a query string
#
sub unhex {
   local ($c, $i, $j, $s, $t, $len);
   $s=$_[0];
   if (! defined($s)) { $s=''; }
   $t='';
   $len = length($s);
   $i = 0;
   $j = 0;
   while ($i < $len) {
       $c = substr($s, $i, 1);
       if ($c eq '%') {
          $c = chr(hex(substr($s,$i+1,2)));
          $i += 3;
       }
       else {
          if ($c eq '+') { $c = ' '; }
          $i++;
       }
       if ($c eq '`') { $c = '"'; }
       if ($c eq ';') { $c = ' '; }
       substr($t,$j++,1) = $c;
   }
   return $t;
}

#
# read and parse the .g2subrc file
#

sub read_g2subrc {
    local ($dir);
    $dir=$_[0];
    $file="$dir/.g2subrc";
    if (!-r "$file") {
        return;
    }
    open(FTP2URC, "< $file");
    while (<FTP2URC>) {
        ($name,$value) = split('=', $_, 2);
        if (defined $value) { chomp $value; }
        if ($name eq 'title') {
            $title=$value;
        }
        elsif ($name eq 'gribfilter') {
            $gribfilter=$value;
        }
        elsif ($name eq 'files_pat') {
            $files_pat=$value;
        }
        elsif ($name eq 'vars') {
            $vars=$value;
        }
        elsif ($name eq 'levs') {
            $levs=$value;
        }
        elsif ($name eq 'ncol') {
            $ncol=$value;
        }
        elsif ($name eq 'hours') {
            $hours=$value;
        }
        elsif ($name eq 'days') {
            $days=$value;
        }
        elsif ($name eq 'months') {
            $months=$value;
        }
        elsif ($name eq 'forecast') {
            $forecast=$value;
        }
        elsif ($name eq 'nosubregion') {
            $nosubregion=$value;
        }
        elsif ($name eq 'nopoints') {
            $nopoints=$value;
        }
        elsif ($name eq 'noregrid') {
            $noregrid=$value;
        }
    }
    close(FTP2URC);
    return;
}
}
1;
