#!/usr/bin/perl -TI../ -I./
#
# date product browser
#
# $Id$
#
# get action test
#
# April 2000
#--------------------------------------------------------------------
use CGI;
require "config.pl";
require "util.pl";

($PROGRAM = $0) =~ s%.*/%%;
$|=1;
$ENV{'PATH'} = '';
$THIS_DOCDIR = $OPS_DOCDIR;
$THIS_REAL_DOCDIR = $OPS_REAL_DOCDIR;
$THIS_CGIDIR = $OPS_CGIDIR;
$CATEGORY = "ops";
$LOOPER = "$CGIDIR/loop.pl.test";
$TARGET = 'target="newwindow"';
$HCOLOR = "lightblue";
$GREY = "#EEEEEE";
$TITLE = "Available Operational Products";

$FORM = new CGI;

%list = ();


#--------------------------------------------------------------------
#
# IOP input
#
#--------------------------------------------------------------------
#if($iop = $FORM->param("iop")) {
##$iop = 4;
#  # untaint iop input
#  if($iop =~ /(\d+)/) {
#    $iop = $1;
#    $iop =~ s/^\s*0*//;
#  } else {
#    $iop = 'INVALID';
#  }
#  $iop = 'INVALID' if(!$IOP_DATES{$iop});
# 
#  # Construct date query for unix 'find'
#  ($start,$end) = split /:/,$IOP_DATES{$iop};
#  for $i (0..7) {
#    $s = substr $start,$i,1;
#    $e = substr $end,$i,1;
#    if($s == $e) {
#      $query_date .= $s;
#    } else {
#      $query_date .= "[$s-$e]*"; 
#      last;
#    } 
#  }
#
#  # Create the 'list' hash for print_arrows subroutine
#  for $i (sort keys %IOP_DATES) {
#    ($s,$e) = split /:/,$IOP_DATES{$i};
#    $list{$i} = "IOP $i ($s -> $e)";
#  }
#  $name = "IOP $iop ($start -> $end)";
#  $name_short = "IOP $iop";
#  $user_input = ($iop =~ /INVALID/ ? 1:$iop);
#  $param_name = "iop";
#  $param_str  = "iop";

#--------------------------------------------------------------------
#
# start/end input
#
#--------------------------------------------------------------------
if($start = $FORM->param("start")) {
  $end = $FORM->param("end");
  $mission = $FORM->param("mission");
  $tz = "UTC";

  $datestr = substr $start,0,4;
  $datestr .= "/" . substr $start,4,2;
  $datestr .= "/" . substr $start,6,2;
  $hour = substr $start,8,2;
  $min = substr $start,10;
  $datestr .= " $hour:$min" if($hour ne "");

  ($s = $start) =~ s/(\d{4})(\d\d)(\d\d)/$1\/$2\/$3/;
  $s =~ s/(\/\d\d)(\d\d)/$1 $2/;
  $s =~ s/( \d\d)(\d\d)/$1:$2/;
  ($e = $end) =~ s/(\d{4})(\d\d)(\d\d)/$1\/$2\/$3/;
  $e =~ s/(\/\d\d)(\d\d)/$1 $2/;
  $e =~ s/( \d\d)(\d\d)/$1:$2/;

  $name = "$mission mission($s -> $e UTC)";
  #$name_short = "mission $mission ($tz)";
  $name_short = "$mission mission";
  #$user_input = $ldate;
  #$param_name = "date$tz";
  #$param_str  = "Date\($tz\)";

  #$platform = 'S-Pol';
  $platform = '*';
  $prod = '*';

#--------------------------------------------------------------------
#
# Local Date input
#
#--------------------------------------------------------------------
} elsif($ldate = $FORM->param("date$TZ")) {
  # untaint ldate input
  if($ldate =~ /(200[0-9]\d{4})/) {
    $ldate = $1;
  } else {
     zprint_error("Invalid date$TZ value"); 
  }
  $tz = $TZ;
  $start = local2gmt("${ldate}000000");
  $end   = local2gmt("${ldate}235959");

  ($s = $start) =~ s/(\d{4})(\d\d)(\d\d)/$1\/$2\/$3 $4:$5:$6/;
  ($s = $start) =~ s/(\d{4})(\d\d)(\d\d)(\d\d)(\d\d)(\d\d)/$1\/$2\/$3 $4:$5:$6/;
  ($e = $end) =~ s/(\d{4})(\d\d)(\d\d)(\d\d)(\d\d)(\d\d)/$1\/$2\/$3 $4:$5:$6/;
  ($lds = $ldate) =~ s/(\d{4})(\d\d)(\d\d)/$1\/$2\/$3/;
  $name = "$lds $TZ ($s -> $e UTC)";
  $name_short = "$ldate($TZ)";
  $user_input = $ldate;
  $param_name = "date$TZ";
  $param_str  = "Date\($TZ\)";

  $platform = '*';
  $prod = '*';
#--------------------------------------------------------------------
#
# GMT DATE input - default
#
#--------------------------------------------------------------------
} else {
  $tz = "UTC";
  if($date = $FORM->param("dateUTC")) {
    # untaint date input
    if($date =~ /(200[0-9]\d{4})/) {
      $date = $1;
    } else {
      zprint_error("Invalid dateUTC value"); 
    }
  # if no user input use first available date - the default
  } else {
    #$date = (sort keys %list)[-1]; #last element
    $date = (sort keys %list)[0];   #first element
  }
  $start = $date;
  $end = $date;
  ($name = $date) =~ s/(\d{4})(\d\d)(\d\d)/$1\/$2\/$3/;
  $name .= " $tz";
  $name_short = $date;
  #$query_date = $date;
  $user_input = $date;
  $param_name = "dateUTC";
  $param_str  = "Date\(UTC\)";

  $platform = '*';
  $prod = '*';
}

#
# Read the groups in the 'groups.pl' file
#
@groups=();
$groupfile = "$REAL_CGIDIR/$CATEGORY/groups.pl";
if(-e $groupfile) {
  require $groupfile;
  open(GROUP ,"<$groupfile");
  while(<GROUP>) {
    if(/@(\w+)[\s=]+/) {
      $group = $1;
      push(@groups,$1) if($#{$group} > -1);
    }
  }
  close GROUPS;
  $info_link = $LINKS{lc $platform};
}


#
# Find all products for a given day. 
#
$category = $CATEGORY;
#$platform = '*';
#$prod = '*';
@files = &file_query(\$category,\$platform,\$prod,\$start,\$end);
if($#files < 0) {
 zprint_error("No files found");
}                              


#
# Separate products into groups.
#
FILE:foreach (@files) {
  ($link = $_) =~ s/^$DOCROOT//; 
  $file = $link;
  $file =~ s/.*\///;
  ($fcategory,$fplatform,$pdate,$dummy2) = split /\./, $file,4;
  foreach $group (@groups) {
    if(grep /^$fplatform$/i, @{$group}) {
      push(@{"${group}_links"},$link);
      next FILE;
    }
  }
  push(@OTHER,$link);
}

#
# Find date range for previous/next buttons
#
opendir (PRODS, $THIS_REAL_DOCDIR);
while ($proddir = readdir PRODS) {
  next if ($proddir =~ /^\./);
  if (-d "$THIS_REAL_DOCDIR/$proddir") {
    opendir(PDATE, "$THIS_REAL_DOCDIR/$proddir");
    while ($datedir = readdir PDATE) {
      next if ($datedir =~ /^\./);
      if (-d "$THIS_REAL_DOCDIR/$proddir/$datedir") {
        ($datestr = $datedir) =~ s/(\d{4})(\d\d)(\d\d)/$1\/$2\/$3/;
        $list{$datedir} = $datestr." $tz"; 
      }
    }
  }
}
closedir PRODS;

#
# Local timezone fudge
#
@dates = sort keys %list;
if($tz eq $TZ)  {
  # east time zones - add another day at end
  if($DH < 0) {
    $newdate = &date_add_hour($dates[-1],24);
  # west time zones - add another day at beginning
  } else {
    $newdate = &date_add_hour($dates[0],-24);
  }
  ($datestr = $newdate) =~ s/(\d{4})(\d\d)(\d\d)/$1\/$2\/$3/;
  $list{$newdate} = $datestr." $tz"; 
}


#
#Do screen echo
#---------------
print "Content-type: text/html\n\n";

#
# print header
#
if (-e "$THIS_REAL_DOCDIR/head.html") {
  #print `/bin/cat $THIS_REAL_DOCDIR/head.html`
  $header = join "",`/bin/cat $THIS_REAL_DOCDIR/head.html`;
  $header =~ s/(\<\/title\>)/: $name_short$1/i;
  print $header;
}


#print <<EOHDR;
#<HEAD>
#<TITLE>$PROJECT PRODUCT INVENTORY FOR $name</TITLE>
#<style>
#<!--
#A.status {text-decoration: none;color: black}
#-->
#</style>
#</HEAD>
#<BODY BGCOLOR="#ffffff" LINK="#0000ff" VLINK="#6600cc" ALINK="#ff0000" TEXT="#000000">

print <<EOHDR;
<center>
<!--
<h1>$PROJECT PRODUCT INVENTORY</h1>
-->

<font color=008800><b>(The following listing is auto generated.
Click reload/refresh often to see new products.) </font></b>

<h3>$TITLE for $name</h3>

EOHDR

#
# Print the navigation arrows and menu
#
&print_arrows($param_str,$param_name,$user_input,%list) if(!$mission);

#
# Print the Product tables for each group
#
foreach $group (@groups) {
  $group_links = "${group}_links";
  ($group_title = $group) =~ s/_/ /g;
  if ( $#{$group_links} < 0 ) {
    print "<table border=1 cellpadding=2 cellspacing=0>\n";
    print "<caption>$group_title</caption>\n";
    print "<tr><td><b>No $group_title for: $name_short</b></td></tr>\n";
    print "</table>\n";
  } elsif($group =~ /forecast/i) {
    %PRODS = &forecast_hash(@{$group_links});
    &print_table("$group_title","Forecast<br>Times(UTC)",%PRODS);
  } else {
    %PRODS = &prod_hash(@{$group_links});
    &print_table("$group_title","Product<br>Times(UTC)",%PRODS);
  }
  print "<p>\n";


}

#
# Create Other Product Table
#
if ( $#OTHER > -1 ) {
  %PRODS = &prod_hash(@OTHER);
  &print_table("Other Products","Product<br>Times(UTC)",%PRODS);
  print "<p>\n";
}

#******************************************************************
#
# Print Footer
#
#******************************************************************
print "</center><p>\n";
print $FOOTER;

exit 0;
sub do_error {
  local($errstr) = @_;
  print <<EOERR;
<H1>Error</H1>
An error has occurred.
$errstr
Please send mail to
<EM><A HREF="mailto:www\@joss.ucar.edu">www\@joss.ucar.edu</A></EM>
and tell us what you were doing when the error occurred. Thank you.
<HR>
EOERR
  exit 0;
}

#******************************************************************
# subroutine: print_table
#
# inputs:
#
#  $caption      - caption for table.
#  $top_row_name - text string to put in top left corner of table.
#  %prods        - input hash for table entries.
#
#   %prods must be of the form:
#    $prods{prod[;date]}{subp}{year}{month}{day}{hour}{time} = "file[;name]";
#   where: 
#         prod  = product name
#         ;date = YYYYMMDDhhmm... optional model analysis time. For forecast
#                                 models.
#         subp  = subproduct name
#         year  = YYYY (four digit year)
#         month = MM (1-12)
#         day   = DD (1-31)
#         hour  = hh (0-23)
#         time  = hhmmss...
#         file  = url path to file
#         ;name = optional string to use for link name. If not present
#                 will use 'time' above for link name.
#
#******************************************************************

sub print_table {

  local($caption,$top_row_name,%prods) = @_;
  local(%dates) = ();
  local($year,$month,$day,$hour,$time);
  local($prod,$subp,$nsubp,$titleprod,$trueprod,$runtime);
  local($fullprod,$fullsubp);
  local($name,$totcol,$colspan,$nspace);
  local(@allurl,@hrlyurl,%hrlyurl_flag);

  # For cosmetic purposes only. Used for indenting table tags.
  local($s0,$s1,$s2,$s3,$s4);
  $s0 = "";
  $s1 = $s0."\t"x1;
  $s2 = $s0."\t"x2;
  $s3 = $s0."\t"x3;
  $s4 = $s0."\t"x4;

  # Stuff the date and hour range into hash 'dates'
  for $prod (keys %prods) {
   for $subp (keys %{$prods{$prod}}) {
    $nsubp++;
    for $year (keys %{$prods{$prod}{$subp}}) {
     for $month (keys %{$prods{$prod}{$subp}{$year}}) {
      for $day (keys %{$prods{$prod}{$subp}{$year}{$month}}) {
       for $hour (keys %{$prods{$prod}{$subp}{$year}{$month}{$day}}) {
        $dates{$year}{$month}{$day}{$hour} = 1;   
       }
      }
     }
    }
   }
  }


  # Calculate total column span
  $totcol=2;
  for $year (sort keys %dates) {
   for $month (sort keys %{$dates{$year}}) {
    for $day (sort keys %{$dates{$year}{$month}}) {
     for $hour (sort keys %{$dates{$year}{$month}{$day}}) {
       $totcol++;
     }
    }
   }
  }

  #
  # Start table and print the days the products span.
  #
  #print "$s0<table cols=$totcol width=\"80%\" border=1 cellpadding=2 cellspacing=0>\n";
  #print "$s0<table cols=$totcol border=1 cellpadding=2 cellspacing=0>\n";
  print "$s0<table border=1 cellpadding=2 cellspacing=0>\n";
  print "$s1<caption>$caption</caption>\n";

  print "$s1<tr align=center>\n";
  print "$s2<td rowspan=2>\n";
  print "${s3}$top_row_name\n";
  print "$s2</td>\n";
  for $year (sort keys %dates) {
   for $month (sort keys %{$dates{$year}}) {
    for $day (sort keys %{$dates{$year}{$month}}) {
     $colspan = keys %{$dates{$year}{$month}{$day}};
     $smonth = $NUMTOMONTH[$month];
     print "$s2<td  bgcolor=$HCOLOR colspan=$colspan align=center>\n";
     print "$s3<b>$day $smonth $year</b>\n";
     print "$s2</td>\n";
    }
   }
  }
  print "$s2<td rowspan=2 bgcolor=$GREY>\n";
  print "$s3 Movies\n";
  print "$s2</td>\n";
  print "$s1</tr>\n";

  #
  # Print the hours for which there are products for each day
  #
  print "$s1<tr>\n";
  #$totcol=2;
  for $year (sort keys %dates) {
   for $month (sort keys %{$dates{$year}}) {
    for $day (sort keys %{$dates{$year}{$month}}) {
     for $hour (sort keys %{$dates{$year}{$month}{$day}}) {
      print "$s2<td  bgcolor=$HCOLOR align=center>\n";
      print "$s3<b>$hour</b>\n";
      print "$s2</td>\n";
      #$totcol++;
     }
    }
   }
  }
  print "$s1</tr>\n";


  #
  # Start of main table.
  #
  for $prod (sort keys %prods) {
   $runtime = '';
   ($trueprod,$runtime) = split /;/, $prod;
   if($runtime ne "") { # A forecast product. 'runtime' is analysis time
     ($runtime_str = $runtime) =~ s/(\d{4})(\d\d)(\d\d)(\d\d)(\d\d)/$1\/$2\/$3 $4:$5/;    
     $titleprod = "$trueprod -  Analysis and Forecast from $runtime_str UTC";
   } else {
     $titleprod = $prod;
   }
   #$fullprod = $LONG_NAMES{$trueprod} ? $LONG_NAMES{$trueprod} : $trueprod;
   print "$s1<tr align=center valign=top>\n"; 
   print "$s2<td colspan=$totcol align=left bgcolor=lightgrey>\n"; 
   print "$s3<b>$titleprod</b>\n"; 
   #print "$s3<b><a class=status title='$fullprod' href=\"javascript:alert('$trueprod:  $fullprod')\" onMouseOver=\"status='$fullprod'\;return true\" onMouseOut=\"status=''\">$trueprod</a></b>\n"; 

   $info_link = $LINKS{lc $trueprod};
   print "($info_link)" if($info_link);
#<HACK>
#if($prod =~ /^mips/i) {
#  print " (<a href=\"/ihop/catalog/mips_doc.html\">MIPS Wind Product Information</a>)";
#}
#</HACK>
   print "$s2</td>\n"; 
   print "$s1</tr>\n"; 
   for $subp (sort keys %{$prods{$prod}}) {

    print "$s1<tr>\n"; 
    print "$s2<td>\n"; 
    #$fullsubp = $LONG_NAMES{"$trueprod:$subp"} ? $LONG_NAMES{"$trueprod:$subp"} : $subp;
    #print "$s3<a class=status title='$fullsubp' href=\"javascript:alert('$subp:  $fullsubp')\" onMouseOver=\"status='$fullsubp'\;return true\" onMouseOut=\"status=''\">$subp</a>\n"; 
    print "$s3$subp\n"; 
    print "$s2</td>\n"; 

    @allurl = ();
    @hrlyurl = ();       
    %hrlyurl_flag = ();

    for $year (sort keys %dates) {
     for $month (sort keys %{$dates{$year}}) {
      for $day (sort keys %{$dates{$year}{$month}}) {
       for $hour (sort keys %{$dates{$year}{$month}{$day}}) {


        if($prods{$prod}{$subp}{$year}{$month}{$day}{$hour}) {
         print "$s2<td align=center>\n";
         $nspace = ""; #So we won't print a link and a space
         for $time (sort keys %{$prods{$prod}{$subp}{$year}{$month}{$day}{$hour}}) {
          if($link = $prods{$prod}{$subp}{$year}{$month}{$day}{$hour}{$time}) {
           ($link,$name) = split /;/, $link;
           if(!$name) {
             $name = $time;
           } else { 
             $name .= "hr" if($name !~ /->/);
           }
           $link =~ s/^\.\///;
           $file = $link; $file =~ s/.*\///;;
           ($file =~ /.*\.(.+?)$/) && ($suffix = $1);

           #Generate movie links
           if (grep /^$suffix$/i, @IMGSFXS) { 
             ($imglink = $link) =~ s/.*\///;
             $parm = "&img=" . $imglink;
             if($runtime ne "") { # A forecast product
               push(@allurl, $parm);
               #@allurl = ($runtime,$runtime);
             } else {
               push(@allurl, "$year$month$day$hour");
             }
             push(@hrlyurl, $parm) if(!$hrlyurl_flag{$year}{$month}{$day}{$hour}); 
             $hrlyurl_flag{$year}{$month}{$day}{$hour} = 1;  
           }

           print "$s3<a style=\"text-decoration: none\" href=\"";
           SWITCH: {
             if (grep /^$suffix$/i, @IMGSFXS) { 
                print "$CGIDIR/imagewrap.nonav?$link"; last SWITCH; }
             if (grep /^$suffix$/i, @TXTSFXS) { 
                print "$CGIDIR/preformat.nonav?$link"; last SWITCH; }
             if (grep /^$suffix$/i, @HTMLSFXS) { 
                print "$CGIDIR/htmlwrap.nonav?$link"; last SWITCH; }
             print "$link";
           }
           print "\" $TARGET><font size=-2>${name}</font></a><br>\n";
           $nspace = 1;
          } elsif(!$nspace) {
           print "${s3}&nbsp;\n";
           $nspace = 1;
          }
         }
         print "$s2</td>\n";
        } else {
         print "$s2<td>&nbsp;</td>\n";
        }

       }
      }
     }
    }

    #
    # Print the movie links at right side of table
    #
    print "$s2<td bgcolor=$GREY>\n";

    if($#allurl > 0) {
      if($runtime ne "") {
        ($turl = join "",@allurl) =~ s/^&//;
        print "$s3<font size=2><a href=\"$LOOPER?$turl\" $TARGET>all</a></font>\n";
      } else {
        $pstart = $allurl[0];
        $pend = $allurl[-1];
        print "$s3<font size=2><a href=\"$LOOPER?category=$CATEGORY&platform=$trueprod&prod=$subp&start=$pstart&end=$pend\" $TARGET>all</a></font>\n";
      }
      if($#hrlyurl > 0 && $#hrlyurl < $#allurl) {
        ($turl = join "",@hrlyurl) =~ s/^&//;
        print "$s3<font size=2><a href=\"$LOOPER?$turl\" $TARGET>hourly</a></font>\n";
      }
    } else {
      print "$s3&nbsp;\n";
    }



    print "$s2</td>\n";
    print "$s1</tr>\n";


   }
  }

  if($nsubp > 15) {
    #
    # Print the dates again at bottom of table.
    #
    print "$s1<tr align=center>\n";
    print "$s2<td rowspan=2>\n";
    print "${s3}$top_row_name\n";
    print "$s2</td>\n";
  
    # Print the hours for which there are products for each day
    #$totcol=2;
    for $year (sort keys %dates) {
     for $month (sort keys %{$dates{$year}}) {
      for $day (sort keys %{$dates{$year}{$month}}) {
       for $hour (sort keys %{$dates{$year}{$month}{$day}}) {
        print "$s2<td  bgcolor=$HCOLOR align=center>\n";
        print "$s3<b>$hour</b>\n";
        print "$s2</td>\n";
        #$totcol++;
       }
      }
     }
    }
  
    print "$s2<td rowspan=2>\n";
    print "$s3&nbsp;\n";
    print "$s2</td>\n";
    print "$s1</tr>\n";
  
    # Print days for which there are products
    print "$s1<tr>\n";
    for $year (sort keys %dates) {
     for $month (sort keys %{$dates{$year}}) {
      for $day (sort keys %{$dates{$year}{$month}}) {
       $colspan = keys %{$dates{$year}{$month}{$day}};
       $smonth = $NUMTOMONTH[$month];
       print "$s2<td  bgcolor=$HCOLOR colspan=$colspan align=center>\n";
       print "$s3<b>$day $smonth $year</b>\n";
       print "$s2</td>\n";
      }
     }
    }
    print "$s1</tr>\n";
  }

  print "$s0</table>\n";
}


#
# Print prev/next and choose tag
#
sub print_arrows {
  local($param_str,$param,$value,%list) = @_;

  @alist = sort keys %list;
  $count=0;
  for (@alist) { last if(/$value/); $count++}
  $prev = $count > 0 ? $alist[$count - 1] : "";
  $next = $count < $#alist ? $alist[$count + 1] : "";
  print "<table border=0 cellspacing=3><tr valign=baseline><td>\n";
  print "<a href=\"$THIS_CGIDIR/$PROGRAM?$param=$prev\">" if($prev);
  print "<img border=0 src=\"/icons/left.gif\" align=top> Previous $param_str";
  print "</a>" if($prev);
  print "</td><td>\n";
  
  #
  # Print the Choose tag
  #
  print "<form>\n";
  print "<select name=\"$param\" onChange=\"window.open('$PROGRAM?$param='+this.options[this.selectedIndex].value,'_top')\">\n";

  #print "<form method=\"POST\" ACTION=\"$PROGRAM\" onsubmit=\"window.open(this.element[0].options[this.element[0].selectedIndex].value,'_top');return(false)\">\n";
  #print "<select name=\"$param\" onChange=\"window.open(this.options[this.selectedIndex].value,'_top')\">\n";

  #print "<option>Choose $param_str\n";
  print "<option value=$value>Choose $param_str\n";
  for (@alist) { print "<option value=$_>$list{$_}</option>\n"};
  print "</select></form>\n";
  
  print "</td><td>";
  print "<a href=\"$THIS_CGIDIR/$PROGRAM?$param=$next\">" if($next);
  print "Next $param_str <img border=0 src=\"/icons/right.gif\" align=top>";
  print "</a>" if($next);
  print "</td></tr></table>\n";
}

sub prod_hash {
  local(@data) = @_;
  local($type,$prod,$pdate,$subp);
  local($year,$month,$day,$hour,$time);
  my(%products) = ();
  for (@data) {
    s/\s*$//;
    $file = $_;
    $file =~ s/.*\///;
    ($type,$prod,$pdate,$subp) = split /\./, $file,4;
#$prod =~ s/dmsp_f-\d+/dmsp/;
$subp =~ s/multisensor2\.f-\d+\./multisensor2./;
$subp =~ s/(vis|ir)\.f-\d+\./$1./;
$subp =~ s/daynight_lowcloud\.(day|term|night)\./daynight_lowcloud./;
$subp =~ s/Ron\.[\dA-F]+\./Ron./;
    $subp =~ s/\.[^\.]+$//;
    $year  = substr $pdate,0,4;
    $month = substr $pdate,4,2;
    $day   = substr $pdate,6,2;
    $hour = substr $pdate,8,2;
    $time = substr $pdate,8;
    if($hour !~ /\d/) {
      $hour = '00';
    }
    $hour = $hour.'0'x(2-length($hour));
    if($time !~ /\d/) {
      $count++;
      #$time = "????$count";
      $time = "0->";
    }
    $products{$prod}{$subp}{$year}{$month}{$day}{$hour}{$time} = $_;
  }
  return %products;
}

sub forecast_hash {
  local(@data) = @_;
  local($type,$prod,$pdate,$subp);
  local($sec,$min,$hour,$day,$month,$year,$wday,$yday,$isdst);
  my(%products) = ();
  require "timelocal.pl";

  for (@data) {
    s/\s*$//;
    $file = $_;
    $file =~ s/.*\///;

    ($type,$prod,$pdate,$subp) = split /\./, $file,4;
    if($subp =~ /^\d+_\w+/) {
      ($fhour,$subp) = split /_/, $subp,2;
    } else {
      $fhour = "0-> ";
    }

    $subp =~ s/\.[^\.]+$//;

    #
    # Convert forecast hour to date
    #
    $year = (substr $pdate,0,4) - 1900;
    $month = (substr $pdate,4,2) - 1;
    $day = substr $pdate,6,2;
    $hour = substr $pdate,8,2;
    $sec=0;$min=0;
    eval {
      ($sec,$min,$hour,$day,$month,$year,$wday,$yday,$isdst) = gmtime(
            $fhour*3600 + timegm($sec,$min,$hour,$day,$month,$year));
    };
    if($@) { 
      print STDERR "date_browse: $@\n";
      next;
    }

    $year+=1900;
    $month = sprintf("%2.2d",$month+1);
    $day = sprintf("%2.2d",$day);
    $hour = sprintf("%2.2d",$hour);

    # 
    # Save forecast dates and model info in hash.
    #
    $time = substr $pdate,8;
    if($time !~ /\d/) {
      $count++;
      #$time = "????$count";
      $time = "0->";
    }
    $products{"$prod;$pdate"}{$subp}{$year}{$month}{$day}{$hour}{$time} = "$_;$fhour";
  }
  return %products;
}
