#!/bin/sh
# restart using wish \
exec wish "$0" "$@"

#=============================================================================
# Program: xsnd
# 
# This graphical user interface was created for the purpose of editing 
# quality control flags in SCSMEX sounding data.  This utility is 
# still being tested. Users are advised that some bugs may remain. 
# The program was developed by Patrick Haertel within Dr. Richard 
# H. Johnson's research group at Colorado State University with NASA
# funding. The main loop of the program comes at the end, after the 
# global variables and procedures are defined.
#
# Program was revised by Paul Ciesielski on 4/23/04 to grab station
# name and number of each sonde in the file.
# This program was written using Tcl (tickle) a scripting language
# and Tk which is an extension to Tcl which adds X-windows capabilities
# to Tcl. wishx is a shell interpreter that knows Tcl and Tk.
#
# Version 2.0:
# Program was cleaned up and improved by Rick Taft during June 2011.  Fonts
# and formatting/layout were improved.  The skewT image was upgraded from an
# XBM file format to a GIF image, and the ability to run the program in three
# different screen resolutions was added.  The global variable "imageDir"
# (see below) must be set to the location of the three skewT GIF image files:
# "skewt-s.gif" (small resolution), "skewt-m.gif" (medium resolution), and
# "skewt-l.gif" (large resolution).
#=============================================================================

# user-defined location for the three GIF skewT images (change as needed)
set imageDir "/usr/local/lib/xsnd"

# check the command line for a size request (optional; default is "small") and
# for the filename of the datafile (required)
if {$argc == 2} then {
   switch -glob [lindex $argv 0] {
      [sS]    {set size "s"}
      [mM]    {set size "m"}
      [lL]    {set size "l"}
      default {set size "bad"}
   }
   set filename [lindex $argv 1]
} elseif {$argc == 1} then {
   switch -glob [lindex $argv 0] {
      [sS]    {set size "s"; set filename ""}
      [mM]    {set size "m"; set filename ""}
      [lL]    {set size "l"; set filename ""}
      default {set size "s"; set filename [lindex $argv 0]}
   }
} else {
   set size "bad"
   set filename ""
}
if {$filename == "" || $size == "bad"} {
   puts stderr "Usage: xsnd \[s|m|l\] datafile"
   exit -1
}

# global variables that do not depend on requested size
set windPmin 100
set windPmax 1050
set maxWind 40

set skewtPt 100.0
set skewtPb 1050.0
set skewtTtl -109.2
set skewtTtr -39.6
set skewtTbl -33.6

set zoomScale 3
set zoomFlag 0
set changeFlag 0
set filter 0
# if |T - Td| < close then the dewpoint circle is plotted at half size
set close 0.8

# global variables that depend (or could depend) on requested size
switch $size {
   s {set skewtImgFile "skewt-s.gif"
      set skewtImgWidth 502
      set skewtImgHeight 488
      set skewtXmarg 10
      set skewtYmarg 10
      set skewtXl 26.0
      set skewtXr 400.0
      set skewtYt 25.5
      set skewtYb 484.0
      set skewtKeyHeight 15
      set windXlmarg 45
      set windXrmarg 10
      set defDotSize 3
      set controlPadY 15}
   m {set skewtImgFile "skewt-m.gif"
      set skewtImgWidth 753
      set skewtImgHeight 732
      set skewtXmarg 10
      set skewtYmarg 10
      set skewtXl 39.0
      set skewtXr 600.0
      set skewtYt 38.0
      set skewtYb 726.0
      set skewtKeyHeight 22
      set windXlmarg 50
      set windXrmarg 10
      set defDotSize 4
      set controlPadY 25}
   l {set skewtImgFile "skewt-l.gif"
      set skewtImgWidth 1004
      set skewtImgHeight 976
      set skewtXmarg 10
      set skewtYmarg 10
      set skewtXl 52.0
      set skewtXr 800.0
      set skewtYt 50.5
      set skewtYb 968.0
      set skewtKeyHeight 30
      set windXlmarg 50
      set windXrmarg 10
      set defDotSize 5
      set controlPadY 35}
}

set skewtWidth [expr $skewtImgWidth + 2*$skewtXmarg]
set skewtHeight [expr $skewtImgHeight + 3*$skewtYmarg + $skewtKeyHeight]
set skewtMinX [expr $defDotSize + 4]
set skewtMaxX [expr $skewtWidth + 1 - $defDotSize]
set skewtKeyX1 [expr 0.10*$skewtWidth]
set skewtKeyX2 [expr 0.22*$skewtWidth]
set skewtKeyX3 [expr 0.45*$skewtWidth]
set skewtKeyX4 [expr 0.60*$skewtWidth]
set skewtKeyX5 [expr 0.84*$skewtWidth]
set skewtKeyY [expr $skewtImgHeight + 2*$skewtYmarg + $skewtKeyHeight/2]
set skewtKeyXoff [expr 0.02*$skewtWidth]

set windWidth [expr $skewtWidth/2]
set windHeight $skewtHeight
set windXl $windXlmarg
set windXr [expr $windWidth - $windXrmarg]
set windScale [expr 0.5*($windXr - $windXl)/$maxWind]
set windX0 [expr 0.5*($windXl + $windXr)]
set windYmarg $skewtYmarg

set dotSize $defDotSize

# font info
switch $size {
   s {font create titlefont -family Helvetica -size 13 -weight bold
      font create buttonfont -family Helvetica -size 11 -weight bold
      font create labelfont -family Helvetica -size 11 -weight bold
      font create inputfont -family Helvetica -size 11 -weight normal
      font create axesfont -family Helvetica -size 9 -weight bold
      font create keyfont -family Helvetica -size 9 -weight bold}
   m {font create titlefont -family Helvetica -size 14 -weight bold
      font create buttonfont -family Helvetica -size 13 -weight bold
      font create labelfont -family Helvetica -size 13 -weight bold
      font create inputfont -family Helvetica -size 13 -weight normal
      font create axesfont -family Helvetica -size 11 -weight bold
      font create keyfont -family Helvetica -size 11 -weight bold}
   l {font create titlefont -family Helvetica -size 15 -weight bold
      font create buttonfont -family Helvetica -size 14 -weight bold
      font create labelfont -family Helvetica -size 14 -weight bold
      font create inputfont -family Helvetica -size 14 -weight normal
      font create axesfont -family Helvetica -size 13 -weight bold
      font create keyfont -family Helvetica -size 13 -weight bold}
}

# Procedures

# coordinate transformations
proc skewx {p t} {
   global skewtWidth skewtPt skewtPb skewtTtl skewtTtr skewtTbl \
          skewtXl skewtXr skewtXmarg skewtMinX skewtMaxX
   set ratio [expr (log($p) - log($skewtPt))/(log($skewtPb) - log($skewtPt))]
   # the temperature at the left boundary at p
   set tl [expr $skewtTtl + $ratio*($skewtTbl - $skewtTtl)]
   # the position relative to the nw corner (origin) of image
   set xrel [expr $skewtXl + \
                (($skewtXr - $skewtXl)/($skewtTtr - $skewtTtl))*($t - $tl)]
   set x [expr $skewtXmarg + $xrel]
   if {$x < $skewtMinX} {
      return $skewtMinX
   } elseif {$x > $skewtMaxX} {
      return $skewtMaxX
   } else {
      return $x
   }
}

proc skewy {p} {
   global skewtPt skewtPb skewtYt skewtYb skewtYmarg
   set ratio [expr (log($p) - log($skewtPt))/(log($skewtPb) - log($skewtPt))]
   set yrel [expr $skewtYt + $ratio*($skewtYb - $skewtYt)]
   return [expr $skewtYmarg + $yrel]
}

proc windx {u} {
   global windX0 windScale
   return [expr $windX0 + $windScale*$u]
}

proc windy {p} {
   return [skewy $p]
}

# pressure and wind axes and labels on both plots
proc makeAxes {} {
   global maxWind windPmin windPmax windHeight windYmarg
   .wind create text [windx 0] $windYmarg -anchor n \
      -text "u (black) and v (cyan)" -font keyfont -tags axes
   .wind create text [windx 0] $windHeight \
      -anchor s -text "m/s" -font axesfont -tags axes
   set xl [windx [expr -$maxWind]]
   set xr [windx [expr  $maxWind]]
   set yb [windy $windPmax]
   set yt [windy $windPmin]
   .wind create line $xl $yb $xl $yt -tags axes -width 1.5
   .wind create line $xr $yb $xr $yt -tags axes -width 1.5
   for {set p $windPmin} {$p <= $windPmax} {incr p 50} {
      set y [windy $p]
      .wind create line $xl $y [expr $xl - 3] $y -tags axes -width 1.5
      .wind create text [expr $xl - 5] $y -text $p -anchor e \
         -font axesfont -tags axes
   }
   .wind create line $xl $yb $xr $yb -tags axes -width 1.5
   .wind create line $xl $yt $xr $yt -tags axes -width 1.5
   set windIncr [expr $maxWind/5]
   for {set u [expr -$maxWind]} {$u <= $maxWind} {incr u $windIncr} {
      set x [windx $u]
      .wind create line $x $yb $x [expr $yb + 3] -tags axes -width 1.5
      .wind create text $x [expr $yb + 5] -text $u -anchor n \
         -font axesfont -tags axes
   }
   for {set p [expr $windPmin + 50]} {$p < $windPmax} {incr p 50} {
      set y [windy $p]
      .wind create line $xl $y $xr $y -tags axes -width 1.0 -fill gray
   }
   for {set u [expr $windIncr]} {$u < $maxWind} {incr u $windIncr} {
      set x1 [windx $u]
      set x2 [windx [expr -$u]]
      .wind create line $x1 $yb $x1 $yt -tags axes -width 1.0 -fill gray
      .wind create line $x2 $yb $x2 $yt -tags axes -width 1.0 -fill gray
   }
   set x [windx 0]
   .wind create line $x $yb $x $yt -tags axes -width 1.0
}

# The following procedures are helper functions for the procedures
# that plot the data.  Each takes a line from a sounding file
# and returns the canvas and the position on it where
# a particular observation is to be plotted in addition
# to the quality flag for the observation.
proc doT {line} {
   global dotSize filter skewtPt skewtPb
   set p [lindex $line 0]
   set t [lindex $line 2]
   set q [lindex $line 8]
   if {$t == "-999.0" || $p < $skewtPt || $p > $skewtPb} {return ""}
   if {$q > 3 && $filter == 1} {return "bad"}
   set x [skewx $p $t]
   set y [skewy $p]
   return ".skewt $x $y $q $dotSize"
}

proc zoomT {line} {
   global x1 y1 zoomScale dotSize
   set tmp [doT $line]
   if {$tmp == ""} {
      return ""
   } elseif {$tmp == "bad"} {
      return "bad"
   } else {
      set x [lindex $tmp 1]
      set y [lindex $tmp 2]
      set q [lindex $tmp 3]
      set xz [expr $zoomScale*($x - $x1)]
      set yz [expr $zoomScale*($y - $y1)]
      return ".zoom.c $xz $yz $q $dotSize"
   }
}

proc doTd {line} {
   global dotSize close filter skewtPt skewtPb
   set p [lindex $line 0]
   set t [lindex $line 2]
   set td [lindex $line 3]
   set q [lindex $line 9]
   if {$td == "-999.0" || $p < $skewtPt || $p > $skewtPb} {return ""}
   if {$q > 3 && $filter == 1} {return "bad"}
   # the position on the canvas
   set x [skewx $p $td]
   set y [skewy $p]
   if {abs($t-$td) >= $close} {
      return ".skewt $x $y $q $dotSize"
   } else {
      return ".skewt $x $y $q [expr $dotSize/2]"
   }
}

proc zoomTd {line} {
   global x1 y1 zoomScale dotSize close
   set t [lindex $line 2]
   set td [lindex $line 3]
   set tmp [doTd $line]
   if {$tmp == ""} {
      return ""
   } elseif {$tmp == "bad"} {
      return "bad"
   } else {
      set x [lindex $tmp 1]
      set y [lindex $tmp 2]
      set q [lindex $tmp 3]
      set xz [expr $zoomScale*($x - $x1)]
      set yz [expr $zoomScale*($y - $y1)]
      if {abs($t-$td) >= $close} {
         return ".zoom.c $xz $yz $q $dotSize"
      } else {
         return ".zoom.c $xz $yz $q [expr $dotSize / 2]"
      }
   }
}

proc doU {line} {
   global dotSize filter windPmin windPmax
   set p [lindex $line 0]
   set dir [lindex $line 4]
   set spd [lindex $line 5]
   set q [lindex $line 10]
   if {$dir == "-999.0" || $spd == "-999.0" || \
         $p < $windPmin || $p > $windPmax} {
      return ""
   }
   if {$q > 3 && $filter == 1} {return "bad"}
   set rad [expr (90.0 - $dir)*(2.0*3.14159265)/360.0]
   set u [expr $spd * -cos($rad)]
   set x [windx $u]
   set y [windy $p]
   return ".wind $x $y $q $dotSize"
}

proc zoomU {line} {
   global x1 y1 zoomScale dotSize
   set tmp [doU $line]
   if {$tmp == ""} {
      return ""
   } elseif {$tmp == "bad"} {
      return "bad"
   } else {
      set x [lindex $tmp 1]
      set y [lindex $tmp 2]
      set q [lindex $tmp 3]
      set xz [expr $zoomScale*($x - $x1)]
      set yz [expr $zoomScale*($y - $y1)]
      return ".zoom.c $xz $yz $q $dotSize"
   }
}

proc doV {line} {
   global dotSize filter windPmin windPmax
   set p [lindex $line 0]
   set dir [lindex $line 4]
   set spd [lindex $line 5]
   set q [lindex $line 10]
   if {$dir == "-999.0" || $spd == "-999.0" || \
         $p < $windPmin || $p > $windPmax} {
      return "" 
   }
   if {$q > 3 && $filter == 1} {return "bad"}
   set rad [expr (90.0 - $dir)*(2.0*3.14159265)/360.0]
   set v [expr $spd * -sin($rad)]
   set x [windx $v]
   set y [windy $p]
   return ".wind $x $y $q $dotSize"
}

proc zoomV {line} {
   global x1 y1 zoomScale dotSize
   set tmp [doV $line]
   if {$tmp == ""} {
      return ""
   } elseif {$tmp == "bad"} {
      return "bad"
   } else {
      set x [lindex $tmp 1]
      set y [lindex $tmp 2]
      set q [lindex $tmp 3]
      set xz [expr $zoomScale*($x - $x1)]
      set yz [expr $zoomScale*($y - $y1)]
      return ".zoom.c $xz $yz $q $dotSize"
   }
}

proc ovalColor {q} {
   return [ switch $q 1 {format white} 2 {format blue} 3 {format blue} \
            4 {format red} 5 {format red} default {format green} ]
}

# the procedues that actually plot the data
proc makeOval {can x y q dotSize} {
   return [$can create oval [expr $x - $dotSize] [expr $y - $dotSize] \
      [expr $x + $dotSize] [expr $y + $dotSize] -outline black -fill \
      [ovalColor $q] ]
}

proc plotField {s do} {
   set m [llength $s]
   set lastx ""
   for {set i 4} {$i <= $m} {incr i} {
      set tmp [$do [lindex $s $i]]
      if {$tmp == ""} {
         set lastx ""
      } elseif {$tmp != "bad"} {
         set curpt [eval makeOval $tmp]
         set can [lindex $tmp 0]
         $can bind $curpt <Button-1> "qshift $do $i"
         if {$do == "doT" || $do == "zoomT"} {
            set col 8
         } elseif {$do == "doTd" || $do == "zoomTd"} {
            set col 9
         } elseif {$do == "doU" || $do == "doV" || $do == "zoomU" \
                   || $do == "zoomV"} {
            set col 10
         }
         $can itemconfigure $curpt -tags "pos$i,$col data"
         set x [lindex $tmp 1]
         set y [lindex $tmp 2]
         if {$lastx != ""} {
           set edge [$can create line $lastx $lasty $x $y -tags data -width 1.5]
           $can lower $edge $prept
           if {$do == "doV" || $do == "zoomV"} {
              $can itemconfigure $edge -fill cyan
           } elseif {$do == "doT" || $do == "zoomT"} {
              $can itemconfigure $edge -fill red 
           } elseif {$do == "doTd" || $do == "zoomTd"} {
              $can itemconfigure $edge -fill Green
           }
         }
         set lastx $x
         set lasty $y
         set prept $curpt
      }
   }
}

proc plotSounding {s} {
   plotField $s doT
   plotField $s doTd
   plotField $s doU
   plotField $s doV
}

# procedures for constructing the zoom box and window
proc setmark {can x y} {
   global x1 y1 x2 y2 zoomFlag
   .skewt delete box
   .wind delete box
   if {$zoomFlag > 0} {destroy .zoom}
   set zoomFlag 0
   set x1 $x
   set y1 $y
   set x2 $x
   set y2 $y
}
proc drawbox {can x y} {
   global x1 y1 x2 y2
   $can delete box
   set x2 $x
   set y2 $y
   if {$x1 > $x2} {
      set tmp $x1
      set x1 $x2
      set x2 $tmp
   }
   if {$y1 > $y2} {
      set tmp $y1
      set y1 $y2
      set y2 $tmp
   }
   $can create rect $x1 $y1 $x2 $y2 -tags box
}
proc createZoom {can s} {
   global zoomScale x1 y1 x2 y2 zoomFlag
   if {$x1 != $x2 && $y1 != $y2} {
      toplevel .zoom
      frame .zoom.row
      button .zoom.dis -text "Dismiss" -font buttonfont -command \
         {set zoomFlag 0; .skewt delete box; .wind delete box; destroy .zoom}
      button .zoom.gd -text "Good" -font buttonfont -command {shiftZoom 1}
      button .zoom.qs -text "Questionable" -font buttonfont -command {shiftZoom 3}
      button .zoom.bd -text "Bad" -font buttonfont -command {shiftZoom 5}
      canvas .zoom.c -width [expr $zoomScale*($x2 - $x1)] \
         -height [expr $zoomScale*($y2 - $y1)] -relief sunken -borderwidth 2
      pack .zoom.c .zoom.row .zoom.dis -side top -padx 10 -pady 10
      pack .zoom.gd .zoom.qs .zoom.bd -in .zoom.row -side left -padx 10 -expand 1
      if {$can == ".skewt"} {
         plotField $s zoomT
         plotField $s zoomTd
         set zoomFlag 1
      } elseif {$can == ".wind"} {
         plotField $s zoomU
         plotField $s zoomV
         set zoomFlag 2
      }
   }
}

proc redraw {eraseFlag} {
   global sounding i zoomFlag
   if {$eraseFlag == 1} {
      if {$zoomFlag > 0} {
         .wind delete box
         .skewt delete box
         destroy .zoom
         set zoomFlag 0
      }   
   }
   .skewt delete data
   .wind delete data
   plotSounding $sounding($i)
   if {$zoomFlag == 1} {
      .zoom.c delete data
      plotField $sounding($i) zoomT
      plotField $sounding($i) zoomTd
   } elseif {$zoomFlag == 2} {
      .zoom.c delete data
      plotField $sounding($i) zoomU
      plotField $sounding($i) zoomV
   }
}

# the procedure that shifts the quality control flag
proc qshift {do j {to 0}} {
   global sounding i zoomFlag changeFlag filter
   if {$do == "doT" || $do == "zoomT"} {
      set col 8
   } elseif {$do == "doTd" || $do == "zoomTd"} {
      set col 9
   } elseif {$do == "doU" || $do == "doV" || $do == "zoomU" || $do == "zoomV"} {
      set col 10
   } else {
      puts stderr "qshift{}: unrecognized field"
      exit -1
   }
   set s $sounding($i)
   set line [lindex $s $j]
   set flag [lindex $line $col]
   if {$flag == 1} {
      set flag 3
   } elseif {$flag == 2 || $flag == 3} {
      set flag 5
   } elseif {$flag == 4 || $flag == 5} {
      set flag 1
   } else {
      set flag 1
   }
   if {$to > 0} {set flag $to}
   set line [lreplace $line $col $col $flag]
   set sounding($i) [lreplace $s $j $j "$line"]
   set changeFlag 1
   .skewt itemconfigure pos$j,$col -fill [ovalColor $flag]
   .wind itemconfigure pos$j,$col -fill [ovalColor $flag]
   if {$zoomFlag > 0} {
      .zoom.c itemconfigure pos$j,$col -fill [ovalColor $flag]
   }
   if {$to == 0 && $filter == 1} {redraw 0}
}

# changes the quality control flag for all points in the zoom window
proc shiftZoom {{to 0}} {
   global sounding i zoomFlag x1 x2 y1 y2
   set m [llength $sounding($i)]
   for {set j 4} {$j <= $m} {incr j} {
      set line [lindex $sounding($i) $j]
      if {$zoomFlag == 1} {
         set tmp [doT $line]
         if {$tmp != "" && $tmp != "bad"} {
            set x [lindex $tmp 1]
            set y [lindex $tmp 2]
            if {$x >= $x1 && $x <= $x2 && $y >= $y1 && $y <= $y2} { 
               qshift doT $j $to
            }
         }
         set tmp [doTd $line]
         if {$tmp != "" && $tmp != "bad"} {
            set x [lindex $tmp 1]
            set y [lindex $tmp 2]
            if {$x >= $x1 && $x <= $x2 && $y >= $y1 && $y <= $y2} { 
               qshift doTd $j $to
            }
         }
      } elseif {$zoomFlag == 2} {
         set tmp [doU $line]
         if {$tmp != "" && $tmp != "bad"} {
            set x [lindex $tmp 1]
            set y [lindex $tmp 2]
            if {$x >= $x1 && $x <= $x2 && $y >= $y1 && $y <= $y2} { 
               qshift doU $j $to
            }
         }
         set tmp [doV $line]
         if {$tmp != "" && $tmp != "bad"} {
            set x [lindex $tmp 1]
            set y [lindex $tmp 2]
            if {$x >= $x1 && $x <= $x2 && $y >= $y1 && $y <= $y2} { 
               qshift doV $j $to
            }
         }
      }
   }
   redraw 0
}

# saves the soundings to the same file from which they were read
proc save {} {
   global filename sounding n changeFlag
   set f [open "$filename" w]
   for {set i 1} {$i <= $n} {incr i} {
      set s $sounding($i)
      set m [llength $s]
      for {set j 0} {$j < $m} {incr j} {
         set line [lindex $s $j]
         if {$j < 4} {
            puts $f $line
         } else {
            puts $f [eval format {"%8s%8s%8s%8s%8s%8s%4s%3s%3s%3s%3s%8s%8s"} $line]
         }
      }
   }
   set changeFlag 0
}

proc findStation line {
   if {[llength $line] == 6} {
      return ""
   } else {
      return [lrange $line 0 0]
   }
}

proc findWMOnum line {
   if {[llength $line] == 6} {
      return [lrange $line 5 5]
   } else {
      return [string trim [lrange $line 6 6]]
   }
}

proc findDate line {
   if {[llength $line] == 6} {
      return [string trim [lrange $line 0 0]]
   } else {
      return [string trim [lrange $line 1 1]]
   }
}
proc findTime line {
   if {[llength $line] == 6} {
      return [lrange $line 1 1]
   } else {
      return [lrange $line 2 2]
   }
}

# set the date, time, station id, wmo# of the current sounding
proc setTime {} {
   global sounding i station number date time
   set line [lindex $sounding($i) 1]
   set date [findDate $line]
   set time [findTime $line]
   set station [findStation $line]
   set number [findWMOnum $line]
}

# checks to make sure changes are saved before exiting
proc safeExit {} {
   global changeFlag
   if {$changeFlag == 0} {
      exit
   } else {
      toplevel .prompt
      wm title .prompt "Warning"
      label .prompt.q -text "Save changes?" -font labelfont
      button .prompt.y -text "Yes" -font buttonfont -command {save; exit}
      button .prompt.n -text "No" -font buttonfont -command exit
      pack .prompt.q .prompt.y .prompt.n -padx 15 -pady 5
   }
}

proc newStation {} {
   global n sounding i zoomFlag station
   for {set j 1} {$j <= $n} {incr j} {
      set line [lindex $sounding($j) 1]
      if { "[findStation $line]" == "$station" } {
         set i $j
         .skewt delete data
         .wind delete data
         if {$zoomFlag > 0} {
            destroy .zoom
            set zoomFlag 0
         }
         .wind delete box
         .skewt delete box
         plotSounding $sounding($i)
      }
   }
   setTime
}

proc newNumber {} { 
   global n sounding i zoomFlag number 
   for {set j 1} {$j <= $n} {incr j} {
      set line [lindex $sounding($j) 1]
      if { "[findWMOnum $line]" == "$number" } {
         set i $j
         .skewt delete data
         .wind delete data
         if {$zoomFlag > 0} {
            destroy .zoom
            set zoomFlag 0
         }
         .wind delete box
         .skewt delete box
         plotSounding $sounding($i)
      }
   }
   setTime
}

proc newDateAndTime {} {
   global n sounding i zoomFlag time date
   for {set j 1} {$j <= $n} {incr j} {
      set line [lindex $sounding($j) 1]
      if { "[findTime $line]" == "$time" && "[findDate $line]" == "$date" } {
         set i $j
         .skewt delete data
         .wind delete data
         if {$zoomFlag > 0} {
            destroy .zoom
            set zoomFlag 0
         }
         .wind delete box
         .skewt delete box
         plotSounding $sounding($i)
      }
   }
   setTime
}

# Main Loop

# read data into array sounding()
# each element of the array is a list of lines for one sounding
set f [open "$filename"]
set n 0
gets $f line
if {[lindex $line 0] != "STN"} {
   puts stderr "unexpected format in file $filename"
   exit -1
}
while {[eof $f] == 0} {
   if {[llength $line] == 0} {
      puts stderr "encountered blank line in file $filename" 
      exit -1
   }
   if {[string compare [lindex $line 0] "STN"] == 0} {incr n}
   lappend sounding($n) $line
   gets $f line
}
close $f
puts "read in $n soundings"

# Divide the main window into three panels.  The leftmost panel
# contains the skewt, the middle is the info/control panel, and the
# right contains the wind plots.
frame .panel1
frame .panel2
frame .panel3
pack .panel1 .panel2 .panel3 -padx 10 -pady 10 -side left

# create and label canvases for skewt and wind graphs
label .skewtl -text "Skew-T log-P Diagram" -font titlefont
canvas .skewt -height $skewtHeight -width $skewtWidth -borderwidth 2 \
   -relief sunken
pack .skewtl .skewt -in .panel1 -pady 5
label .windl -text "Wind Components" -font titlefont
canvas .wind -height $windHeight -width $windWidth -borderwidth 2 -relief sunken
pack .windl .wind -in .panel3 -pady 5
makeAxes

# add skewt image to the skewt canvas
image create photo skewti -file [join [concat $imageDir $skewtImgFile] /]
.skewt create image $skewtXmarg $skewtYmarg -image skewti -anchor nw

# add skewt key info to skewt canvas
.skewt create text $skewtKeyX1 $skewtKeyY -anchor w -font keyfont \
    -text "T (red)"
.skewt create text $skewtKeyX2 $skewtKeyY -anchor w -font keyfont \
    -text "Td (green)"
makeOval .skewt $skewtKeyX3 $skewtKeyY 1 $defDotSize
.skewt create text [expr $skewtKeyX3 + $skewtKeyXoff] $skewtKeyY \
    -anchor w -font keyfont -text "Good"
makeOval .skewt $skewtKeyX4 $skewtKeyY 3 $defDotSize
.skewt create text [expr $skewtKeyX4 + $skewtKeyXoff] $skewtKeyY \
    -anchor w -font keyfont -text "Questionable"
makeOval .skewt $skewtKeyX5 $skewtKeyY 5 $defDotSize
.skewt create text [expr $skewtKeyX5 + $skewtKeyXoff] $skewtKeyY \
    -anchor w -font keyfont -text "Bad"

# when the program is started up the first sounding in the file is shown
set i 1
setTime
plotSounding $sounding($i)

# enable mouse options to create a zoom box
bind .skewt <3> "setmark .skewt %x %y"
bind .skewt <B3-Motion> "drawbox .skewt %x %y"
bind .skewt <ButtonRelease-3> {createZoom .skewt $sounding($i)}
bind .wind <3> "setmark .wind %x %y"
bind .wind <B3-Motion> "drawbox .wind %x %y"
bind .wind <ButtonRelease-3> {createZoom .wind $sounding($i)}

# the widgets in the info (middle) panel
#label .station -text [format "%s: %s" station $station]
#label .number -text [format "%s: %s" WMO# $number]
frame .soundinginfo
frame .appearance
frame .controls
pack .soundinginfo .appearance .controls -pady $controlPadY -side top \
      -in .panel2

frame .station
label .stationl -text "Station:" -font labelfont
entry .statione -width 6 -relief sunken -textvariable station -font inputfont \
     -justify center
bind .statione <Return> newStation
frame .number
label .numberl -text "WMO#:" -font labelfont
entry .numbere -width 6 -relief sunken -textvariable number -font inputfont \
     -justify center
bind .numbere <Return> newNumber
frame .date
label .datel -text "Date:" -font labelfont
entry .datee -width 7 -relief sunken -textvariable date -font inputfont \
     -justify center
bind .datee <Return> newDateAndTime
frame .time
label .timel -text "Time:" -font labelfont
entry .timee -width 5 -relief sunken -textvariable time -font inputfont \
     -justify center
bind .timee <Return> newDateAndTime
frame .chgbuttons
button .prev -text "Prev" -font buttonfont \
    -command { if {$i > 1} {incr i -1; redraw 1; setTime} }
button .next -text "Next" -font buttonfont \
    -command { if {$i < $n} {incr i; redraw 1; setTime} }
#if {[string length $station] > 0} {
  pack .station .number .date .time .chgbuttons -side top -pady 10 \
     -expand 1 -in .soundinginfo
#} else {
#  pack .number .date .time .chgbuttons -side top -pady 10 -expand 1 \
#     -in .soundinginfo
#}
pack .stationl .statione -in .station -side left
pack .numberl .numbere -in .number -side left
pack .timel .timee -in .time -side left
pack .datel .datee -in .date -side left
pack .prev .next -in .chgbuttons -side left -padx 10

frame .dotSize
label .dotSizel -text "Dot Size:" -font labelfont
entry .dotSizee -width 2 -relief sunken -textvariable dotSize -font inputfont \
     -justify center
bind .dotSizee <Return> { redraw 1 }
frame .maxWind
label .maxWindl -text "Max. Wind:" -font labelfont
entry .maxWinde -width 3 -relief sunken -textvariable maxWind -font inputfont \
     -justify center
bind .maxWinde <Return> {
   set windScale [expr 0.5*($windXr - $windXl)/$maxWind]
   .wind delete axes
   makeAxes
   redraw 1
}
frame .zoomScale
label .zoomScalel -text "Zoom Scale:" -font labelfont
entry .zoomScalee -width 2 -relief sunken -textvariable zoomScale \
     -font inputfont -justify center
bind .zoomScalee <Return> {
   if {$zoomFlag == 1} {
      destroy .zoom
      createZoom .skewt $sounding($i)
   } elseif {$zoomFlag == 2} {
      destroy .zoom
      createZoom .wind $sounding($i)
   }  
}
checkbutton .filter -text "Filter" -font labelfont -command {redraw 0}
pack .dotSize .maxWind .zoomScale .filter -side top -pady 10 \
     -expand 1 -in .appearance
pack .dotSizel .dotSizee -in .dotSize -side left
pack .maxWindl .maxWinde -in .maxWind -side left
pack .zoomScalel .zoomScalee -in .zoomScale -side left

frame .filebuttons
button .save -text "Save" -font buttonfont -command save
button .exit -text "Exit" -font buttonfont -command safeExit
button .about -text "About xsnd" -font buttonfont \
   -command {
      toplevel .ident
      wm title .ident "About xsnd"
      text .ident.t -height 14 -width 44 -relief flat
      .ident.t insert end "This program was created for the purpose    " \
                      end "of editing quality control flags in         " \
                      end "sounding data. On the plots, the dot color  " \
                      end "indicates data quality with white dots for  " \
                      end "good data, blue dots for questionable data  " \
                      end "red dots for bad data, and green dots for   " \
                      end "interpolated data. Quality can be changed   " \
                      end "by clicking on a dot with left mouse button." \
                      end "Zooming can be done with right mouse button." \
                      end "This utility is still being tested. Users   " \
                      end "are advised that some bugs may remain. The  " \
                      end "program was developed by Patrick Haertel    " \
                      end "within Dr. Richard H. Johnson's research at " \
                      end "Colorado State University with NASA funding " 
      button .ident.b -text "Dismiss" -font buttonfont -command {destroy .ident}
      pack .ident.t .ident.b -padx 20 -pady 20
   }
pack .filebuttons .about -side top -pady 10 -expand 1 -in .controls
pack .save .exit -in .filebuttons -side left -padx 10
