
# JStrack:  copyright 1997/2010 by Jim Graham, N5IAL, all rights reserved.

# It's about time this filter and the ftp filter are fully integrated
# into JStrack, thus allowing easier transition to a single Windows
# executable (with standalone executables for the regular e-mail and
# ftp updates in the background, if desired).
#
# The first part of that is moving all but the exe's (or shell's) entry
# into the filter into its own file.


proc check_stormdir {} {
   global storms
   if {[file isdirectory $storms] == 0} {
      if {[file exists $storms]} {
         puts "ERROR:  Value set for \$storms ($storms)"
         puts "exists and is not a directory!"
         puts "Please check the configuration in filt.tcl and try again."
         exit 1
      } else {
         file mkdir $storms
      }
   }
}


proc debug {s} {
   global rfcdir
   # change to a 0 for normal non-debug operation
   if {1} {
      set f [open $rfcdir/debug.out a]
      puts $f $s
      close $f
   }
}

# stripzeros:  strip leading zeros from numbers (e.g., 098 --> 98)

proc stripzeros {value} {
   set retval [string trimleft $value 0]
   if {![string length $retval]} { return 0 }
   return $retval
}


proc city {city latt n long w} {
   global city_coords
   set city_coords($city) "$latt $long"
}


proc clockscan {s} {
   if {[regexp {^([012][0-9])([0-5][0-9]) ([AP]M [A-Z][DS]T.*)$} $s a hh mm end]} {
      set s "$hh:$mm $end"
   } elseif {[regexp {^([0-9])([0-5][0-9]) ([AP]M [A-Z][DS]T.*)$} $s a hh mm end]} {
      set s "$hh:$mm $end"
   }
   return [clock scan $s]
}


proc filter_prob {sts st_type name advno nodelist nmidx} {
   global storms city_coords

   set tsidx [expr $nmidx + 2]
   set tsline [lindex $nodelist $tsidx]
   set ts [clock format [clockscan $tsline] -format "%d/%H%MZ" -gmt true]

   set idx [lsearch -regexp $nodelist "^LOCATION  *A  *B  *C"]
   incr idx
   set more 1
   while {$more} {
      incr idx
      set line [lindex $nodelist $idx]
      if {[string compare $line ""]} {
         lappend filterme [string range $line 0 31]
         set part2 [string range $line 35 end]
         if {[string compare $part2 ""]} { lappend filterme $part2 }
      } else {
         set more 0
      }
   }
   set name [string tolower $name]
   set f [open $storms/$name.pr a]
   foreach i $filterme {
      if {[regexp {^([0-9]+\.[0-9])N *([0-9]+\.[0-9])W *([0-9X].*)} \
            $i a latt long probs]} {
         puts $f "prob_plot [string toupper $name] $ts $latt $long $probs"
      } elseif {[regexp {GULF *([0-9]+)N *([0-9]+)W *([0-9X].*)} \
            $i a latt long probs]} {
         puts $f "prob_plot [string toupper $name] $ts $latt $long $probs"
      } elseif {[regexp {^[A-Z0-9]+ *([0-9]+)N *([0-9]+)W *([0-9X].*)} \
            $i a latt long probs]} {
         set latt [expr double([stripzeros $latt]/10.0)]
         set long [expr double([stripzeros $long]/10.0)]
         puts $f "prob_plot [string toupper $name] $ts $latt $long $probs"
      } else {
         set found 0
         foreach j [array names city_coords] {
            if {[regexp "^$j *(\[0-9X].*)" $i a probs]} {
            set found 1
            puts $f \
               "prob_plot [string toupper $name] $ts $city_coords($j) $probs"
            }
         }
         if {!$found} { puts $f "# MISSING:  $i" }
      }
   }
   close $f
}


proc filt_read_advisories {{filename ""}} {
   global storms city_coords rfcdir

   check_stormdir

   array set city_coords {}
   source $rfcdir/city.list

   set type FORECAST/ADVISORY ; set ext fc
   if {$filename != ""} {
      if {[file exists $filename] == 0} {
         puts stderr "No such file:  $filename"
         return 1
      }
      set f [open $filename r]
   } else {
      set f stdin
   }

   set flist [split [read $f] \r\n]
   close $f

   array set matches {}
   set tlist [list] ; set index -1
   set inadv 0
   foreach line $flist {
      if {[regexp {.*KWNH .*[0-3][0-9][012][0-9][0-5][0-9]} $line]} {
         set inadv 0 ;# could be more REAL data...just skip this one
      }
      if {[regexp {.*KNHC .*[0-3][0-9][012][0-9][0-5][0-9]} $line]} {
         if {$index >= 0} {
            set matches($index) $tlist ; lappend indexlist $index
         }
         incr index
         set inadv 1
         set tlist [list $line]
      } elseif {[regexp {^To unsubscribe from WX-ATLAN} $line]} { set inadv 0
      } elseif {[regexp {^\+-\+-\+-\+-\+-\+-\+-\+-\+-}  $line]} { set inadv 0
      } elseif {$inadv} { lappend tlist $line
      }
   }
   if {$index >= 0} {
      set matches($index) $tlist ; lappend indexlist $index
   }

   if {![info exists indexlist]} { puts stderr "Could not find any NHC data" ; return 1 }


   foreach i $indexlist {
      set found_vitals 0
      for {set counter 0} {$counter < 8 && $found_vitals == 0} {incr counter} {
         set vitals [lindex $matches($i) $counter]
         if       {[regexp "^EXTRATROPICAL STORM" $vitals]} { set found_vitals $counter
         } elseif {[regexp "^SUBTROPICAL STORM" $vitals]}      { set found_vitals $counter
         } elseif {[regexp "^TROPICAL DEPRESSION" $vitals]} { set found_vitals $counter
         } elseif {[regexp "^TROPICAL STORM" $vitals]}      { set found_vitals $counter
         } elseif {[regexp "^HURRICANE" $vitals]}           { set found_vitals $counter
         }
      }

      if {$found_vitals == 0} { set vitals "" }
      set ntlist [get_storm_name $vitals]
      set st_type [lindex $ntlist 0]
      if {[regexp "NUMBER *(\[0-9]+\[A-Z]*)" $vitals a advno] == 0} {
         set advno XX
      }
      if {$st_type != "SKIP"} {
         set name [lindex $ntlist 1]
         if {[string first "FORECAST/ADVISORY" $vitals] > 0} {
            filter_advisories $i $st_type $name $advno $matches($i)
            set type fc
         } else {
            if {[string first "ADVISORY" $vitals] > 0} {
               set type adv
            } elseif {[string first "PROBABILITIES" $vitals] > 0} {
               filter_prob $i $st_type $name $advno $matches($i) $found_vitals
               set type prob
            } elseif {[string first "DISCUSSION" $vitals] > 0} {
               set type dis
            } elseif {[string first "POSITION ESTIMATE" $vitals] > 0} {
               filter_pos_est $i $st_type $name $matches($i) $found_vitals
               set type POS_EST
            }
         }
         if {$type != "POS_EST"} {
         store_advisories $matches($i) $type $name
         }
      }
   }
}


proc set_lock {name} {
#  global storms tclx_library lockptr
#  if {[info exists tclx_library]} {
#     if {[file isdirectory $storms/locks] == 0} {
#        file mkdir $storms/locks
#     }
#     set lockptr [open $storms/locks/$name a]
#     flock -write $lockptr
#  }
}

proc set_unlock {name} {
#  global tclx_library lockptr
#  if {[info exists tclx_library]} {
#     funlock $lockptr
#     close $lockptr
#  }
}


# Write to the storm.trk file (with locking *IF* under TclX)

proc filter_advisories {sts storm_type name advno nodelist} {
   global storms rfcdir tcl_platform

   set_lock $name
   set name [string tolower $name]
   set f [open $name.tmp w]
   foreach line $nodelist { puts $f "$line" }
   close $f

   source $rfcdir/read_fc.tcl
   find_fc_data $name.tmp $storms/$name.trk

   file delete $name.tmp
   set_unlock $name
}

# Write to the storm.trk file (with locking *IF* under TclX) for position
# estimates.  If we can't figure out the right timestamp, give up....

proc filter_pos_est {i st_type name nodelist nmidx} {
   global storms

   set tsidx [expr $nmidx + 2]
   set name [string tolower $name]
   set time [lindex $nodelist $nmidx]
   if {[catch {
      set timestamp [clock format [clockscan $time] -format %d/%H%MZ -gmt true]
   }]} {
      set timeb_idx [lsearch -regexp $nodelist {AT [0-9]+ [AP]M}]
      set timeb [lindex $nodelist $timeb_idx]
      regexp {AT ([0-9]+ [AP]M [A-Z][DS]T)} $timeb a hour
      set dl [split $time " "]
      if {[catch {
set time "$hour [lindex $dl 3] [lindex $dl 4] [lindex $dl 5] [lindex $dl 6]"
      set timestamp [clock format [clockscan $time] -format %d/%H%MZ -gmt true]
      }]} { return }
   }

   set latidx [lsearch -regexp $nodelist {LATITUDE [^ ]+ NORTH}]
   set lngidx [lsearch -regexp $nodelist {LONGITUDE [^ ]+ WEST}]

   if {$latidx > 0 && $lngidx > 0} {
      set latstr [lindex $nodelist $latidx]
      set lngstr [lindex $nodelist $lngidx]
      regexp {LATITUDE ([^ ]+) NORTH} $latstr a latt
      regexp {LONGITUDE ([^ ]+) WEST} $lngstr a long

      set_lock $name
      set f [open $storms/$name.trk a]
      puts $f "pos_est $timestamp $st_type [string toupper $name] $latt $long"
      close $f
      set_unlock $name
   }
}


# Write to storm.adv, storm.fc, etc. (with locking *IF* under TclX)

proc store_advisories {nodelist type name} {
   global storms

   if {[regexp {/} $name] || [regexp {/} $type] } {
      puts "Found corrupted data file...skipping"
   } else {
      set_lock $name
      set f [open $storms/[string tolower $name].$type a]
      foreach line $nodelist { puts $f "$line" }
      close $f
      set_unlock $name
   }
}


proc get_storm_name {line} {
   if {[regexp {^EXTRATROPICAL STORM ([^ ]+)} $line  a name] == 1} {
      set storm_type "ET"
   } elseif {[regexp {^TROPICAL DEPRESSION ([^ ]+)} $line  a name] == 1} {
      set storm_type "TD"
   } elseif {[regexp {^SUBTROPICAL STORM ([^ ]+)} $line a name] == 1} {
      set storm_type "STS"
   } elseif {[regexp {^TROPICAL STORM ([^ ]+)} $line a name] == 1} {
      set storm_type "TS"
   } elseif {[regexp {^HURRICANE ([^ ]+)} $line a name] == 1} {
      set storm_type "HR"
   } else { return [list SKIP] }
   return [list $storm_type $name]
}




