#!/usr/bin/env perl

use strict;
use warnings;
use File::Copy;
use Cwd;
use List::Util qw[min max];
use Capture::Tiny ':all';
 
use Tk;
use Tk::Pane;
use Tk::Photo;
use Tk::PNG;
use Tk::ProgressBar;
use Tk::LabFrame;
#use Image::Resize;

#*** Create any missing directories.

my @dirs = ( 'Output', 'State', 'Updates' );

foreach my $dir (@dirs) {
  if (! -d $dir) { 
    mkdir($dir) or die "Could not make directory $dir\n";
  }
}

#*** Launch a background process to check for and apply updates.

system( 'ViperUpdate.pl &' );

#*** Call the main routine to start the gui.

&main();


sub main {

  my ( $file, $index, $case, $pause, $pause_tmp, $draw_plots, $display_plots, 
       $fit_plots, $enable_zoom, $plot_quality, $quality_state, $lst_files,
       $requested_action, $select_index, $update_prefs,
       @run_list, @selections, @selected );

#*** Read the user preferences

  my ($prefs_ref, $keys_ref) = readPreferences( );
  my %prefs = %{$prefs_ref};
  my @keys = @$keys_ref;

#*** Recall the runlist

  my ( $run_list_ref, $selected_ref ) = &recall_runlist();
  @run_list = @$run_list_ref;
  @selected = @$selected_ref;

  my $cwd = cwd();
  my $input_dir = "$cwd/Input";

  my $in_types = [
     ['Viper Input Files',       ['.vpi']],
     ['Run List Files',          ['.lst']],
     ['All Files',        '*',           ],
  ];

  my $out_types = [
     ['Run List Files',          ['.lst']],
  ];

  my $mw = new MainWindow(-title=>"VIPER GUI");

  $mw -> geometry("+$prefs{main_window_x_offset}+$prefs{main_window_y_offset}");

#*** Output frame

  my $frm_output = $mw -> Frame();

  my $lab_output = $frm_output ->
     Label(-text=>"VIPER Output",-pady=>10);

  my $txt_output = $frm_output ->
            Scrolled( 'Text',
                     -width  => 80,
                     -height => $prefs{runlist_lines}+23,
                     -scrollbars => 'osoe' );

  my $button_clear_text = $frm_output -> Button(
    -text => "Clear\n Output",
    -command => sub{ $txt_output -> delete('0.0', 'end'); });

  my $button_quit = $frm_output -> Button(
    -text => "Quit",
    -borderwidth => 4,
    -relief => 'raised',
    -command => sub{ @selections  = $lst_files -> curselection();
                     for ( $index=0; $index<@run_list; $index++ ) {
                       $selected[$index] = 0;
                     }
                     foreach $index (@selections) {
                       $selected[$index] = 1;
                     }
                     open(FILE,"+>State/previous.lst") or die 
                          "$0:Could not open previous.lst\n";
                     for ( $index=0; $index<@run_list; $index++ ) {
                       print FILE "$run_list[$index], $selected[$index]\n";
                     }
                     close(FILE);
                     open(FILE,"+>State/main.opt") or die 
                          "$0:Could not open main.opt\n";
                     print FILE "pause $pause\n";
                     print FILE "draw_plots $draw_plots\n";
                     print FILE "display_plots $display_plots\n";
                     print FILE "fit_plots $fit_plots\n";
                     print FILE "enable_zoom $enable_zoom\n";
                     print FILE "plot_quality $plot_quality\n";
                     close(FILE);
                     exit;
                   });

  $lab_output         -> grid(-row=>1,-column=>1,-sticky=>"e");
  $button_clear_text  -> grid(-row=>1,-column=>2,-sticky=>"e");
  $txt_output         -> grid(-row=>2,-column=>1,-columnspan=>2);
  $button_quit        -> grid(-row=>3,-column=>1,-columnspan=>2);

#*** Run list frame

  my $frm_files = $mw -> Frame(-padx=>10);

  my $lab_files = $frm_files ->
     Label(-text=>"Run List",-pady=>10);

  $lst_files = $frm_files ->
            Scrolled( 'Listbox',
                     -selectmode => 'extended',
                     -exportselection => 0,
                     -height => $prefs{runlist_lines},
                     -width => 70,
                     -scrollbars => 'osoe' );
  $lst_files -> insert('end',@run_list);
  tie @run_list, "Tk::Listbox", $lst_files;
#  $lst_files -> selectionSet(@selected);
  foreach $index (@selected) {
    $lst_files -> selectionSet($index);
  }

  my $button_add = $frm_files -> Button(
    -text => "Add to\n run list",
    -command => sub{ my $new_files_ref = $mw -> 
                     getOpenFile( -title=>"Select input file(s)",
                                  -multiple=>1,
                                  -filetypes=>$in_types,
                                  -initialdir=>$input_dir );
                     my @new_files = ();
                     if ( defined $new_files_ref ) {
                       @new_files = @$new_files_ref;
                     }
                     foreach $file (@new_files) {
                       my @decomp = split('\.',$file);
                       my $ext = $decomp[$#decomp];
                       if ( $ext eq 'lst' ) {
                         open (FILE,"<$file") or die 
                           "$0:Could not open $file\n";
                         while (! eof (FILE) ) {
                           my $added_file = readline *FILE; chomp $added_file;
                           push( @run_list, $added_file );
                         }
                         close FILE;
                       } else {
                         push( @run_list, $file );
                       }
                     }
                   });

  my $button_remove = $frm_files -> Button(
    -text => "Remove selected\n files from run list",
    -command => sub{ @selections  = $lst_files -> curselection();
                     @selected = ();
                     foreach $index (@selections) {
                       push(@selected,$run_list[$index]);
                     }
                     my %in_sel = map { $_ => 1 } @selected;
                     my @subset = grep { not $in_sel{$_} } @run_list;
                     @run_list = @subset;
                   });

  my $button_save = $frm_files -> Button(
    -text => "Save\n run list",
    -command => sub{ my $save_file = $mw -> 
                     getSaveFile( -title=>"Select file to save run list",
                                  -filetypes=>$out_types,
                                  -initialdir=>$input_dir );
                      open (FILE,"+>$save_file") or die
                         "$0:Could not open $file\n";
                      foreach $file (@run_list) {
                         print FILE "$file\n";
                      }
                      close FILE;
                   });

  my $button_clear = $frm_files -> Button(
    -text => "Clear\n run list",
    -command => sub{ @run_list = (); });

  my $button_run_all = $frm_files -> Button(
    -text => "Run all",
    -command => 
      sub{ $pause_tmp = $pause;
           $requested_action = '';
           $index = 0;
           while ( $index <= $#run_list && $requested_action ne 'abort' ) {
             $lst_files -> selection('clear', 0, 'end');
             $lst_files -> selectionSet($index);
             $case = $run_list[$index];
             if ( $index == $#run_list ) { $pause_tmp = -1; }
             $requested_action = run_case( $mw, $case, $txt_output, $pause_tmp,
                                           $draw_plots, $display_plots, 
                                           $fit_plots, $enable_zoom, 
                                           $plot_quality, \%prefs );
             $index ++;
           }
           if( $requested_action eq 'return' || 
               $requested_action eq 'abort'     ) { $mw->raise; }
         });

  my $button_run_select = $frm_files -> Button(
    -text => "Run selected",
    -command => 
      sub{ @selections  = $lst_files -> curselection();
           $pause_tmp = $pause;
           $requested_action = '';
           $index = 0;
           while ( $index <= $#selections && $requested_action ne 'abort' ) {
             $select_index = $selections[$index];
             if ( $index == $#selections ) { $pause_tmp = -1; }
             $case = $run_list[$select_index];
             $requested_action = run_case( $mw, $case, $txt_output, $pause_tmp,
                                           $draw_plots, $display_plots, 
                                           $fit_plots, $enable_zoom,
                                           $plot_quality, \%prefs );
             $index ++;
           }
           if( $requested_action eq 'return' || 
               $requested_action eq 'abort'     ) { $mw->raise; }
      });

  my $button_run_next = $frm_files -> Button(
    -text => "Run next",
    -command => 
      sub{ @selections  = $lst_files -> curselection();
           if ( defined $selections[0] ) {
             $index = $selections[0];
           } else {
             $index = -1;
           }
           if ( $#selections > 1 ) {
             $frm_files -> messageBox(
               -type=>"ok",
               -message=>"More than one case is selected\n".
                         "Deselect some");
           } elsif ( $index == $#run_list ) {
             $frm_files -> messageBox(
               -type=>"ok",
               -message=>"Current selection is at the end of the list\n".
                         "There are no additional cases to run");
           } else {
             $index ++;
             $case = $run_list[$index];
             $pause_tmp = -1;
             $requested_action = run_case( $mw, $case, $txt_output, $pause_tmp,
                                           $draw_plots, $display_plots,
                                           $fit_plots, $enable_zoom,
                                           $plot_quality, \%prefs );
             $lst_files -> selection('clear', 0, 'end');
             $lst_files -> selectionSet($index);
           }
           if( $requested_action eq 'return' ) { $mw->raise; }
      });

  my ( $check_pause, $check_draw, $check_display, $check_fit_plots,
       $check_enable_zoom, $radio_medium_q, $radio_high_q );

#*** Check to make sure that ImageMagick is installed.  If not, permanently
#*** disable the high quality plot option.

  ( $pause, $draw_plots, $display_plots, $fit_plots, $enable_zoom,
    $plot_quality ) = &set_main_options();

  my $max_quality_state = 'normal';
  my ( $stdout, $stderr, $exit ) = capture{ system("convert --version"); };
  if ( $exit != 0 ) { $max_quality_state = 'disabled'; }

  $quality_state = $max_quality_state;
  if ( $draw_plots == 0 ) { $quality_state = 'disabled' };

  $check_pause = $frm_files -> Checkbutton(
    -text=>"Pause after each case", -variable=>\$pause );

  $check_draw = $frm_files -> Checkbutton(
    -text=>"Make plots", -variable=>\$draw_plots );

  $check_draw -> bind( '<ButtonRelease-1>', 
    sub{ 
         if ( $draw_plots==1 ) {
           $check_pause       -> configure( -state=>'normal' );
           $check_display     -> configure( -state=>'normal' );
           $check_fit_plots   -> configure( -state=>'normal' );
           $check_enable_zoom -> configure( -state=>'normal' );
           $radio_medium_q    -> configure( -state=>$max_quality_state );
           $radio_high_q      -> configure( -state=>$max_quality_state );
           $pause = 1;
           $display_plots = 1;
           $fit_plots = 1;
           $enable_zoom = 1;
           $quality_state = $max_quality_state;
         } else {
           $check_pause       -> configure( -state=>'disabled' );
           $check_display     -> configure( -state=>'disabled' );
           $check_fit_plots   -> configure( -state=>'disabled' );
           $check_enable_zoom -> configure( -state=>'disabled' );
           $radio_medium_q    -> configure( -state=>'disabled' );
           $radio_high_q      -> configure( -state=>'disabled' );
           $pause = 0;
           $display_plots = 0;
           $fit_plots = 0;
           $enable_zoom = 0;
           $quality_state = 'disabled';
         } 
    } );

  $check_display = $frm_files -> Checkbutton(
    -text=>"Display plots", -variable=>\$display_plots);

  $check_display -> bind( '<ButtonRelease-1>',
    sub{ if ( $display_plots==1 ) {
           $check_fit_plots -> configure( -state=>'normal' );
           $check_enable_zoom -> configure( -state=>'normal' );
           $fit_plots = 1;
           $enable_zoom = 1;
         } else {
           $check_fit_plots -> configure( -state=>'disabled' );
           $check_enable_zoom -> configure( -state=>'disabled' );
           $fit_plots = 0;
           $enable_zoom = 0;
         }
    } );

  $check_fit_plots = $frm_files -> Checkbutton(
    -text=>"Fit plots to screen", -variable=>\$fit_plots);

  $check_fit_plots -> bind( '<ButtonRelease-1>',
    sub{ if ( $fit_plots==1 ) {
           $check_enable_zoom -> configure( -state=>'normal' );
           $enable_zoom = 1;
         } else {
           $check_enable_zoom -> configure( -state=>'disabled' );
           $enable_zoom = 0;
         }
    } );

  $check_enable_zoom = $frm_files -> Checkbutton(
    -text=>"Enable plot zoom", -variable=>\$enable_zoom);

  my $space1 = $frm_files -> Label(-text=>" ",-font=>'Times 4');
  my $space2 = $frm_files -> Label(-text=>" ",-font=>'Times 4');
#  my $space2 = $frm_files -> Label(-text=>" ");

  $radio_medium_q = $frm_files -> Radiobutton(
    -text=>"Medium quality plots (fast)", 
    -value=>"medium",
    -state=>$quality_state,
    -variable=>\$plot_quality );

  $radio_high_q = $frm_files -> Radiobutton(
    -text=>"High quality plots (slower)", 
    -value=>"high",
    -state=>$quality_state,
    -variable=>\$plot_quality );

#*** New case button

  my $button_new_case = $frm_files -> Button(
    -text => "Construct a\n new case",
    -borderwidth => 4,
    -relief => 'raised',
    -command => sub{ $case = &build_case( \%prefs );
                     if (defined $case) { push(@run_list,$case); }
                   });

#*** Preferences button

  my $button_preferences = $frm_files -> Button(
    -text => "Preferences",
    -command => sub{ ($prefs_ref, $update_prefs) = getPreferences($mw);
                     if( $update_prefs eq 'true') { %prefs = %{$prefs_ref}; }
                   });

#  $lab_files          -> grid(-row=>1,-column=>1,-columnspan=>4);
  $button_add         -> grid(-row=> 1,-column=>1);
  $button_remove      -> grid(-row=> 1,-column=>2);
  $button_save        -> grid(-row=> 1,-column=>3);
  $button_clear       -> grid(-row=> 1,-column=>4);
  $lst_files          -> grid(-row=> 2,-column=>1,-columnspan=>4);
  $button_run_next    -> grid(-row=> 3,-column=>1);
  $button_run_select  -> grid(-row=> 3,-column=>2);
  $button_run_all     -> grid(-row=> 3,-column=>3);
  $space1             -> grid(-row=> 4,-column=>1);
  $check_draw         -> grid(-row=> 5,-column=>1,-sticky=>"w");
  $check_pause        -> grid(-row=> 6,-column=>1,-sticky=>"w");
  $check_display      -> grid(-row=> 7,-column=>1,-sticky=>"w");
  $check_fit_plots    -> grid(-row=> 8,-column=>1,-sticky=>"nw");
  $check_enable_zoom  -> grid(-row=> 9,-column=>1,-sticky=>"nw");
  $space2             -> grid(-row=>10,-column=>1);
  $radio_medium_q     -> grid(-row=>11,-column=>1,-sticky=>"w");
  $radio_high_q       -> grid(-row=>12,-column=>1,-sticky=>"w");
  $button_new_case    -> grid(-row=> 4,-column=>2,-rowspan=>6,-columnspan=>2);
  $button_preferences -> grid(-row=>10,-column=>2,-rowspan=>3,-columnspan=>2);

#*** Frame placement

  $frm_files       -> grid(-row=>1,-column=>1);
  $frm_output      -> grid(-row=>1,-column=>3);

  MainLoop;

}


#------------------------------------------------------------------------------
# This subroutine will allow the user to input all of the parameters used
# to define a new case.  The parameters will be written to the chosen file
# and the name of this file will be returned to the calling program.

sub build_case {

  my ( $prefs_ref ) = @_;
  my %prefs = %{$prefs_ref};

  my ( $index, $ac_id, $loading, $runway_id, 
       @ac_names, @ac_chosen, @runway_chosen );

  my ( $ac_descriptor, $ac_weight, $ac_span, $ac_speed, $ac_b0,
       $b0_ellip, $b0_non_ellip, $heading, $runway_elev );
        
  my ( $case, $ac_type, $ac_y0, $ac_z0, $runway, $surf_wind_dir,
       $surf_wind_spd, $surf_temp, $msl_pressure, $stability, $turbulence ) =
  &set_new_case_parameters();

  my $mw = new MainWindow(-title=>"Build a New Case");

  my $list_rows = int( $prefs{display_height}/50 ) + 4;

#*** Facility for entering the input file name.

  my $cwd = cwd();
  my $input_dir = "$cwd/Input";
  my $viper_input_file = "$input_dir/$case.vpi";

  my $types = [
     ['Data Files',       ['.vpi', '.dat']],
     ['All Files',        '*',            ],
  ];

  my $frm_file_entry = $mw -> Frame();

  my $lab_file_entry = $frm_file_entry -> 
    Label(-text=>'File to store input data',-pady=>5);

  my $entry_file = $frm_file_entry -> 
    Entry(-textvariable=>\$viper_input_file,-width=>55 );

  my $button_browse = $frm_file_entry -> Button(
     -text=>"Browse", -padx=>10,
     -command => sub{ $viper_input_file = $mw -> 
                      getSaveFile( -title=>"VIPER input file",
                                   -filetypes=>$types,
                                   -initialdir=>$input_dir ); });

  $lab_file_entry -> grid(-row=>1,-column=>1);
  $entry_file     -> grid(-row=>2,-column=>1);
  $button_browse  -> grid(-row=>2,-column=>2);

#*** Facility for entering the aircraft type and aircraft parameters. 
#*** This involves two frames; one for the aircraft selection listbox and 
#*** one for the aircraft parameters.

  my $frm_ac_type   = $mw -> Frame();
  my $frm_ac_params = $mw -> Frame();

  my $ac_params_txt = $frm_ac_type -> Text(-width=>30, -height=>4);


#*** Build the aircraft list for the listbox.  We do this by calling the
#*** readAircraftData routine to read the aircraft specs file.  The list
#*** is then made by joining the shortname (3 letter) and the longname 
#*** (descriptor) on each line.  Finally the option "ADD A NEW AIRCRAFT"
#*** is added to the bottom of the list.
#*** While we are at it, we find the index of the aircraft to use as a
#*** default.

  my $AircraftSpecsFile = "DataBase/AC_specs.csv";

  my( $short_ref, $long_ref, $weight_ref, $span_ref, $speed_ref, $b0_ref ) = 
    readAircraftData( "ALL", $AircraftSpecsFile );

  my @shortname = @$short_ref;
  my @longname  = @$long_ref;
  my @weight    = @$weight_ref;
  my @span      = @$span_ref;
  my @speed     = @$speed_ref;
  my @b0        = @$b0_ref;

  for ( $index=0; $index<@shortname; $index++ )
  {
    if ( $shortname[$index] eq $ac_type ) { $ac_id = $index }
    $ac_names[$index] =  $shortname[$index]." ".$longname[$index];
  };
  $index++;
  $ac_names[$index] = "ADD A NEW AIRCRAFT";

#*** Set defaults

  $ac_type       = $shortname[$ac_id];
  $ac_descriptor = $longname[$ac_id];
  $ac_weight     = $weight[$ac_id];
  $ac_span       = $span[$ac_id];
  $ac_speed      = $speed[$ac_id];
  $ac_b0         = $b0[$ac_id];
  if ( defined $ac_b0 ) {
    $loading = "non_elliptical";
  } else {
    $loading = "elliptical";
  }

  $ac_params_txt -> insert('end',"$ac_descriptor\n".
                           "wingspan=$ac_span ft\n".
                           "weight=$ac_weight lbs\n".
                           "speed=$ac_speed kt");

#*** Build the aircraft selection frame

  my $lab_ac_type = $frm_ac_type -> 
    Label( -text => "Select The Aircraft Type.\n".
                    "Use the entry at the bottom of\n".
                    "the list to add a new aircraft" );
  my $lst_ac = $frm_ac_type -> 
            Scrolled( 'Listbox',
                     -listvariable => \@ac_names,
                     -exportselection => 0,
                     -selectmode => 'single',
                     -height => $list_rows,
                     -width => 26,
                     -scrollbars => 'oe' );
  $lst_ac -> selectionSet($ac_id);

#*** Action when an aircraft is selected

  $lst_ac -> bind('<<ListboxSelect>>' => 
                 sub { @ac_chosen  = $lst_ac -> curselection();
                       $ac_id      = $ac_chosen[0];
                       if ( $ac_id > $#shortname ) {
                         ( $ac_type, $ac_descriptor, $ac_weight,
                           $ac_span, $ac_speed, $ac_b0 ) = 
                         &add_new_aircraft($AircraftSpecsFile);
                       } else {
                         $ac_type        = $shortname[$ac_id];
                         $ac_descriptor  = $longname[$ac_id];
                         $ac_weight      = $weight[$ac_id];
                         $ac_span        = $span[$ac_id];
                         $ac_speed       = $speed[$ac_id];
                         $ac_b0          = $b0[$ac_id];
                       }
                       $b0_ellip = sprintf("%3.2f",$ac_span*3.14159265/4.0);
                       $b0_non_ellip = $ac_b0;
                       if ( defined $ac_b0 ) {
                         $loading = "non_elliptical";
                       } else {
                         $loading = "elliptical";
                       }
                       $ac_params_txt -> delete('0.0','end');
                       $ac_params_txt -> insert('end',"$ac_descriptor\n".
                                                "wingspan=$ac_span ft\n".
                                                "weight=$ac_weight lbs\n".
                                                "speed=$ac_speed kt");
                     } );

  my $ac_selected_label = $frm_ac_type -> 
    Label( -text => "Selected aircraft and default parameters",
           -pady => 10 );

  $lab_ac_type       -> grid(-row=>1,-column=>1);
  $lst_ac            -> grid(-row=>2,-column=>1);
  $ac_selected_label -> grid(-row=>3,-column=>1);
  $ac_params_txt     -> grid(-row=>4,-column=>1);

#*** Build the aircraft parameters frame.

  $b0_non_ellip = $ac_b0;
  $b0_ellip     = sprintf("%3.2f",$ac_span*3.14159265/4.0);

  my $adjust_label = $frm_ac_params -> 
    Label( -text => "Adjust the parameters if desired",
           -pady => 10 );

  my $weight_label = $frm_ac_params -> 
    Label( -text => "Aircraft Weight (lb)" );
  my $weight_entry = $frm_ac_params -> Entry( -textvariable => \$ac_weight );

  my $speed_label = $frm_ac_params -> 
    Label( -text => "Aircraft Approach Speed (kt)" );
  my $speed_entry = $frm_ac_params -> Entry( -textvariable => \$ac_speed );

  my $ellip_label = $frm_ac_params -> 
    Label( -text => "Initial vortex spacing assuming\n".
                    "elliptical loading (ft)" );
  my $radio_ellip = $frm_ac_params -> 
    Radiobutton( -value => "elliptical",
                 -variable => \$loading );

  my $non_ellip_label = $frm_ac_params -> 
    Label(-text => "Initial vortex spacing assuming\n".
                   "non-elliptical loading (ft)");
  my $b0_ellip_entry = $frm_ac_params -> 
    Entry( -textvariable => \$b0_ellip, -state=>'disable' );
  my $b0_non_ellip_entry = $frm_ac_params -> 
    Entry( -textvariable => \$b0_non_ellip );
  my $radio_non_ellip = $frm_ac_params -> 
    Radiobutton( -value => "non_elliptical",
                 -variable => \$loading );

  $adjust_label           -> grid(-row=>1,-column=>2,-columnspan=>2);

  $weight_label           -> grid(-row=>2,-column=>2);
  $weight_entry           -> grid(-row=>2,-column=>3);

  $speed_label            -> grid(-row=>3,-column=>2);
  $speed_entry            -> grid(-row=>3,-column=>3);

  $radio_ellip            -> grid(-row=>4,-column=>1);
  $ellip_label            -> grid(-row=>4,-column=>2);

  $radio_non_ellip        -> grid(-row=>5,-column=>1);
  $non_ellip_label        -> grid(-row=>5,-column=>2);
  $b0_ellip_entry         -> grid(-row=>4,-column=>3);
  $b0_non_ellip_entry     -> grid(-row=>5,-column=>3);

#*** Build the runway selection frame

  my $frm_runway = $mw -> Frame();

  my $txt_runway = $frm_runway -> Text(-width=>30, -height=>4);

#*** Read the existing runway data from the data file

  my $AirportFile = "DataBase/AirportData.csv";

  my( $runway_ref, $heading_ref, $elevation_ref ) = 
    readAirportData( "ALL", $AirportFile );

  my @allRunways    = @$runway_ref;
  my @allHeadings   = @$heading_ref;
  my @allElevations = @$elevation_ref;

#*** Append an 'ADD A NEW RUNWAY' line to the bottom of the runways list

  push( @allRunways, "ADD A NEW RUNWAY" );

#*** Set the runway specified in the new_case.par file as the default

  for ( $index=0; $index<@allRunways; $index++ )
  {
    if ( $allRunways[$index] eq $runway ) { $runway_id = $index }
  };
  $runway      = $allRunways[   $runway_id];
  $heading     = $allHeadings[  $runway_id];
  $runway_elev = $allElevations[$runway_id];
  $txt_runway -> insert('end',"$runway\n".
                        "heading=$heading deg\n".
                        "elevation=$runway_elev ft\n");

#*** Add components to the frame

  my $lab_runway = $frm_runway -> 
    Label( -text => "Select The Runway.\n".
                    "Use the entry at the bottom of\n".
                    "the list to add a new runway" );
  my $lst_runway = $frm_runway -> 
            Scrolled( 'Listbox',
                     -listvariable => \@allRunways,
                     -selectmode => 'single',
                     -height => $list_rows,
                     -width => 26,
                     -scrollbars => 'oe' );
  my $lab_runway_selected = $frm_runway -> 
    Label( -text => "Selected runway and parameters",
           -pady => 10 );

#*** Action when a runway is selected

  $lst_runway -> bind('<<ListboxSelect>>' => 
                 sub { @runway_chosen  = $lst_runway -> curselection();
                       $runway_id      = $runway_chosen[0];
                       my $len1 = scalar(@allHeadings);
                       my $len2 = $#allHeadings;
                       if ( $runway_id > $#allHeadings ) {
                         ( $runway, $heading, $runway_elev ) =
                         &add_new_airport($AirportFile);
                       } else {
                         $runway      = $allRunways[   $runway_id];
                         $heading     = $allHeadings[  $runway_id];
                         $runway_elev = $allElevations[$runway_id];
                       }
                       $surf_wind_dir = $heading;
                       $txt_runway -> delete('0.0','end');
                       $txt_runway -> insert('end',"$runway\n".
                                                "heading=$heading deg\n".
                                                "elevation=$runway_elev ft\n");
                     } );

  $lst_runway -> selectionSet($runway_id);

  $lab_runway           -> grid(-row=>1,-column=>1);
  $lst_runway           -> grid(-row=>2,-column=>1);
  $lab_runway_selected  -> grid(-row=>3,-column=>1);
  $txt_runway           -> grid(-row=>4,-column=>1);

#*** Build the initial conditions frame.

  my $frm_init = $mw -> Frame();

  my $label_initial  = $frm_init ->
    Label( -text => "Aircraft initial position" );

  my $label_altitude = $frm_init -> 
    Label( -text => "Initial AGL altitude (ft)" );

  my $entry_altitude = $frm_init -> 
    Entry( -textvariable => \$ac_z0 );

  my $label_offset   = $frm_init -> 
    Label( -text => "Initial lateral offset (ft)" );

  my $entry_offset   = $frm_init -> 
    Entry( -textvariable => \$ac_y0 );

  $label_initial        -> grid(-row=>1,-column=>1);
  $label_altitude       -> grid(-row=>2,-column=>1);
  $entry_altitude       -> grid(-row=>2,-column=>2,-pady=>10);
  $label_offset         -> grid(-row=>3,-column=>1);
  $entry_offset         -> grid(-row=>3,-column=>2,-pady=>10);

#*** Build the environmental conditions frame.

  my $frm_env = $mw -> Frame();

  my $label_env = $frm_env -> 
    Label(-text=>"Environmental Conditions",-pady=>10);

  my $label_winds = $frm_env -> 
     Label( -text => "Surface Winds" );
  my $label_wind_dir = $frm_env -> 
     Label( -text => "Wind direction\n (magnetic)" );
  my $entry_wind_dir = $frm_env -> 
     Entry( -textvariable => \$surf_wind_dir );
  my $label_wind_speed = $frm_env -> 
     Label( -text => "Wind speed\n (kt)" );
  my $entry_wind_speed = $frm_env -> 
     Entry( -textvariable => \$surf_wind_spd );
  my $label_temperature = $frm_env -> 
     Label( -text => "Surface Temperature (C)" );
  my $entry_temperature = $frm_env -> 
     Entry( -textvariable => \$surf_temp );
  my $label_pressure = $frm_env -> 
     Label( -text => "MSL Pressure (mm Hg)" );
  my $entry_pressure = $frm_env -> 
     Entry( -textvariable => \$msl_pressure );

  my $lab_stab_top = $frm_env -> 
     Label(-text=>"Stability\n (buoyancy frequency, 1/s)");

  my $frm_stab = $frm_env -> Frame();

  my $lab_stab_top_right = $frm_stab    -> Label(-text=>"Neutral");
  my $lab_stab_middle_right = $frm_stab -> Label(-text=>"Average");
  my $lab_stab_bottom_right = $frm_stab -> 
     Label(-text=>"Highly Stable                 ");

  my $slider_stab = $frm_env -> Scale( -orient=>'v',
                                  -length=>230,
                                  -from=>0.0,
                                  -to=>0.02,
                                  -resolution=>0.0001,
                                  -digits=>3,
                                  -tickinterval=>0.0025,
                                  -variable=>\$stability );

  my $lab_turb_top = $frm_env -> 
     Label(-text=>"Atmospheric Turbulence\n (eddy dissipation rate, m^2/s^3)");

  my $frm_turb = $frm_env -> Frame();

  my $lab_turb_top_right = $frm_turb    -> Label(-text=>"Calm");
  my $lab_turb_middle_right = $frm_turb -> Label(-text=>"Rough");
  my $lab_turb_bottom_right = $frm_turb -> 
     Label(-text=>"Extremely Rough           ");

  my $slider_turb = $frm_env -> Scale( -orient=>'v',
                                  -length=>230,
                                  -from=>0.0,
                                  -to=>0.03,
                                  -resolution=>0.0001,
                                  -digits=>3,
                                  -tickinterval=>0.005,
                                  -variable=>\$turbulence );

  my $lab_blank = $frm_env -> Label(-text=>" ");

  $label_wind_dir        -> grid(-row=>1,-column=>2);
  $label_wind_speed      -> grid(-row=>1,-column=>3);
  $label_winds           -> grid(-row=>2,-column=>1);
  $entry_wind_dir        -> grid(-row=>2,-column=>2,-pady=>5);
  $entry_wind_speed      -> grid(-row=>2,-column=>3,-pady=>5);
  $label_temperature     -> grid(-row=>3,-column=>1);
  $entry_temperature     -> grid(-row=>3,-column=>2,-pady=>5);
  $label_pressure        -> grid(-row=>4,-column=>1);
  $entry_pressure        -> grid(-row=>4,-column=>2,-pady=>10);

  $lab_stab_top          -> grid(-row=>5,-column=>1);

  $slider_stab           -> grid(-row=>6,-column=>1,-sticky=>"e");

  $lab_stab_top_right    -> grid(-row=>1,-column=>1,-sticky=>"w");
  $lab_stab_middle_right -> grid(-row=>2,-column=>1,-sticky=>"w",-pady=>85);
  $lab_stab_bottom_right -> grid(-row=>3,-column=>1,-sticky=>"w");
  $frm_stab              -> grid(-row=>6,-column=>2);

  $lab_blank             -> grid(-row=>7,-column=>1);

  $lab_turb_top          -> grid(-row=>8,-column=>1);

  $slider_turb           -> grid(-row=>9,-column=>1,-sticky=>"e");

  $lab_turb_top_right    -> grid(-row=>1,-column=>1,-sticky=>"w");
  $lab_turb_middle_right -> grid(-row=>2,-column=>1,-sticky=>"w",-pady=>85);
  $lab_turb_bottom_right -> grid(-row=>3,-column=>1,-sticky=>"w");
  $frm_turb              -> grid(-row=>9,-column=>2);

#*** Build the save file button

  my $but_save_file = $mw -> Button(
    -text=>"Save inputs\n to file", 
    -borderwidth => 4,
    -relief => 'raised',
    -command => sub { 
      if ($loading eq "non_elliptical" and ! defined $ac_b0) {
        $mw -> messageBox(-message=>"You must supply an initial vortex ".
                           "spacing if you choose non-elliptical loading",
                           -type=>'OK',-title=>'Input Error');
      } else { if ( $loading eq "elliptical" ) { 
                 $ac_b0 = $b0_ellip;
               } else {
                 $ac_b0 = $b0_non_ellip;
               }
               &write_input_file( $viper_input_file, $ac_type, $ac_descriptor,
                                  $ac_weight, $ac_span, $ac_speed, $ac_b0, 
                                  $ac_y0, $ac_z0, $runway, $heading, 
                                  $runway_elev, $surf_wind_dir, $surf_wind_spd,
                                  $surf_temp, $msl_pressure, $stability, 
                                  $turbulence );
               destroy $mw;
      }
    });

#*** Build the close button

  my $but_close = $mw -> Button(-text=>"Close\n without saving", 
                                -borderwidth => 4,
                                -relief => 'raised',
                                -command => 
                                  sub { undef $viper_input_file;
                                        destroy $mw; } );

#*** Frame Geometry Management

  $frm_file_entry -> grid(-row=>1,-column=>1);

  $frm_ac_type    -> grid(-row=>2,-column=>1);

  $frm_ac_params  -> grid(-row=>3,-column=>1);

  $but_save_file  -> grid(-row=>1,-column=>2);

  $frm_runway     -> grid(-row=>2,-column=>2);

  $frm_init       -> grid(-row=>3,-column=>2);

  $frm_env        -> grid(-row=>1,-column=>3,-rowspan=>3);

  $but_close      -> grid(-row=>4,-column=>1,-columnspan=>3);

#*** Hang on until we distroy the window.

  $mw -> waitWindow;

  return($viper_input_file);

}

sub recall_runlist {

  my ( $cwd, $input_dir );
  my @run_list = ();
  my @selected = ();

  if (-e 'State/previous.lst') {

    open(FILE,"<State/previous.lst") or die "$0:Could not open previous.lst\n";

    my $index = -1;
    while (! eof (FILE) ) {
      my $line = readline *FILE; chomp $line;
      my ($file, $select_flag) = split ',',$line;
      if (-e $file ) {
        $index ++;
        push( @run_list, $file );
        if ( $select_flag == 1 ) { push(@selected,$index); }
      }
    }

    close FILE;

#  } else {
#    $cwd = cwd();
#    $input_dir = "$cwd/Input";
#    @run_list = ("$input_dir/Fra04_OGE_B744_001.vpi",
#                 "$input_dir/Fra04_OGE_B744_005.vpi",
#                 "$input_dir/Fra04_OGE_B744_007.vpi",
#                 "$input_dir/Fra04_OGE_B744_026.vpi" );
#    @selected = (0);
  }

  return( \@run_list, \@selected );

}

sub set_new_case_parameters {

  my ( $case, $ac_type, $ac_y0, $ac_z0, $runway, $surf_wind_dir,
       $surf_wind_spd, $surf_temp, $msl_pressure, $stability, $turbulence );

  $case          = "test";
  $ac_type       = "B744";
  $ac_y0         = 0.0;
  $ac_z0         = 1000.0;
  $runway        = "DEN_16L";
  $surf_wind_dir = 353;
  $surf_wind_spd = 0.0;
  $surf_temp     = 15;
  $msl_pressure  = 29.92;
  $stability     = 0.0105;
  $turbulence    = 0.001;

  if (-e 'State/new_case.par') {

    open(FILE,"<State/new_case.par") or die "$0:Could not open new_case.par\n";

    while (! eof (FILE) ) {
      my $line = readline *FILE; chomp $line;
      if ($line =~ m/^\s*#|^\s*$|^\s*\/|^\s*\\/) {
        next
      } else {
        my @a2 = split ' ',$line;
        if ($a2[0] eq 'case'         ) { $case          = $a2[1]; }
        if ($a2[0] eq 'ac_type'      ) { $ac_type       = $a2[1]; }
        if ($a2[0] eq 'ac_y0'        ) { $ac_y0         = $a2[1]; }
        if ($a2[0] eq 'ac_z0'        ) { $ac_z0         = $a2[1]; }
        if ($a2[0] eq 'runway'       ) { $runway        = $a2[1]; }
        if ($a2[0] eq 'surf_wind_dir') { $surf_wind_dir = $a2[1]; }
        if ($a2[0] eq 'surf_wind_spd') { $surf_wind_spd = $a2[1]; }
        if ($a2[0] eq 'surf_temp'    ) { $surf_temp     = $a2[1]; }
        if ($a2[0] eq 'msl_pressure' ) { $msl_pressure  = $a2[1]; }
        if ($a2[0] eq 'stability'    ) { $stability     = $a2[1]; }
        if ($a2[0] eq 'turbulence'   ) { $turbulence    = $a2[1]; }
      }
    }

    close FILE;

  }

  return( $case, $ac_type, $ac_y0, $ac_z0, $runway, $surf_wind_dir,
          $surf_wind_spd, $surf_temp, $msl_pressure, $stability, $turbulence );

}

sub set_main_options {

  my $pause         = 1;
  my $draw_plots    = 1;
  my $display_plots = 1;
  my $fit_plots     = 1;
  my $enable_zoom   = 1;
  my $plot_quality = 'medium';

  if (-e 'State/main.opt') {

    open(FILE,"<State/main.opt") or die "$0:Could not open main.opt\n";

    while (! eof (FILE) ) {
      my $line = readline *FILE; chomp $line;
      if ($line =~ m/^\s*#|^\s*$|^\s*\/|^\s*\\/) {
        next
      } else {
        my @a2 = split ' ',$line;
        if ($a2[0] eq 'pause'         ) { $pause          = $a2[1]; }
        if ($a2[0] eq 'draw_plots'    ) { $draw_plots     = $a2[1]; }
        if ($a2[0] eq 'display_plots' ) { $display_plots  = $a2[1]; }
        if ($a2[0] eq 'fit_plots'     ) { $fit_plots      = $a2[1]; }
        if ($a2[0] eq 'enable_zoom'   ) { $enable_zoom    = $a2[1]; }
        if ($a2[0] eq 'plot_quality'  ) { $plot_quality   = $a2[1]; }
      }
    }

    close FILE;

  }

  return( $pause, $draw_plots, $display_plots, $fit_plots, $enable_zoom,
          $plot_quality );

}


#*** This subroutine writes the case parameters to the viper input file.

sub write_input_file {

  my ( $viper_input_file, $ac_type, $ac_descriptor, $ac_weight, $ac_span,
       $ac_speed, $ac_b0, $ac_y0, $ac_z0, $runway, $heading, $runway_elev,
       $surf_wind_dir, $surf_wind_spd, $surf_temp, $msl_pressure, 
       $stability, $turbulence ) = @_;

  open (INPUT_FILE,"+>$viper_input_file") or die 
        "$0:Could not open $viper_input_file\n";

  my $col1_fmt = "%-16s";
  my $col2_int_fmt = "%-13d";
  my $col2_str_fmt = "%-13s";
  my $col2_flt_fmt = "%-13.5f";
  my $col2_exp_fmt = "%-13.5e";
  my $col3_fmt = "%-49s";

  my $dateString = localtime();

  print INPUT_FILE 
    "# This file was created by viper_gui on $dateString\n".
    "# Here we use aviation units: length in ft, speed in kt\n".
    "# pressure in in Hg, and temperature in C.\n\n";

  print INPUT_FILE sprintf("$col1_fmt $col2_int_fmt $col3_fmt\n",
    "units_flag", 1, "Units flag: 0-SI; 1-Aviation");
  print INPUT_FILE sprintf("$col1_fmt $col2_str_fmt $col3_fmt\n",
    "ac_type", $ac_type, "Four letter aircraft designator");
  print INPUT_FILE sprintf("$col1_fmt $col2_str_fmt $col3_fmt\n",
    "ac_descriptor", $ac_descriptor, "More detailed aircraft description");
  print INPUT_FILE sprintf("$col1_fmt $col2_exp_fmt $col3_fmt\n",
    "ac_weight", $ac_weight, "Aircraft weight (lb)");
  print INPUT_FILE sprintf("$col1_fmt $col2_flt_fmt $col3_fmt\n",
    "ac_span", $ac_span, "Aircraft wingspan (ft)");
  print INPUT_FILE sprintf("$col1_fmt $col2_flt_fmt $col3_fmt\n",
    "ac_speed", $ac_speed, "Aircraft speed (kt)");
  print INPUT_FILE sprintf("$col1_fmt $col2_flt_fmt $col3_fmt\n",
    "ac_b0", $ac_b0, "Initial vortex spacing (ft)");
  print INPUT_FILE sprintf("$col1_fmt $col2_flt_fmt $col3_fmt\n",
    "ac_y0", $ac_y0, "Initial aircraft offset from runway center (ft)");
  print INPUT_FILE sprintf("$col1_fmt $col2_flt_fmt $col3_fmt\n",
    "ac_z0", $ac_z0, "Initial aircraft AGL altitude (ft)");
  print INPUT_FILE sprintf("$col1_fmt $col2_str_fmt $col3_fmt\n",
    "runway", $runway, "Airport_Runway");
  print INPUT_FILE sprintf("$col1_fmt $col2_flt_fmt $col3_fmt\n",
    "heading", $heading, "Runway heading");
  print INPUT_FILE sprintf("$col1_fmt $col2_flt_fmt $col3_fmt\n",
    "runway_elev", $runway_elev, "Runway elevation (ft)");
  print INPUT_FILE sprintf("$col1_fmt $col2_int_fmt $col3_fmt\n",
    "surf_wind_dir", $surf_wind_dir, "Surface wind direction");
  print INPUT_FILE sprintf("$col1_fmt $col2_flt_fmt $col3_fmt\n",
    "surf_wind_spd", $surf_wind_spd, "Surface wind speed (kt)");
  print INPUT_FILE sprintf("$col1_fmt $col2_flt_fmt $col3_fmt\n",
    "surf_temp", $surf_temp, "Surface temperature (C)");
  print INPUT_FILE sprintf("$col1_fmt $col2_flt_fmt $col3_fmt\n",
    "msl_pressure", $msl_pressure, "Mean sea level pressure, (in Hg)");
  print INPUT_FILE sprintf("$col1_fmt $col2_exp_fmt $col3_fmt\n",
    "stability", $stability, "Brunt Vaisala frequency (1/s)");
  print INPUT_FILE sprintf("$col1_fmt $col2_exp_fmt $col3_fmt\n",
    "turbulence", $turbulence, 
    "Atmospheric eddy dissipation rate (ft^2/t^3)");

  close(INPUT_FILE);

  my @decomp = split('/',$viper_input_file);
  my ($case, $ext) = split('\.',$decomp[$#decomp]);

  open(FILE,"+>State/new_case.par") or die "$0:Could not open new_case.par\n";

  print FILE "case           $case\n";
  print FILE "ac_type        $ac_type\n";
  print FILE "ac_y0          $ac_y0\n";
  print FILE "ac_z0          $ac_z0\n";
  print FILE "runway         $runway\n";
  print FILE "surf_wind_dir  $surf_wind_dir\n";
  print FILE "surf_wind_spd  $surf_wind_spd\n";
  print FILE "surf_temp      $surf_temp\n";
  print FILE "msl_pressure   $msl_pressure\n";
  print FILE "stability      $stability\n";
  print FILE "turbulence     $turbulence\n";

  close FILE;

}

#------------------------------------------------------------------------------
# This subroutine will have the user enter data for a new aircraft

sub add_new_aircraft {

  my $filename = $_[0];

  my ( $ac_type, $ac_descriptor, $ac_weight, $ac_span, $ac_speed, $ac_b0 );

  my $mw = new MainWindow(-title=>"Enter New Aircraft Data");

  my $type_label = $mw -> 
    Label( -text => "Aircraft type\n (e.g. B744)" );
  my $type_entry = $mw -> Entry( -textvariable => \$ac_type );

  my $descriptor_label = $mw -> 
    Label( -text => "Aircraft description\n (e.g. B747-400)" );
  my $descriptor_entry = $mw -> Entry( -textvariable => \$ac_descriptor );

  my $weight_label = $mw -> 
    Label( -text => "85% of maximum landing weight (lb)" );
  my $weight_entry = $mw -> Entry( -textvariable => \$ac_weight );

  my $span_label = $mw -> 
    Label( -text => "Aircraft wingspan (ft)" );
  my $span_entry = $mw -> Entry( -textvariable => \$ac_span );

  my $speed_label = $mw -> 
    Label( -text => "Aircraft speed at 0.85*MLW (kt)" );
  my $speed_entry = $mw -> Entry( -textvariable => \$ac_speed );

  my $b0_label = $mw -> 
    Label( -text => "Initial vortex spacing assuming\n".
                    "non-elliptical loading (ft).  Leave blank\n".
                    "for elliptical loading estimate" );
  my $b0_entry = $mw -> Entry( -textvariable => \$ac_b0 );

#*** Buttons

  my $but1 = $mw -> Button(-text=>"Submit",
       -command => sub { destroy $mw; } );

#*** Geometry Management

  $type_label         -> grid(-row=>1,-column=>1);
  $type_entry         -> grid(-row=>1,-column=>2);

  $descriptor_label   -> grid(-row=>2,-column=>1);
  $descriptor_entry   -> grid(-row=>2,-column=>2);

  $weight_label       -> grid(-row=>3,-column=>1);
  $weight_entry       -> grid(-row=>3,-column=>2);

  $span_label         -> grid(-row=>4,-column=>1);
  $span_entry         -> grid(-row=>4,-column=>2);

  $speed_label        -> grid(-row=>5,-column=>1);
  $speed_entry        -> grid(-row=>5,-column=>2);

  $b0_label           -> grid(-row=>6,-column=>1);
  $b0_entry           -> grid(-row=>6,-column=>2);

  $but1 -> grid(-row=>7,-column=>2);

  $mw -> waitWindow;

  open (FILE,">>$filename") or die "$0:Could not open $filename\n";

  if ( defined $ac_b0 ) {
    print FILE sprintf( "%-7s%-26s%12.4e,%6.1f,%7.2f,%6.1f\n",
          $ac_type.",", $ac_descriptor.",", $ac_weight,
          "$ac_span, $ac_speed, $ac_b0" );
  } else {
    print FILE sprintf( "%-7s%-26s%12.4e,%6.1f,%7.2f,\n",
          $ac_type.",", $ac_descriptor.",", $ac_weight,
          $ac_span, $ac_speed );
  }

  close (FILE);

  return ( $ac_type, $ac_descriptor, $ac_weight, $ac_span, $ac_speed, $ac_b0 );

}

#------------------------------------------------------------------------------
# This subroutine will have the user enter data for a new airport

sub add_new_airport {

  my $filename = $_[0];

  my ( $runway, $heading, $elevation );

  my $mw = new MainWindow(-title=>"Enter New Airport Data");

  my $label_runway = $mw -> 
    Label( -text => "Airport_Runway\n (e.g. DEN_16L)" );
  my $entry_runway = $mw -> Entry( -textvariable => \$runway );

  my $label_heading = $mw -> 
    Label( -text => "Runway heading (magnetic)\n (e.g. 163)" );
  my $entry_heading = $mw -> Entry( -textvariable => \$heading );

  my $label_elevation = $mw -> 
    Label( -text => "Runway elevation (ft)" );
  my $entry_elevation = $mw -> Entry( -textvariable => \$elevation );

#*** Buttons

  my $but1 = $mw -> Button(-text=>"Submit",
       -command => sub { destroy $mw; } );

#*** Geometry Management

  $label_runway     -> grid(-row=>1,-column=>1);
  $entry_runway     -> grid(-row=>1,-column=>2);
  $label_heading    -> grid(-row=>2,-column=>1);
  $entry_heading    -> grid(-row=>2,-column=>2);
  $label_elevation  -> grid(-row=>3,-column=>1);
  $entry_elevation  -> grid(-row=>3,-column=>2);

  $but1             -> grid(-row=>4,-column=>2);

  $mw -> waitWindow;

#  print "after wait in add_new_airport\n";

  open (FILE,">>$filename") or die "$0:Could not open $filename\n";
  print FILE "$runway, $heading, $elevation\n";
  close (FILE);

  return ( $runway, $heading, $elevation );

}

# ===================================================== readAircraftData
sub readAircraftData
{

=pod

NAME
  readAircraftData: read and parse aircraft data file input lines

USAGE
  @output = readAircraftData( $nameShort, $filename );

DESCRIPTION
  extract aircraft data from the file $filename.

  if $nameShort eq "ALL", then ...
  return arrays of 

  1. aircraft short name
  2. aircraft long name
  3. aircraft landing weight
  4. aircraft wing span
  5. aircraft landing approach speed
  6. b0, wing-tip-vortex initial separation

  for all aircraft contained in $filename.

  if $nameShort ne "ALL", then return values for items 2-6 above for 
  the aircraft $nameShort.

  comment lines and white space are ignored in $filename

OPTIONS
  none

ARGUMENTS
  $nameShort - either the short name associated with desired aircraft OR
               "ALL" (see explanation above)
  $filename  - aircraft data filename

OUTPUT
  @output - if $nameShort eq "ALL", @output is an array of 6 pointers
            to the individual arrays containing the six items listed above.
            if $nameShort ne "ALL", @output is a five-element array,
            containing the data enumerated in 2.-6. above in the 
            DESCRIPTION section.

EXAMPLES
  Single aircraft mode -
  ($nameLong,$weight,$span,$speed,$b0) =
                  readacdata( "B747" , "aircraftLandingDataFile.txt" )

  Mode ALL
  ( $short_ref, $long_ref, $weight_ref, $span_ref, $speed_ref, $b0_ref ) =
  readAircraftData( "ALL", "aircraftLandingDataFile.txt" );
  my @shortname = @$short_ref;
  my @longname = @$long_ref;
  my @weight = @$weight_ref;
  my @span = @$span_ref;
  my @speed = @$speed_ref;
  my @b0 = @$b0_ref;

AUTHOR
  Joe Werne, 2013

=cut

  # force declaration of all variables
  use strict;

  # detect the number of arguments passed
  my ($numArgs) = $#_ + 1;

  # if number of arguments is not 2, bail.
  if ($numArgs != 2)
  {
    warn "\n";
    warn "$0: Number of arguments not equal to 2.\n";
    warn "   \$numArgs = $numArgs\n";
    warn "\n";
    warn "USAGE: \@output = readAircraftData( \$nameShort, \$filename )\n";
    exit 1;
  }

  # read input
  my ($nameShort, $filename) = @_;

  # initialize output variables
  my ($line) = "default";             # data line from $filename
  my ($nameShortInFile) = "default";  # aircraft short name in $filename
  my ($nameLong) = "default";         # aircraft long name
  my ($weight) = -9999.;              # aircraft weight
  my ($span) = -9999.;                # aircraft span
  my ($speed) = -9999.;               # aircraft speed
  my ($b0) = -9999.;                  # aircraft b0

  # define internal variables
  my (@a6);
  my (@allNameShort);
  my (@allNameLong);
  my (@allWeight);
  my (@allSpan);
  my (@allSpeed);
  my (@allB0);
  my (@sortedNameShort);
  my (@sortedNameLong);
  my (@sortedWeight);
  my (@sortedSpan);
  my (@sortedSpeed);
  my (@sortedB0);
  my (@sortOrder);
  my ($all, $i, $ii);

  # open $filename
  open (FILE,"<$filename") or die "$0:Could not open $filename\n";

  # if $shortName eq "ALL" (actually, case does not matter) ...
  if (lc $nameShort eq "all") 
  {
    $all=1
  } 
  else 
  {
    $all=0
  }

  # read and parse all lines in $filename
  while (! eof (FILE) )
  {
    # read a line from $filename
    $line = readline *FILE; chomp $line;

    # if this is a comment or header line, skip it
    if ($line =~ m/^\s*#|^\s*$|^\s*\/|^\s*\\/) 
    {
      next
    } 

    # otherwise parse the line
    else 
    {
      @a6 = split /\s*,\s*/,$line;

      # if constructing a list of ALL aircraft short names ...
      if ($all)
      {
        push(@allNameShort,$a6[0]);
        push(@allNameLong ,$a6[1]);
        push(@allWeight   ,$a6[2]);
        push(@allSpan     ,$a6[3]);
        push(@allSpeed    ,$a6[4]);
        push(@allB0       ,$a6[5]);
      }
      else
      {
        # if $nameShort matches $nameShortInFile ...
        if ($nameShort eq $a6[0])
        {
          # define output data and terminate loop
          ($nameShortInFile,$nameLong,$weight,$span,$speed,$b0) = @a6;
          last;
        }
      }
    }
  }
  close (FILE);

  if (! $all)
  {
    return ($nameLong,$weight,$span,$speed,$b0);
  };
    
  @sortOrder = 
    sort { $allNameShort[$a] cmp $allNameShort[$b] } 0 .. $#allNameShort;

  for $i ( 0 .. $#sortOrder )
  {
    $ii = $sortOrder[$i];
    $sortedNameShort[$i] = $allNameShort[$ii];
    $sortedNameLong[ $i] = $allNameLong[ $ii];
    $sortedWeight[   $i] = $allWeight[   $ii];
    $sortedSpan[     $i] = $allSpan[     $ii];
    $sortedSpeed[    $i] = $allSpeed[    $ii];
    $sortedB0[       $i] = $allB0[       $ii];
  };

  return ( \@sortedNameShort, \@sortedNameLong, \@sortedWeight,
           \@sortedSpan,      \@sortedSpeed,    \@sortedB0      );
}

# ===================================================== readAirportData
sub readAirportData
{

=pod

NAME
  readAirportData: read and parse airport data file input lines

USAGE
  @output = readAirportData( $runway, $filename );

DESCRIPTION
  extract airport data from the file $filename.

  if $runway eq "ALL", then ...
  return arrays of 

  1. airport designator/runway (e.g. DEN_16L)
  2. runway heading (degrees magnetic)
  3. touchdown zone elevation

  for all airports/runways contained in $filename.

  if $runway ne "ALL", then return values for items 2-3 above for 
  the specified $runway.

  comment lines and white space are ignored in $filename

OPTIONS
  none

ARGUMENTS
  $runway   - either the airport designator/runway (e.g. DEN_16L) OR
              "ALL" (see explanation above)
  $filename - airport data filename

OUTPUT
  @output - if $runway eq "ALL", @output is an array of 3 pointers
            to the individual arrays containing the three items listed above.
            if $runway ne "ALL", @output is a two-element array,
            containing the data enumerated in 2-3 above in the 
            DESCRIPTION section.

EXAMPLES
  Single runway mode -
  ( $runwayHeading, $runwayElevation ) =
                  readacdata( "DEN_16L" , "AirportData.txt" )

  Mode ALL
  ( $runway_ref, $heading_ref, $elevation_ref ) =
  readAirportData( "ALL", "AirportData.txt" );
  my @runway    = @$runway_ref;
  my @heading   = @$heading_ref;
  my @elevation = @$elevation_ref;

AUTHOR
  Tome Lund, Joe Werne, 2013

=cut

  # force declaration of all variables
  use strict;

  # detect the number of arguments passed
  my ($numArgs) = $#_ + 1;

  # if number of arguments is not 2, bail.
  if ($numArgs != 2)
  {
    warn "\n";
    warn "$0: Number of arguments not equal to 2.\n";
    warn "   \$numArgs = $numArgs\n";
    warn "\n";
    warn "USAGE: \@output = readAirportData( \$runway, \$filename )\n";
    exit 1;
  }

  # read input
  my ($runway, $filename) = @_;


  # initialize output variables
  my ($line) = "default";             # data line from $filename
  my ($runwayInFile) = "default";     # runway name in $filename
  my ($heading) = "default";          # runway heading
  my ($elevation) = -9999.;           # runway elevation

  # define internal variables
  my (@a3);
  my (@allRunway);
  my (@allHeading);
  my (@allElevation);
  my (@sortedRunway);
  my (@sortedHeading);
  my (@sortedElevation);
  my (@sortOrder);
  my ($all, $i, $ii);

  # open $filename
  open (FILE,"<$filename") or die "$0:Could not open $filename\n";

  # if $runway eq "ALL" (actually, case does not matter) ...
  if (lc $runway eq "all") 
  {
    $all=1
  } 
  else 
  {
    $all=0
  }

  # read and parse all lines in $filename
  while (! eof (FILE) )
  {
    # read a line from $filename
    $line = readline *FILE; chomp $line;

    # if this is a comment or header line, skip it
    if ($line =~ m/^\s*#|^\s*$|^\s*\/|^\s*\\/) 
    {
      next
    } 

    # otherwise parse the line
    else 
    {
      @a3 = split /\s*,\s*/,$line;

      # if constructing a list of ALL aircraft short names ...
      if ($all)
      {
        push(@allRunway    ,$a3[0]);
        push(@allHeading   ,$a3[1]);
        push(@allElevation ,$a3[2]);
      }
      else
      {
        # if $runway matches $runwayInFile ...
        if ($runway eq $a3[0])
        {
          # define output data and terminate loop
          ($runwayInFile,$heading,$elevation) = @a3;
          last;
        }
      }
    }
  }
  close (FILE);

  if (! $all)
  {
    return ($heading,$elevation);
  };
    
  @sortOrder = sort { $allRunway[$a] cmp $allRunway[$b] } 0 .. $#allRunway;

  for $i ( 0 .. $#sortOrder )
  {
    $ii = $sortOrder[$i];
    $sortedRunway[   $i] = $allRunway[   $ii];
    $sortedHeading[  $i] = $allHeading[  $ii];
    $sortedElevation[$i] = $allElevation[$ii];
  };

  return ( \@sortedRunway, \@sortedHeading, \@sortedElevation );

}

#------------------------------------------------------------------------------
# This subroutine will run viper and collect the output.  It will also make
# and display the plots.

sub run_case {

  my ( $mw, $inputFile, $txt_output, $pause, $draw_plots, $display_plots, 
       $fit_plots, $enable_zoom, $plot_quality, $prefs_ref ) = @_;

  my ( $base_name, $ext, $plot, $plot_size_x, $plot_size_y, $n_rows, $n_cols,
       $stdout, $stderr, $exit,
       @decomp, @plots, %limits, %sub_hash, %plot_hash );

  my %prefs = %{$prefs_ref};

  my $requested_action = '';

# Set up a progress bar

  my $x_offset = int($prefs{display_width}/3);
  my $y_offset = int($prefs{display_height}/3);

  my $top = $mw -> Toplevel(-title=>'Viper is Running');
  $top->geometry("+$x_offset+$y_offset");
  my $progress = $top->ProgressBar(-from=>0,-to=>100,-value=>10,
                                   -length=>500)->pack();
  $progress->value(10);
  $top->update;

  my $time_max;
  if( $prefs{max_t_mthd} eq 'measured' ) {
    $time_max = -1;
  } elsif( $prefs{max_t_mthd} eq 'model' ) {
    $time_max =  0;
  } else {
    $time_max = $prefs{max_t_valu};
  }

# Remove old output files

  @decomp = split('/',$inputFile);
  ($base_name, $ext) = split('\.',$decomp[$#decomp]);

  my @files_to_delete = <Output/$base_name*.png>;
  if( -e "Output/$base_name.limits" ) {
    push( @files_to_delete, "Output/$base_name.limits" );
  }
  foreach my $file (@files_to_delete) {
    unlink $file;
  }

# Run the model(s)

  my @models = ($prefs{model1}, $prefs{model2});
  my @extensions = ($prefs{ext1}, $prefs{ext2});

  for ( my $index=0; $index<$prefs{n_models}; $index++ ) {
    if( -e "Output/$base_name.$extensions[$index]" ) {
      unlink "Output/$base_name.$extensions[$index]";
    }
    ($stdout, $stderr, $exit) = 
      capture{ system( "run_viper -m $models[$index] -i $inputFile" ); };
    $txt_output -> insert('end',$stdout);
    $txt_output -> insert('end',$stderr);
    $progress->value(50);
    $top->update;
  }

# If the plots are to be displayed, determine their dimensions so they fit
# correctly on the screen.

  $progress->value(90);
  $top->update;

  if ( $display_plots == 1 ) {

    my $plot_ratio = 720/504;

#  We need to reserve some vertical space for the window controls at the top,
#  (25) the quit button at the bottom (25), border around the plots (10),
#  and for the taskbar at the bottom of the host screen (80).  For now, we
#  only reserve horizontal space for a border around the plots (10).

    my $usable_width  = $prefs{display_width}  -  10;
    my $usable_height = $prefs{display_height} - 140;

# if we are not fitting the plots to the screen, we also need to leave room
# for the scroll bar on the right.

    if( $fit_plots == 0 ) { $usable_width = $usable_width - 25; }

# if we are drawing high quality plots, make sure that two of these will fit
# the screen width, if not we will need a scroll bar at the bottom as well.

    if( $plot_quality eq 'high' and 2*720 > $usable_width ) {
      $usable_height = $usable_height - 25;
    }

#  Optimize the number of rows and columns for the grid of plots.

    if ( $fit_plots == 1 ) {

      my $plot_size_x_23 = 
        min( ($usable_width/3.0)/$plot_ratio, $usable_height/2.0 )*$plot_ratio;
      my $plot_size_x_32 = 
        min( ($usable_width/2.0)/$plot_ratio, $usable_height/3.0 )*$plot_ratio;

#      print "plot_size_x_23 = $plot_size_x_23\n";
#      print "plot_size_x_32 = $plot_size_x_32\n";

      if ( $plot_size_x_23 > $plot_size_x_32 ) {
        $n_rows = 2;
        $n_cols = 3;
        $plot_size_x = int( $plot_size_x_23 + 0.5 );
      } else {
        $n_rows = 3;
        $n_cols = 2;
        $plot_size_x = int( $plot_size_x_32 + 0.5 );
      }

    } else {

      $n_rows = 3;
      $n_cols = 2;
      if ( $plot_quality eq 'medium' ) {
        $plot_size_x = min( int($usable_width/$n_cols+0.5), 720 );
      } else {
        $plot_size_x = 720;
      }

    }

    $plot_size_y = int( $plot_size_x/$plot_ratio + 0.5 );

#    print "display_width  = $prefs{display_width}\n";
#    print "display_height = $prefs{display_height}\n";
#    print "usable_width  = $usable_width\n";
#    print "usable_height = $usable_height\n";
#    print "plot_size_x = $plot_size_x\n";
#    print "plot_size_y = $plot_size_y\n";

  } else {

    $plot_size_x = 720;
    $plot_size_y = 504;

  }

  if ( $draw_plots == 1 ) { 

#*** Read the plot limits information into the hash limits.

    unless( -e "Output/$base_name.limits" ) {
      $txt_output -> 
        insert('end'," Error: file Output/$base_name.limits not found\n");
      $txt_output -> 
        insert('end'," This probably means that the viper code crashed\n");
      $progress->value(95);
      $top->update;
      $top->destroy;
      return( 'abort' );
    }

    open FILE, "Output/$base_name.limits" or die $!;

    while (<FILE>) {
      chomp;
      my( $key, $value ) = split ' ';
      $limits{$key} = $value;
    };
    close FILE;

#*** Fill out the substitute hash with the limits processed according to
#*** the user preferences.

    $sub_hash{CASE} = $limits{case};
    ($sub_hash{TITLE} = $limits{case}) =~ s/_/-/g;
    $sub_hash{B0} = $limits{b0};
    $sub_hash{V0} = $limits{v0};
    $sub_hash{Z0} = $limits{z0};
    my $bump = 0.0;
    my $time_max;
    if( $prefs{max_t_mthd} eq 'measured' ) { 
      if( $limits{meas_time_max} == 0 ) {
        $time_max = $limits{modl_time_max};
      } else {
        $time_max = $limits{meas_time_max};
      }
      $sub_hash{TMAX} = &my_round( $time_max, $prefs{max_t_step}, 1, 0 );
    } elsif( $prefs{max_t_mthd} eq 'model' ) { 
      $sub_hash{TMAX} = &my_round( $limits{modl_time_max},
                                   $prefs{max_t_step}, 1, -0.01 );
    } else {
      $sub_hash{TMAX} = $prefs{max_t_valu};
    }
    if( $prefs{min_y_mthd} eq 'autoscale' ) {
      if( $limits{meas_y_min} == 0.0 ) {
        $sub_hash{YMIN} = &my_round( $limits{modl_y_min},
                                     $prefs{min_y_step}, 0, $bump );
      } else {
        $sub_hash{YMIN} = 
          &my_round( min($limits{meas_y_min},$limits{modl_y_min}),
                     $prefs{min_y_step}, 0, $bump );
      }
    } else {
      $sub_hash{YMIN} = $prefs{min_y_valu};
    }
    if( $prefs{max_y_mthd} eq 'autoscale' ) {
      if( $limits{meas_y_max} == 0.0 ) {
        $sub_hash{YMAX} = &my_round( $limits{modl_y_max},
                                     $prefs{max_y_step}, 1, $bump );
      } else {
        $sub_hash{YMAX} =
          &my_round( max($limits{meas_y_max},$limits{modl_y_max}),
                     $prefs{max_y_step}, 1, $bump );
      }
    } else {
      $sub_hash{YMAX} = $prefs{max_y_valu};
    }
    if( $prefs{min_z_mthd} eq 'autoscale' ) {
      if( $limits{meas_z_min} == 0.0 ) {
        $sub_hash{ZMIN} = &my_round( $limits{modl_z_min},
                                     $prefs{min_z_step}, 0, $bump );
      } else {
        $sub_hash{ZMIN} = 
          &my_round( min($limits{meas_z_min},$limits{modl_z_min}),
                     $prefs{min_z_step}, 0, $bump );
      }
    } else {
      $sub_hash{ZMIN} = $prefs{min_z_valu};
    }
    if( $prefs{max_z_mthd} eq 'autoscale' ) {
      if( $limits{meas_z_max} == 0.0 ) {
        $sub_hash{ZMAX} = &my_round( $limits{modl_z_max},
                                     $prefs{max_z_step}, 1, $bump );
      } else {
        $sub_hash{ZMAX} = 
          &my_round( max($limits{meas_z_max},$limits{modl_z_max}),
                     $prefs{max_z_step}, 1, $bump );
      }
    } else {
      $sub_hash{ZMAX} = $prefs{max_z_valu};
    }
    if( $prefs{min_c_mthd} eq 'autoscale' ) {
      if( $limits{meas_cir_min} == 0.0 ) {
        $sub_hash{CIRMIN} = &my_round( $limits{modl_cir_min},
                                       $prefs{min_c_step}, 0, $bump );
      } else {
        $sub_hash{CIRMIN} =
          &my_round( min($limits{meas_cir_min},$limits{modl_cir_min}),
                     $prefs{min_c_step}, 0, $bump );
      }
    } else {
      $sub_hash{CIRMIN} = $prefs{min_c_valu};
    }
    if( $prefs{max_c_mthd} eq 'autoscale' ) {
      if( $limits{meas_cir_max} == 0.0 ) {
        $sub_hash{CIRMAX} = &my_round( $limits{modl_cir_max},
                                       $prefs{max_c_step}, 1, $bump );
      } else {
        $sub_hash{CIRMAX} =
          &my_round( max($limits{meas_cir_max},$limits{modl_cir_max}),
                     $prefs{max_c_step}, 1, $bump );
      }
    } else {
      $sub_hash{CIRMAX} = $prefs{max_c_valu};
    }
    $sub_hash{EPSTICKS}    = $limits{epsticks};
    if( $prefs{show_instability} == 1 ) {
      $sub_hash{TTLD}    = $limits{tld};
      $sub_hash{YPTLD}   = $limits{yptld};
      $sub_hash{YSTLD}   = $limits{ystld};
      $sub_hash{YTLD}    = min($limits{yptld},$limits{ystld});
      $sub_hash{ZPTLD}   = $limits{zptld};
      $sub_hash{ZSTLD}   = $limits{zstld};
      $sub_hash{ZTLD}    = min($limits{zptld},$limits{zstld});
      $sub_hash{CIRTLD}  = $limits{cirtld};
      $sub_hash{TTSSD}   = $limits{tssd};
      $sub_hash{YPTSSD}  = $limits{yptssd};
      $sub_hash{YSTSSD}  = $limits{ystssd};
      $sub_hash{YTSSD}   = min($limits{yptssd},$limits{ystssd});
      $sub_hash{ZPTSSD}  = $limits{zptssd};
      $sub_hash{ZSTSSD}  = $limits{zstssd};
      $sub_hash{ZTSSD}   = min($limits{zptssd},$limits{zstssd});
      $sub_hash{CIRTSSD} = $limits{cirtssd};
    } else {
      $sub_hash{TTLD}    = 0;
      $sub_hash{YPTLD}   = 0;
      $sub_hash{YSTLD}   = 0;
      $sub_hash{YTLD}    = $sub_hash{YMIN};
      $sub_hash{ZPTLD}   = 0;
      $sub_hash{ZSTLD}   = 0;
      $sub_hash{ZTLD}    = $sub_hash{ZMIN};
      $sub_hash{CIRTLD}  = $sub_hash{CIRMIN};
      $sub_hash{TTSSD}   = 0;
      $sub_hash{YPTSSD}  = 0;
      $sub_hash{YSTSSD}  = 0;
      $sub_hash{YTSSD}   = $sub_hash{YMIN};
      $sub_hash{ZPTSSD}  = 0;
      $sub_hash{ZSTSSD}  = 0;
      $sub_hash{ZTSSD}   = $sub_hash{ZMIN};
      $sub_hash{CIRTSSD} = $sub_hash{CIRMIN};
    }
    $sub_hash{EXT1} = $prefs{ext1};
    $sub_hash{EXT2} = $prefs{ext2};
    $sub_hash{LAB1} = $prefs{lab1};
    $sub_hash{LAB2} = $prefs{lab2};

#*** Define the list of plots based on the user preferences.

    @plots = ('circ', 'y', 'z', 'N', 'wind', 'edr' );
    if( $prefs{y_plot_choice} eq 'traj' ) { $plots[1] = 'traj'; }

    for ( my $index=0; $index<@plots; $index++ ) {
      $plot_hash{$plots[$index]} = "Output/$base_name"."_$plots[$index].png";
    }
    $plot_hash{'temp'} = "Output/$base_name"."_temp.png";
    if( $prefs{y_plot_choice} eq 'traj' ) {
      $plot_hash{'y'} = "Output/$base_name"."_y.png";
    } else {
      $plot_hash{'traj'} = "Output/$base_name"."_traj.png";
    }

#*** Now make the plots.

    &make_plots( \@plots, \%sub_hash, $plot_size_x, $plot_size_y, 
                 $plot_quality, $base_name, \%prefs );

  }

  $progress->value(95);
  $top->update;
  $top->destroy;

  if ( $display_plots == 1 ) { 

    foreach my $plot ( @plots ) {
      unless( -e $plot_hash{$plot} ) {
        $txt_output ->
          insert('end'," Error: file $plot_hash{$plot} not found\n");
        $txt_output ->
          insert('end'," This probably means that the viper code crashed\n");
        return( 'abort' );
      }
    }

    $requested_action = 
      show_plots( $mw, $base_name, \%plot_hash, \%sub_hash, $pause, 
                  $plot_size_x, $plot_size_y, $plot_quality, $n_rows, $n_cols, 
                  $enable_zoom, \%prefs );
  }

  return( $requested_action )

}

#------------------------------------------------------------------------------
# Utility to round the plot limits

sub my_round {

#  x    is the input value to be rounded
#  inc  is the tic size
#  bias is 1 for rounding up, 0 for rounding down
#  bump is a factor between [0,1] used to add a cushion to the rounded value.
#
#  if if bump=0.0 then (x,inc,bias,bump)=(17,10,1,0.0) rounds to 20
#  if if bump=0.3 then (x,inc,bias,bump)=(17,10,1,0.3) rounds to 30
#  The use of bump for rounding down close to zero may not produce the expected
#  result since the int() function handles negative values in an inconsistent
#  way.  Switching to the floor() function 'use POSIX qw(floor)' will fix this.
#  The current configuration has the advantage that it will not round a
#  positive value below zero so the int() function is retained.  Although this 
#  routine works, I think the logic could be improved.

  my ($x, $inc, $bias, $bump) = @_;

  my $rounded;

  if( $bias == 0 && $x < 0 ) {
    $bias = -1.0;
    $bump = -1.0*$bump;
  }

  if( $bias == 1 && $x < 0 ) { $bias = 0.0; }

  if( $bias == 0 && $x > 0 ) { $bump = -1.0*$bump; }

  if( $inc == 0.0 ) {
     $rounded = $x;
  } else {
     $rounded = ( int( $x/$inc + $bump ) + $bias )*$inc;
  }

#  print "$x, $inc, $bias, $bump, $rounded\n";

  return($rounded);

}
#------------------------------------------------------------------------------
# This subroutine makes the plots

sub make_plots{

  my ( $plot_ref, $sub_ref, $plot_size_x, $plot_size_y, $plot_quality,
       $base_name, $prefs_ref ) = @_;

  my @plots = @$plot_ref;
  my %sub_hash = %{$sub_ref};
  my %prefs = %{$prefs_ref};

  my( $plot, $infile, $outfile, $key, $value, $output,
      @templates, %template_file );

  my $src_ext;
  if ( $plot_quality eq 'high' ) {
    $src_ext  = 'ps_src';
  } else {
    $src_ext  = 'png_src';
  };

  @templates = ('circ', 'y', 'traj', 'z', 'N', 'wind', 'edr', 'temp');
  foreach my $template (@templates) {
    $template_file{$template} = $template;
  }
  if( $prefs{n_models} == 2 ) {
    $template_file{circ} = 'circ2';
    $template_file{y}    = 'y2';
    $template_file{traj} = 'traj2';
    $template_file{z}    = 'z2';
  }

  my $resize = 0;
  if( $plot_size_x != 720 ) { $resize = 1; }

  $sub_hash{'SIZE'} = "$plot_size_x,$plot_size_y";
  $sub_hash{'FONT1'} = int( 15.0 - (720.0-$plot_size_x)/50.0 + 0.5) +
                       $prefs{plot_font_size_bump};
  $sub_hash{'FONT2'} = int( 13.0 - (720.0-$plot_size_x)/60.0 + 0.5) +
                       $prefs{plot_font_size_bump};
  $sub_hash{'LINEWIDTH'} = int( 15.0 - (720.0-$plot_size_x)/36.0 )/10.0;
  $sub_hash{'POINTS'} = int( 10.0 - (720.0-$plot_size_x)/72.0 )/10.0;

#*** Step through each of the source files, substituting strings for the
#*** template keys.  The edited source files will be written as $file.exe.

  chdir('Output') or die "$!";

  foreach $plot (@plots) {
    $infile  = "../Template/$template_file{$plot}.$src_ext";
    $outfile = "$plot.exe";
    open INFILE , "<$infile"  or die $!;
    open OUTFILE,"+>$outfile" or die $!;
    while (<INFILE>) {
      while ( ($key, $value) = each(%sub_hash) ) {
        $_ =~ s/$key/$value/g;
      }
      print OUTFILE $_;
    }
    close INFILE;
    close OUTFILE;
    my ($stdout, $stderr, $exit) = capture {
       system( "gnuplot $plot.exe" );
    };
#    $txt_output -> insert('end',$stdout);
#    $txt_output -> insert('end',$stderr);
#    unlink "$plot.exe";
    if ( $plot_quality eq 'high' ) {
      my ($stdout, $stderr, $exit) = capture {
         system( "convert $plot.ps -rotate 90 -quality 100 -flatten -crop 720x504+0+0 -geometry $plot_size_x"."x$plot_size_y $base_name"."_$plot.png" );
      };
#      $txt_output -> insert('end',$stdout);
#      $txt_output -> insert('end',$stderr);
      unlink "$plot.ps";
    } else {
#      if ( $resize == 1 ) {
#        my $large_plot = Image::Resize->new("$plot.png");
#        my $small_plot = $large_plot->resize($plot_size_x,$plot_size_y);
#        open( FH, ">$base_name"."_$plot"."_small.png");
#        print FH $small_plot->png();
#        close(FH);
#      }
      move( "$plot.png", "$base_name"."_$plot.png");
    };
  }

  chdir('..') or die "$!";

}

#------------------------------------------------------------------------------
# This subroutine display the output plots in a new window.

sub show_plots{

  my ( $parent_window, $base_name, $plot_hash_ref, $sub_hash_ref, $pause,
       $plot_size_x, $plot_size_y, $plot_quality, $n_rows, $n_cols, 
       $enable_zoom, $prefs_ref ) = @_;

  my %plot_hash = %{$plot_hash_ref};
  my %prefs = %{$prefs_ref};

  my $done = 0;
  my $requested_action = '';

  my $top = $parent_window -> Toplevel(-title=>"$base_name Results");

#  print "n_cols, n_rows = $n_cols, $n_rows\n";

  my $scroll_x=0;
  my $scroll_y=0;
  if ( $plot_size_x*$n_cols > $prefs{display_width}  ) { $scroll_x=1; }
  if ( $plot_size_y*$n_rows > $prefs{display_height} ) { $scroll_y=1; }

  my ( $window_width, $window_height, $pane_width, $pane_height, $scr_bar );

  $scr_bar = '';
  if ( $scroll_x == 0 ) {
    $window_width = $plot_size_x*$n_cols + 10;
    $pane_width   = $window_width;
  } else {
    $window_width = $prefs{display_width};
    $pane_width   = $window_width - 25*$scroll_y;
    $scr_bar = $scr_bar.'os';
  }

  if ( $scroll_y == 0 ) {
    $pane_height   = $plot_size_y*$n_rows + 10;
    $window_height = $pane_height + 50;
  } else {
    $window_height = $prefs{display_height} - 80;
    $pane_height   = $window_height         - 50 - 25*$scroll_x;
    $scr_bar = $scr_bar.'oe';
  }

#  print "pane_width, pane_height = $pane_width, $pane_height\n";
#  print "window_width, window_height = $window_width, $window_height\n";

  $top -> geometry("${window_width}x${window_height}".
                  "+$prefs{plot_window_x_offset}+$prefs{plot_window_y_offset}");

  my $pane;
  if( $scroll_x+$scroll_y == 0 ) {
    $pane = $top -> Frame( -width=>$pane_width, -height=>$pane_height ) -> pack;
  } else {
    $pane = $top -> 
      Scrolled('Pane', -scrollbars=>$scr_bar, -width=>$pane_width,
               -height=>$pane_height ) -> pack;
  }

 #*** Display the plots as buttons which will zoom up the plot if clicked.

  my $zoom_state = 'disabled';
  if ( $plot_size_x < 720 && $enable_zoom == 1 ) { $zoom_state = 'normal'; }

  my $img_circ = $pane -> Photo(-file=>$plot_hash{circ});
  my $img_z    = $pane -> Photo(-file=>$plot_hash{z});
  my $img_y    = $pane -> Photo(-file=>$plot_hash{$prefs{y_plot_choice}});
  my $img_N    = $pane -> Photo(-file=>$plot_hash{N});
  my $img_wind = $pane -> Photo(-file=>$plot_hash{wind});
  my $img_edr  = $pane -> Photo(-file=>$plot_hash{edr});

  my $button_circ = $pane -> Button(-image=>$img_circ,
       -command => sub{ &zoom_plot( $top, $sub_hash_ref, $plot_hash_ref, 
        $plot_size_x, $plot_size_y, $base_name, 'circ',
        $plot_quality, $zoom_state, $prefs_ref ); } );
  my $button_z    = $pane -> Button(-image=>$img_z   ,
       -command => sub{ &zoom_plot( $top, $sub_hash_ref, $plot_hash_ref, 
        $plot_size_x, $plot_size_y, $base_name, 'z'   ,
        $plot_quality, $zoom_state, $prefs_ref ); } );
  my $button_y    = $pane -> Button(-image=>$img_y   ,
       -command => sub{ &zoom_plot( $top, $sub_hash_ref, $plot_hash_ref, 
        $plot_size_x, $plot_size_y,  $base_name, $prefs{y_plot_choice},
        $plot_quality, $zoom_state, $prefs_ref ); } );
  my $button_N    = $pane -> Button(-image=>$img_N   ,
       -command => sub{ &zoom_plot( $top, $sub_hash_ref, $plot_hash_ref, 
        $plot_size_x, $plot_size_y, $base_name, 'N'   ,
        $plot_quality, $zoom_state, $prefs_ref ); } );
  my $button_wind = $pane -> Button(-image=>$img_wind,
       -command => sub{ &zoom_plot( $top, $sub_hash_ref, $plot_hash_ref, 
        $plot_size_x, $plot_size_y, $base_name, 'wind',
        $plot_quality, $zoom_state, $prefs_ref ); } );
  my $button_edr  = $pane -> Button(-image=>$img_edr ,
       -command => sub{ &zoom_plot( $top, $sub_hash_ref, $plot_hash_ref, 
        $plot_size_x, $plot_size_y, $base_name, 'edr' ,
        $plot_quality, $zoom_state, $prefs_ref ); } );

  if( $n_rows == 2 ) {
    $button_circ -> grid(-row=>1,-column=>1);
    $button_z    -> grid(-row=>1,-column=>2);
    $button_y    -> grid(-row=>1,-column=>3);
    $button_N    -> grid(-row=>2,-column=>1);
    $button_wind -> grid(-row=>2,-column=>2);
    $button_edr  -> grid(-row=>2,-column=>3);
  } else {
    $button_circ -> grid(-row=>1,-column=>1);
    $button_z    -> grid(-row=>1,-column=>2);
    $button_y    -> grid(-row=>2,-column=>1);
    $button_N    -> grid(-row=>2,-column=>2);
    $button_wind -> grid(-row=>3,-column=>1);
    $button_edr  -> grid(-row=>3,-column=>2);
  }

#*** Add some buttons at the bottom

  my $button_show_temp = $top -> Button(-text=>'Show temperature',
       -command => sub{ &zoom_plot( $top, $sub_hash_ref, $plot_hash_ref, 
        $plot_size_x, $plot_size_y, $base_name, 'temp', $plot_quality,
        'normal', $prefs_ref ); } ) -> 
          pack(-side=>'left',-expand=>1);

  my $y_text = 'Show trajectory';
  my $alt_y  = 'traj';
  if( $prefs{y_plot_choice} eq 'traj' ) { 
    $y_text = 'Show y vs time';
    $alt_y  = 'y';
  }
  my $button_show_alt_y = $top -> Button(-text=>$y_text,
       -command => sub{ &zoom_plot( $top, $sub_hash_ref, $plot_hash_ref, 
        $plot_size_x, $plot_size_y, $base_name, $alt_y, $plot_quality,
        'normal', $prefs_ref ); } ) -> 
          pack(-side=>'left',-expand=>1);

  if( $pause == 1 ) {

    my $button_close_advance = $top -> Button( -text=>'Close+Advance',
         -command=>sub{ $requested_action='continue'; $done=1;
                        destroy $top;} ) -> 
            pack(-side=>'left',-expand=>1);

    my $button_save_advance = $top -> Button( -text=>'Save+Advance',
         -command=>sub{ $requested_action='continue'; $done=1; } ) ->
            pack(-side=>'left',-expand=>1);

    my $button_abort = $top -> Button( -text=>'Abort Sequence',
         -command=>sub{ $requested_action='abort'; $done=1; } ) ->
            pack(-side=>'left',-expand=>1);

    my $button_help  = $top -> Button( -text=>'Help',
      -command=>sub{ my $help_window = $top -> 
        messageBox(-type=>'ok',-title=>'Help',-message=>
          "The 'Close+Advance' button will close this window ".
          "and advance to the next case in the run sequence.\n".
          "Keyboard shortcut: 'x' key.\n\n".
          "The 'Save+Advance' button will save this window ".
          "and advance to the next case in the run sequence.\n".
          "Keyboard shortcut: 'Enter' key.\n\n".
          "The 'Abort Sequence' will abort the run sequence while ".
          "preserving the current results window.  It will also bring ".
          "the main window to the front.\n".
          "Keyboard shortcut: 'Control-c' combo.\n\n".
          "If the 'Fit plots to screen' AND the 'Enable plot zoom' boxs ".
          "are checked on the main window panel, then a full-sized image ".
          "is displayed when any plot is clicked.\n\n".
          "The temperature profile is displayed as a full-size image when ".
          "the 'Show temperature' button is clicked.") 
    } ) -> pack(-side=>'left',-expand=>1);

  } elsif( $pause == 0 ) {

    my $button_close = $top -> Button( -text=>'Close',
         -command=>sub{ destroy $top;} ) -> 
            pack(-side=>'left',-expand=>1);

    my $button_help  = $top -> Button( -text=>'Help',
      -command=>sub{ my $help_window = $top ->
        messageBox(-type=>'ok',-title=>'Help',-message=>
          "The 'Close' button will close this window.\n".
          "Keyboard shortcut: 'x' key.\n\n".
          "If the 'Fit plots to screen' AND the 'Enable plot zoom' boxs ".
          "are checked on the main window panel, then a full-sized image ".
          "is displayed when any plot is clicked.\n\n".
          "The temperature profile is displayed as a full-size image when ".
          "the 'Show temperature' button is clicked.")
    } ) -> pack(-side=>'left',-expand=>1);

   } else {   # this is when $pause=-1, which means no more cases follow

    my $button_close = $top -> Button( -text=>'Close',
         -command=>sub{ $requested_action='none'; $done=1;
                        destroy $top;} ) -> 
            pack(-side=>'left',-expand=>1);

    my $button_return = $top -> Button( -text=>'Save+Return to Main Window',
         -command=>sub{ $requested_action='return'; $done=1; } ) ->
            pack(-side=>'left',-expand=>1);

    my $button_help  = $top -> Button( -text=>'Help',
      -command=>sub{ my $help_window = $top ->
        messageBox(-type=>'ok',-title=>'Help',-message=>
          "The 'Close' button will close this window.\n".
          "Keyboard shortcut: 'x' key.\n\n".
          "The 'Save+Return to Main Window' button will save this window ".
          "and bring the main window to the front.\n".
          "Keyboard shortcut: 'Enter' key.\n\n".
          "If the 'Fit plots to screen' AND the 'Enable plot zoom' boxs ".
          "are checked on the main window panel, then a full-sized image ".
          "is displayed when any plot is clicked.\n\n".
          "The temperature profile is displayed as a full-size image when ".
          "the 'Show temperature' button is clicked.")
    } ) -> pack(-side=>'left',-expand=>1);

  }

  $top -> bind("<Control-Key-c>", sub {$requested_action='abort'; $done=1;});
  $top -> bind("<Key-x>", 
              sub{ $requested_action='continue';
                   $done=1;
                   destroy $top;
              });
  $top -> bind("<Key-Return>", 
              sub { $requested_action='continue';
                    if( $pause == -1 ) { $requested_action='return'; }
                    $done=1;
              });
  $top -> bind( "<Destroy>", sub{$requested_action='continue'; $done=1;} );

  if ( $pause != 0 ) { $top -> waitVariable(\$done); }

  if( $requested_action eq 'return' || $requested_action eq 'abort' ) {
    $parent_window->raise($top);
  }

  return( $requested_action );

  sub zoom_plot {
    my ( $parent_window, $sub_hash_ref, $plot_hash_ref, $plot_size_x, 
         $plot_size_y, $base_name, $plot, $plot_quality, $zoom_state,
         $prefs_ref ) = @_;
    if ( $zoom_state eq 'normal' ) {
      my %plot_hash = %{$plot_hash_ref};
      my @plots = ($plot);
      if ( $plot_size_x < 720 ) {
        &make_plots( \@plots, $sub_hash_ref, 720, 504, $plot_quality,
                     $base_name, $prefs_ref );
      }
      my $top = $parent_window -> Toplevel();
      my $img = $top->Photo(-file=>$plot_hash{$plot});
      my $lab = $top->Label(-image=>$img) -> pack;
      my $but = $top->Button(-text=>'Close',-command=>sub{destroy $top})->pack;
    } else {
#      $parent_window -> messageBox(-type=>'ok',
#        -message=>"Plot zoom unavailable.\n".
#                  "The plot is either currently displayed at full size or ".
#                  "the 'Enable plot zoom' box is not checked");
    }
  }

}

#-------------------------------------------------------------------------------
# Subroutine to present the user with a preferences dialog

sub getPreferences {

  my $parent_window = $_[0];

  my ( $entry_auto_min_c_state, $entry_spec_min_c_state,
       $entry_auto_max_c_state, $entry_spec_max_c_state,
       $entry_auto_min_y_state, $entry_spec_min_y_state,
       $entry_auto_max_y_state, $entry_spec_max_y_state,
       $entry_auto_min_z_state, $entry_spec_min_z_state,
       $entry_auto_max_z_state, $entry_spec_max_z_state,
       $entry_auto_max_t_state, $entry_spec_max_t_state,
       $entry_spec_display_size_state,
    );

  my $update_prefs = 'false';

  my ($prefs_ref, $keys_ref) = readPreferences($parent_window);

  my %prefs = %{$prefs_ref};
  my @keys = @$keys_ref;

  if( $prefs{min_c_mthd} eq 'autoscale' ) {
    $entry_auto_min_c_state = 'normal';
    $entry_spec_min_c_state = 'disabled';
  } else {
    $entry_auto_min_c_state = 'disabled';
    $entry_spec_min_c_state = 'normal';
  }

  if( $prefs{max_c_mthd} eq 'autoscale' ) {
    $entry_auto_max_c_state = 'normal';
    $entry_spec_max_c_state = 'disabled';
  } else {
    $entry_auto_max_c_state = 'disabled';
    $entry_spec_max_c_state = 'normal';
  }

  if( $prefs{min_y_mthd} eq 'autoscale' ) {
    $entry_auto_min_y_state = 'normal';
    $entry_spec_min_y_state = 'disabled';
  } else {
    $entry_auto_min_y_state = 'disabled';
    $entry_spec_min_y_state = 'normal';
  }

  if( $prefs{max_y_mthd} eq 'autoscale' ) {
    $entry_auto_max_y_state = 'normal';
    $entry_spec_max_y_state = 'disabled';
  } else {
    $entry_auto_max_y_state = 'disabled';
    $entry_spec_max_y_state = 'normal';
  }

  if( $prefs{min_z_mthd} eq 'autoscale' ) {
    $entry_auto_min_z_state = 'normal';
    $entry_spec_min_z_state = 'disabled';
  } else {
    $entry_auto_min_z_state = 'disabled';
    $entry_spec_min_z_state = 'normal';
  }

  if( $prefs{max_z_mthd} eq 'autoscale' ) {
    $entry_auto_max_z_state = 'normal';
    $entry_spec_max_z_state = 'disabled';
  } else {
    $entry_auto_max_z_state = 'disabled';
    $entry_spec_max_z_state = 'normal';
  }

  if( $prefs{max_t_mthd} eq 'measured' || $prefs{max_t_mthd} eq 'model' ) {
    $entry_auto_max_t_state = 'normal';
    $entry_spec_max_t_state = 'disabled';
  } else {
    $entry_auto_max_t_state = 'disabled';
    $entry_spec_max_t_state = 'normal';
  }

  if( $prefs{display_size_mthd} eq 'autodetect' ) {
    $entry_spec_display_size_state = 'disabled';
  } else {
    $entry_spec_display_size_state = 'normal';
  }

#--- Create a new toplevel to hold the preferences dialogs

  my $top = $parent_window -> Toplevel(-title=>'Preferences');

#--- All of the setting controls will go in the settings frame

  my $frm_settings = $top -> Frame() -> pack();

  my $auto_display_width  = $top->screenwidth;
  my $auto_display_height = $top->screenheight;

#--- Frame for adjusting the plot limits

  my $frm_limits = $frm_settings -> LabFrame(-label => 'Plot Limits',
                                             -labelside => 'acrosstop');
#--- Minimum Circulation

  my $frm_min_c = $frm_limits -> Frame();

  my $lab_min_c = $frm_min_c ->
       Label(-text=>"\nMinimum Circulation");

  my $frm_auto_min_c = $frm_min_c -> Frame();

  my $radio_auto_min_c = $frm_auto_min_c -> Radiobutton(
      -text=>'Autoscale, round by',
      -value=>'autoscale',
      -variable=>\$prefs{min_c_mthd} );

  my $entry_auto_min_c = $frm_auto_min_c -> Entry(
      -width=>4, -textvariable=>\$prefs{min_c_step},
      -state=>$entry_auto_min_c_state );

  $radio_auto_min_c  -> grid(-row=>1,-column=>1,-sticky=>'w');
  $entry_auto_min_c  -> grid(-row=>1,-column=>2,-sticky=>'w');

  my $frm_spec_min_c = $frm_min_c -> Frame();

  my $radio_spec_min_c = $frm_spec_min_c -> Radiobutton(
      -text=>'Specified',
      -value=>'spec',
      -variable=>\$prefs{min_c_mthd} );

  my $entry_spec_min_c = $frm_spec_min_c -> Entry(
      -width=>13, -textvariable=>\$prefs{min_c_valu},
      -state=>$entry_spec_min_c_state );

  $radio_auto_min_c -> bind( '<ButtonRelease-1>',
    sub{ if ( $prefs{min_c_mthd} eq 'autoscale' ) {
           $entry_auto_min_c -> configure( -state=>'normal'  );
           $entry_spec_min_c -> configure( -state=>'disabled');
         } else {
           $entry_auto_min_c -> configure( -state=>'disabled');
           $entry_spec_min_c -> configure( -state=>'normal'  );
         }
    } );

  $radio_spec_min_c -> bind( '<ButtonRelease-1>',
    sub{ if ( $prefs{min_c_mthd} eq 'autoscale' ) {
           $entry_auto_min_c -> configure( -state=>'normal'  );
           $entry_spec_min_c -> configure( -state=>'disabled');
         } else {
           $entry_auto_min_c -> configure( -state=>'disabled');
           $entry_spec_min_c -> configure( -state=>'normal'  );
         } 
    } );

  my $space_min_c = $frm_spec_min_c -> Label(-text=>' ',-padx=>'10');

  $radio_spec_min_c  -> grid(-row=>1,-column=>1,-sticky=>'w');
  $entry_spec_min_c  -> grid(-row=>1,-column=>2,-sticky=>'w');
  $space_min_c       -> grid(-row=>1,-column=>3);

  $lab_min_c         -> grid(-row=>1,-column=>1,-sticky=>'n');
  $frm_auto_min_c    -> grid(-row=>2,-column=>1,-sticky=>'w');
  $frm_spec_min_c    -> grid(-row=>3,-column=>1,-sticky=>'w');

#--- Maximum Circulation

  my $frm_max_c = $frm_limits -> Frame();

  my $lab_max_c = $frm_max_c ->
       Label(-text=>"\nMaximum Circulation");

  my $frm_auto_max_c = $frm_max_c -> Frame();

  my $radio_auto_max_c = $frm_auto_max_c -> Radiobutton(
      -text=>'Autoscale, round by',
      -value=>'autoscale',
      -variable=>\$prefs{max_c_mthd} );

  my $entry_auto_max_c = $frm_auto_max_c -> Entry(
      -width=>4, -textvariable=>\$prefs{max_c_step},
      -state=>$entry_auto_max_c_state );

  $radio_auto_max_c  -> grid(-row=>1,-column=>1,-sticky=>'w');
  $entry_auto_max_c  -> grid(-row=>1,-column=>2,-sticky=>'w');

  my $frm_spec_max_c = $frm_max_c -> Frame();

  my $radio_spec_max_c = $frm_spec_max_c -> Radiobutton(
      -text=>'Specified',
      -value=>'spec',
      -variable=>\$prefs{max_c_mthd} );

  my $entry_spec_max_c = $frm_spec_max_c -> Entry(
      -width=>13, -textvariable=>\$prefs{max_c_valu},
      -state=>$entry_spec_max_c_state );

  $radio_auto_max_c -> bind( '<ButtonRelease-1>',
    sub{ if ( $prefs{max_c_mthd} eq 'autoscale' ) {
           $entry_auto_max_c -> configure( -state=>'normal'  );
           $entry_spec_max_c -> configure( -state=>'disabled');
         } else {
           $entry_auto_max_c -> configure( -state=>'disabled');
           $entry_spec_max_c -> configure( -state=>'normal'  );
         }
    } );

  $radio_spec_max_c -> bind( '<ButtonRelease-1>',
    sub{ if ( $prefs{max_c_mthd} eq 'autoscale' ) {
           $entry_auto_max_c -> configure( -state=>'normal'  );
           $entry_spec_max_c -> configure( -state=>'disabled');
         } else {
           $entry_auto_max_c -> configure( -state=>'disabled');
           $entry_spec_max_c -> configure( -state=>'normal'  );
         } 
    } );

  my $space_max_c = $frm_spec_max_c -> Label(-text=>' ',-padx=>'10');

  $radio_spec_max_c  -> grid(-row=>1,-column=>1,-sticky=>'w');
  $entry_spec_max_c  -> grid(-row=>1,-column=>2,-sticky=>'w');
  $space_max_c       -> grid(-row=>1,-column=>3);

  $lab_max_c         -> grid(-row=>1,-column=>1,-sticky=>'n');
  $frm_auto_max_c    -> grid(-row=>2,-column=>1,-sticky=>'w');
  $frm_spec_max_c    -> grid(-row=>3,-column=>1,-sticky=>'w');

#--- Minimum y

  my $frm_min_y = $frm_limits -> Frame();

  my $lab_min_y = $frm_min_y ->
       Label(-text=>"\nMinimum Lateral Coordinate");

  my $frm_auto_min_y = $frm_min_y -> Frame();

  my $radio_auto_min_y = $frm_auto_min_y -> Radiobutton(
      -text=>'Autoscale, round by',
      -value=>'autoscale',
      -variable=>\$prefs{min_y_mthd} );

  my $entry_auto_min_y = $frm_auto_min_y -> Entry(
      -width=>4, -textvariable=>\$prefs{min_y_step},
      -state=>$entry_auto_min_y_state );

  $radio_auto_min_y  -> grid(-row=>1,-column=>1,-sticky=>'w');
  $entry_auto_min_y  -> grid(-row=>1,-column=>2,-sticky=>'w');

  my $frm_spec_min_y = $frm_min_y -> Frame();

  my $radio_spec_min_y = $frm_spec_min_y -> Radiobutton(
      -text=>'Specified',
      -value=>'spec',
      -variable=>\$prefs{min_y_mthd} );

  my $entry_spec_min_y = $frm_spec_min_y -> Entry(
      -width=>13, -textvariable=>\$prefs{min_y_valu},
      -state=>$entry_spec_min_y_state );

  $radio_auto_min_y -> bind( '<ButtonRelease-1>',
    sub{ if ( $prefs{min_y_mthd} eq 'autoscale' ) {
           $entry_auto_min_y -> configure( -state=>'normal'  );
           $entry_spec_min_y -> configure( -state=>'disabled');
         } else {
           $entry_auto_min_y -> configure( -state=>'disabled');
           $entry_spec_min_y -> configure( -state=>'normal'  );
         }
    } );

  $radio_spec_min_y -> bind( '<ButtonRelease-1>',
    sub{ if ( $prefs{min_y_mthd} eq 'autoscale' ) {
           $entry_auto_min_y -> configure( -state=>'normal'  );
           $entry_spec_min_y -> configure( -state=>'disabled');
         } else {
           $entry_auto_min_y -> configure( -state=>'disabled');
           $entry_spec_min_y -> configure( -state=>'normal'  );
         } 
    } );

  my $space_min_y = $frm_spec_min_y -> Label(-text=>' ',-padx=>'10');

  $radio_spec_min_y  -> grid(-row=>1,-column=>1,-sticky=>'w');
  $entry_spec_min_y  -> grid(-row=>1,-column=>2,-sticky=>'w');
  $space_min_y       -> grid(-row=>1,-column=>3);

  $lab_min_y         -> grid(-row=>1,-column=>1,-sticky=>'n');
  $frm_auto_min_y    -> grid(-row=>2,-column=>1,-sticky=>'w');
  $frm_spec_min_y    -> grid(-row=>3,-column=>1,-sticky=>'w');

#--- Maximum y

  my $frm_max_y = $frm_limits -> Frame();

  my $lab_max_y = $frm_max_y ->
       Label(-text=>"\nMaximum Lateral Coordinate");

  my $frm_auto_max_y = $frm_max_y -> Frame();

  my $radio_auto_max_y = $frm_auto_max_y -> Radiobutton(
      -text=>'Autoscale, round by',
      -value=>'autoscale',
      -variable=>\$prefs{max_y_mthd} );

  my $entry_auto_max_y = $frm_auto_max_y -> Entry(
      -width=>4, -textvariable=>\$prefs{max_y_step},
      -state=>$entry_auto_max_y_state );

  $radio_auto_max_y  -> grid(-row=>1,-column=>1,-sticky=>'w');
  $entry_auto_max_y  -> grid(-row=>1,-column=>2,-sticky=>'w');

  my $frm_spec_max_y = $frm_max_y -> Frame();

  my $radio_spec_max_y = $frm_spec_max_y -> Radiobutton(
      -text=>'Specified',
      -value=>'spec',
      -variable=>\$prefs{max_y_mthd} );

  my $entry_spec_max_y = $frm_spec_max_y -> Entry(
      -width=>13, -textvariable=>\$prefs{max_y_valu},
      -state=>$entry_spec_max_y_state );

  $radio_auto_max_y -> bind( '<ButtonRelease-1>',
    sub{ if ( $prefs{max_y_mthd} eq 'autoscale' ) {
           $entry_auto_max_y -> configure( -state=>'normal'  );
           $entry_spec_max_y -> configure( -state=>'disabled');
         } else {
           $entry_auto_max_y -> configure( -state=>'disabled');
           $entry_spec_max_y -> configure( -state=>'normal'  );
         }
    } );

  $radio_spec_max_y -> bind( '<ButtonRelease-1>',
    sub{ if ( $prefs{max_y_mthd} eq 'autoscale' ) {
           $entry_auto_max_y -> configure( -state=>'normal'  );
           $entry_spec_max_y -> configure( -state=>'disabled');
         } else {
           $entry_auto_max_y -> configure( -state=>'disabled');
           $entry_spec_max_y -> configure( -state=>'normal'  );
         } 
    } );

  my $space_max_y = $frm_spec_max_y -> Label(-text=>' ',-padx=>'10');

  $radio_spec_max_y  -> grid(-row=>1,-column=>1,-sticky=>'w');
  $entry_spec_max_y  -> grid(-row=>1,-column=>2,-sticky=>'w');
  $space_max_y       -> grid(-row=>1,-column=>3);

  $lab_max_y         -> grid(-row=>1,-column=>1,-sticky=>'n');
  $frm_auto_max_y    -> grid(-row=>2,-column=>1,-sticky=>'w');
  $frm_spec_max_y    -> grid(-row=>3,-column=>1,-sticky=>'w');

#--- Minimum z

  my $frm_min_z = $frm_limits -> Frame();

  my $lab_min_z = $frm_min_z ->
       Label(-text=>"\nMinimum Altitude");

  my $frm_auto_min_z = $frm_min_z -> Frame();

  my $radio_auto_min_z = $frm_auto_min_z -> Radiobutton(
      -text=>'Autoscale, round by',
      -value=>'autoscale',
      -variable=>\$prefs{min_z_mthd} );

  my $entry_auto_min_z = $frm_auto_min_z -> Entry(
      -width=>4, -textvariable=>\$prefs{min_z_step},
      -state=>$entry_auto_min_z_state );

  $radio_auto_min_z  -> grid(-row=>1,-column=>1,-sticky=>'w');
  $entry_auto_min_z  -> grid(-row=>1,-column=>2,-sticky=>'w');

  my $frm_spec_min_z = $frm_min_z -> Frame();

  my $radio_spec_min_z = $frm_spec_min_z -> Radiobutton(
      -text=>'Specified',
      -value=>'spec',
      -variable=>\$prefs{min_z_mthd} );

  my $entry_spec_min_z = $frm_spec_min_z -> Entry(
      -width=>13, -textvariable=>\$prefs{min_z_valu},
      -state=>$entry_spec_min_z_state );

  $radio_auto_min_z -> bind( '<ButtonRelease-1>',
    sub{ if ( $prefs{min_z_mthd} eq 'autoscale' ) {
           $entry_auto_min_z -> configure( -state=>'normal'  );
           $entry_spec_min_z -> configure( -state=>'disabled');
         } else {
           $entry_auto_min_z -> configure( -state=>'disabled');
           $entry_spec_min_z -> configure( -state=>'normal'  );
         }
    } );

  $radio_spec_min_z -> bind( '<ButtonRelease-1>',
    sub{ if ( $prefs{min_z_mthd} eq 'autoscale' ) {
           $entry_auto_min_z -> configure( -state=>'normal'  );
           $entry_spec_min_z -> configure( -state=>'disabled');
         } else {
           $entry_auto_min_z -> configure( -state=>'disabled');
           $entry_spec_min_z -> configure( -state=>'normal'  );
         } 
    } );

  my $space_min_z = $frm_spec_min_z -> Label(-text=>' ',-padx=>'10');

  $radio_spec_min_z  -> grid(-row=>1,-column=>1,-sticky=>'w');
  $entry_spec_min_z  -> grid(-row=>1,-column=>2,-sticky=>'w');
  $space_min_z       -> grid(-row=>1,-column=>3);

  $lab_min_z         -> grid(-row=>1,-column=>1,-sticky=>'n');
  $frm_auto_min_z    -> grid(-row=>2,-column=>1,-sticky=>'w');
  $frm_spec_min_z    -> grid(-row=>3,-column=>1,-sticky=>'w');

#--- Maximum z

  my $frm_max_z = $frm_limits -> Frame();

  my $lab_max_z = $frm_max_z ->
       Label(-text=>"\nMaximum Altitude");

  my $frm_auto_max_z = $frm_max_z -> Frame();

  my $radio_auto_max_z = $frm_auto_max_z -> Radiobutton(
      -text=>'Autoscale, round by',
      -value=>'autoscale',
      -variable=>\$prefs{max_z_mthd} );

  my $entry_auto_max_z = $frm_auto_max_z -> Entry(
      -width=>4, -textvariable=>\$prefs{max_z_step},
      -state=>$entry_auto_max_z_state );

  $radio_auto_max_z  -> grid(-row=>1,-column=>1,-sticky=>'w');
  $entry_auto_max_z  -> grid(-row=>1,-column=>2,-sticky=>'w');

  my $frm_spec_max_z = $frm_max_z -> Frame();

  my $radio_spec_max_z = $frm_spec_max_z -> Radiobutton(
      -text=>'Specified',
      -value=>'spec',
      -variable=>\$prefs{max_z_mthd} );

  my $entry_spec_max_z = $frm_spec_max_z -> Entry(
      -width=>13, -textvariable=>\$prefs{max_z_valu},
      -state=>$entry_spec_max_z_state );

  $radio_auto_max_z -> bind( '<ButtonRelease-1>',
    sub{ if ( $prefs{max_z_mthd} eq 'autoscale' ) {
           $entry_auto_max_z -> configure( -state=>'normal'  );
           $entry_spec_max_z -> configure( -state=>'disabled');
         } else {
           $entry_auto_max_z -> configure( -state=>'disabled');
           $entry_spec_max_z -> configure( -state=>'normal'  );
         }
    } );

  $radio_spec_max_z -> bind( '<ButtonRelease-1>',
    sub{ if ( $prefs{max_z_mthd} eq 'autoscale' ) {
           $entry_auto_max_z -> configure( -state=>'normal'  );
           $entry_spec_max_z -> configure( -state=>'disabled');
         } else {
           $entry_auto_max_z -> configure( -state=>'disabled');
           $entry_spec_max_z -> configure( -state=>'normal'  );
         } 
    } );

  my $space_max_z = $frm_spec_max_z -> Label(-text=>' ',-padx=>'10');

  $radio_spec_max_z  -> grid(-row=>1,-column=>1,-sticky=>'w');
  $entry_spec_max_z  -> grid(-row=>1,-column=>2,-sticky=>'w');
  $space_max_z       -> grid(-row=>1,-column=>3);

  $lab_max_z         -> grid(-row=>1,-column=>1,-sticky=>'n');
  $frm_auto_max_z    -> grid(-row=>2,-column=>1,-sticky=>'w');
  $frm_spec_max_z    -> grid(-row=>3,-column=>1,-sticky=>'w');

#--- Maximum time

  my $frm_max_t = $frm_limits -> Frame();

  my $lab_max_t = $frm_max_t ->
       Label(-text=>"\nMaximum Time");

  my $frm_auto_max_t = $frm_max_t -> Frame();

  my $radio_meas_max_t = $frm_auto_max_t -> Radiobutton(
      -text=>'From Measurements, round by',
      -value=>'measured',
      -variable=>\$prefs{max_t_mthd} );

  my $radio_modl_max_t = $frm_auto_max_t -> Radiobutton(
      -text=>'From Model Run, round by',
      -value=>'model',
      -variable=>\$prefs{max_t_mthd} );

  my $entry_auto_max_t = $frm_auto_max_t -> Entry(
      -width=>4, -textvariable=>\$prefs{max_t_step},
      -state=>$entry_auto_max_t_state );

  $radio_meas_max_t  -> grid(-row=>1,-column=>1,-sticky=>'w');
  $radio_modl_max_t  -> grid(-row=>2,-column=>1,-sticky=>'w');
  $entry_auto_max_t  -> grid(-row=>1,-column=>2,-sticky=>'w',-rowspan=>2);

  my $frm_spec_max_t = $frm_max_t -> Frame();

  my $radio_spec_max_t = $frm_spec_max_t -> Radiobutton(
      -text=>'Specified',
      -value=>'spec',
      -variable=>\$prefs{max_t_mthd} );

  my $entry_spec_max_t = $frm_spec_max_t -> Entry(
      -width=>22, -textvariable=>\$prefs{max_t_valu},
      -state=>$entry_spec_max_t_state );

  $radio_meas_max_t -> bind( '<ButtonRelease-1>',
    sub{ if ( $prefs{max_t_mthd} eq 'measured' || $prefs{max_t_mthd} eq 'model' ) {
           $entry_auto_max_t -> configure( -state=>'normal'  );
           $entry_spec_max_t -> configure( -state=>'disabled');
         } else {
           $entry_auto_max_t -> configure( -state=>'disabled');
           $entry_spec_max_t -> configure( -state=>'normal'  );
         }
    } );

  $radio_modl_max_t -> bind( '<ButtonRelease-1>',
    sub{ if ( $prefs{max_t_mthd} eq 'measured' || $prefs{max_t_mthd} eq 'model' ) {
           $entry_auto_max_t -> configure( -state=>'normal'  );
           $entry_spec_max_t -> configure( -state=>'disabled');
         } else {
           $entry_auto_max_t -> configure( -state=>'disabled');
           $entry_spec_max_t -> configure( -state=>'normal'  );
         }
    } );

  $radio_spec_max_t -> bind( '<ButtonRelease-1>',
    sub{ if ( $prefs{max_t_mthd} eq 'measured' || $prefs{max_t_mthd} eq 'model' ) {
           $entry_auto_max_t -> configure( -state=>'normal'  );
           $entry_spec_max_t -> configure( -state=>'disabled');
         } else {
           $entry_auto_max_t -> configure( -state=>'disabled');
           $entry_spec_max_t -> configure( -state=>'normal'  );
         } 
    } );

  my $space_max_t = $frm_spec_max_t -> Label(-text=>' ',-padx=>'10');

  $radio_spec_max_t  -> grid(-row=>1,-column=>1,-sticky=>'w');
  $entry_spec_max_t  -> grid(-row=>1,-column=>2,-sticky=>'w');
  $space_max_t       -> grid(-row=>1,-column=>3);

  $lab_max_t         -> grid(-row=>1,-column=>1,-sticky=>'n');
  $frm_auto_max_t    -> grid(-row=>2,-column=>1,-sticky=>'w');
  $frm_spec_max_t    -> grid(-row=>3,-column=>1,-sticky=>'w');

#--- Arrange min and max pieces in the plot limits frame

  $frm_min_c    -> grid(-row=>1,-column=>1);
  $frm_max_c    -> grid(-row=>1,-column=>2);
  $frm_min_y    -> grid(-row=>2,-column=>1);
  $frm_max_y    -> grid(-row=>2,-column=>2);
  $frm_min_z    -> grid(-row=>3,-column=>1);
  $frm_max_z    -> grid(-row=>3,-column=>2);
  $frm_max_t    -> grid(-row=>4,-column=>1,-columnspan=>2);

#--- Frame for adjusting the plot format

  my $frm_plot_format = $frm_settings -> LabFrame(
     -label => 'Plot Formatting Details',
     -labelside => 'acrosstop');

  my $frm_plot_font = $frm_plot_format -> Frame();

  my $lab_plot_font1 = $frm_plot_font ->
     Label(-text=>'Increase plot font by');

  my $lab_plot_font2 = $frm_plot_font ->
     Label(-text=>'points');

  my $entry_plot_font_size = $frm_plot_font -> 
     Entry(-width=>4, -textvariable=>\$prefs{plot_font_size_bump});

  $lab_plot_font1       -> grid(-row=>1,-column=>1);
  $entry_plot_font_size -> grid(-row=>1,-column=>2);
  $lab_plot_font2       -> grid(-row=>1,-column=>3);

  my $frm_instability = $frm_plot_format -> Frame();

  my $check_instability = $frm_instability -> 
     Checkbutton(-text=>'Show instability times',
                 -variable=>\$prefs{show_instability});

  $check_instability -> grid(-row=>1,-column=>1);

  my $frm_y_plot = $frm_plot_format -> Frame();

  my $lab_y_plot = $frm_y_plot ->
     Label(-text=>"\nLateral Plot Type");

  my $radio_y_vs_t = $frm_y_plot -> 
     Radiobutton(-text=>'Show y versus t',
                 -value=>'y',
                 -variable=>\$prefs{y_plot_choice} );

  my $radio_z_vs_y = $frm_y_plot -> 
     Radiobutton(-text=>'Show z versus y',
                 -value=>'traj',
                 -variable=>\$prefs{y_plot_choice} );

  $radio_y_vs_t    -> grid(-row=>1,-column=>1);
  $radio_z_vs_y    -> grid(-row=>2,-column=>1);

  $frm_plot_font   -> grid(-row=>1,-column=>1);
  $frm_instability -> grid(-row=>2,-column=>1);
  $frm_y_plot      -> grid(-row=>3,-column=>1);

#--- Frame for adjusting the display and window placement

  my $frm_display = $frm_settings ->
     LabFrame(-label=>'Display Size and Window Placement',
              -labelside => 'acrosstop');

#--- Display size

  my $frm_display_size = $frm_display -> Frame();

  my $lab_display_size = $frm_display_size ->
     Label(-text=>"\nDisplay Size");

  my $frm_auto_display_size = $frm_display_size -> Frame();

  my $radio_auto_display_size = $frm_auto_display_size -> 
     Radiobutton(-text=>'Autodetect',
                 -value=>'autodetect',
                 -variable=>\$prefs{display_size_mthd} );

  my $lab_auto_by = $frm_auto_display_size ->
     Label(-text=>'x');

  my $entry_auto_x_display_size = $frm_auto_display_size -> 
     Entry(-width=>4, -textvariable=>\$auto_display_width,
           -state=>'disabled');

  my $entry_auto_y_display_size = $frm_auto_display_size -> 
     Entry(-width=>4, -textvariable=>\$auto_display_height,
           -state=>'disabled');

  $radio_auto_display_size   -> grid(-row=>1,-column=>1,-sticky=>'w');
  $entry_auto_x_display_size -> grid(-row=>1,-column=>2,-sticky=>'w');
  $lab_auto_by               -> grid(-row=>1,-column=>3,-sticky=>'w');
  $entry_auto_y_display_size -> grid(-row=>1,-column=>4,-sticky=>'w');

  my $frm_spec_display_size = $frm_display_size -> Frame();

  my $radio_spec_display_size = $frm_spec_display_size -> 
     Radiobutton(-text=>'Manual       ',
                 -value=>'spec',
                 -variable=>\$prefs{display_size_mthd} );

  my $lab_spec_by = $frm_spec_display_size ->
     Label(-text=>'x');

  my $entry_spec_x_display_size = $frm_spec_display_size -> 
     Entry(-width=>4, -textvariable=>\$prefs{display_width},
           -state=>$entry_spec_display_size_state);

  my $entry_spec_y_display_size = $frm_spec_display_size -> 
     Entry(-width=>4, -textvariable=>\$prefs{display_height},
           -state=>$entry_spec_display_size_state);

  $radio_spec_display_size   -> grid(-row=>1,-column=>1,-sticky=>'w');
  $entry_spec_x_display_size -> grid(-row=>1,-column=>2,-sticky=>'w');
  $lab_spec_by               -> grid(-row=>1,-column=>3,-sticky=>'w');
  $entry_spec_y_display_size -> grid(-row=>1,-column=>4,-sticky=>'w');

  $radio_auto_display_size -> bind( '<ButtonRelease-1>',
    sub{ $entry_spec_x_display_size -> configure(-state=>'disabled');
         $entry_spec_y_display_size -> configure(-state=>'disabled');
    } );

  $radio_spec_display_size -> bind( '<ButtonRelease-1>',
    sub{ $entry_spec_x_display_size -> configure(-state=>'normal');
         $entry_spec_y_display_size -> configure(-state=>'normal');
    } );

#--- Arrange the display size frames 

  $lab_display_size      -> grid(-row=>1,-column=>1,-sticky=>'n');
  $frm_auto_display_size -> grid(-row=>2,-column=>1,-sticky=>'w');
  $frm_spec_display_size -> grid(-row=>3,-column=>1,-sticky=>'w');

#--- Window offsets

  my $frm_offsets = $frm_display -> Frame();

  my $lab_offsets = $frm_offsets ->
     Label(-text=>"\nWindow Offsets");

  my $frm_main_window_offsets = $frm_offsets -> Frame();

  my $lab_main_offset = $frm_main_window_offsets ->
     Label(-text=>'Main Window Offset');

  my $lab_main_comma = $frm_main_window_offsets ->
     Label(-text=>',');

  my $entry_main_x_offset = $frm_main_window_offsets -> 
     Entry(-width=>4, -textvariable=>\$prefs{main_window_x_offset});

  my $entry_main_y_offset = $frm_main_window_offsets -> 
     Entry(-width=>4, -textvariable=>\$prefs{main_window_y_offset});

  $lab_main_offset     -> grid(-row=>1,-column=>1,-sticky=>'w');
  $entry_main_x_offset -> grid(-row=>1,-column=>2,-sticky=>'w');
  $lab_main_comma      -> grid(-row=>1,-column=>3,-sticky=>'w');
  $entry_main_y_offset -> grid(-row=>1,-column=>4,-sticky=>'w');

  my $frm_plot_window_offsets = $frm_offsets -> Frame();

  my $lab_plot_offset = $frm_plot_window_offsets ->
     Label(-text=>'Plot Window Offset  ');

  my $lab_plot_comma = $frm_plot_window_offsets ->
     Label(-text=>',');

  my $entry_plot_x_offset = $frm_plot_window_offsets -> 
     Entry(-width=>4, -textvariable=>\$prefs{plot_window_x_offset});

  my $entry_plot_y_offset = $frm_plot_window_offsets -> 
     Entry(-width=>4, -textvariable=>\$prefs{plot_window_y_offset});

  $lab_plot_offset     -> grid(-row=>1,-column=>1,-sticky=>'w');
  $entry_plot_x_offset -> grid(-row=>1,-column=>2,-sticky=>'w');
  $lab_plot_comma      -> grid(-row=>1,-column=>3,-sticky=>'w');
  $entry_plot_y_offset -> grid(-row=>1,-column=>4,-sticky=>'w');

#--- Arrange the offset frames

  $lab_offsets             -> grid(-row=>1,-column=>1);
  $frm_main_window_offsets -> grid(-row=>2,-column=>1);
  $frm_plot_window_offsets -> grid(-row=>3,-column=>1);

  my $frm_output_window_size = $frm_display -> Frame();

  my $lab_output_window_size = $frm_output_window_size ->
     Label(-text=>"\nOutput Window Size");

  my $frm_number_of_lines = $frm_output_window_size -> Frame();

  my $lab_number_of_lines = $frm_number_of_lines ->
     Label(-text=>"Number of lines in the\nviper output window");

  my $entry_number_of_lines = $frm_number_of_lines -> 
     Entry(-width=>4, -textvariable=>\$prefs{runlist_lines});

  $lab_number_of_lines   -> grid(-row=>1,-column=>1);
  $entry_number_of_lines -> grid(-row=>1,-column=>2);

#--- Arrange the output window size frames

  $lab_output_window_size -> grid(-row=>1,-column=>1,-sticky=>'w');
  $frm_number_of_lines    -> grid(-row=>2,-column=>1,-sticky=>'w');

#--- Organize all of the display settings into the display frame

  $frm_display_size       -> grid(-row=>1,-column=>1);
  $frm_offsets            -> grid(-row=>2,-column=>1);
  $frm_output_window_size -> grid(-row=>3,-column=>1);

#--- Frame for selecting which models to run

  my $frm_models = $frm_settings ->
     LabFrame(-label=>'Model Selection',
              -labelside => 'acrosstop');

#--- Model 1

  my $frm_model1 = $frm_models -> Frame();

  my $lab_blank_mod1 = $frm_model1 ->
     Label(-text=>"\n");

  my $lab_model1 = $frm_model1 ->
     Label(-text=>"Model 1");

  my $entry_model1 = $frm_model1 -> 
     Entry(-width=>18, -textvariable=>\$prefs{model1});

  my $lab_lab1 = $frm_model1 ->
     Label(-text=>"Label 1");

  my $entry_lab1 = $frm_model1 -> 
     Entry(-width=>10, -textvariable=>\$prefs{lab1});

  $lab_blank_mod1 -> grid(-row=>1,-column=>1,-sticky=>'w');
  $lab_model1     -> grid(-row=>1,-column=>1,-sticky=>'w');
  $entry_model1   -> grid(-row=>1,-column=>2,-sticky=>'w');
  $lab_lab1       -> grid(-row=>1,-column=>3,-sticky=>'w');
  $entry_lab1     -> grid(-row=>1,-column=>4,-sticky=>'w');

#--- Model 2

  my $frm_model2 = $frm_models -> Frame();

  my $lab_blank_mod2 = $frm_model2 ->
     Label(-text=>"\n");

  my $lab_model2 = $frm_model2 ->
     Label(-text=>"Model 2");

  my $entry_model2 = $frm_model2 -> 
     Entry(-width=>18, -textvariable=>\$prefs{model2});

  my $lab_lab2 = $frm_model2 ->
     Label(-text=>"Label 2");

  my $entry_lab2 = $frm_model2 -> 
     Entry(-width=>10, -textvariable=>\$prefs{lab2});

  $lab_blank_mod2 -> grid(-row=>1,-column=>1,-sticky=>'w');
  $lab_model2     -> grid(-row=>1,-column=>1,-sticky=>'w');
  $entry_model2   -> grid(-row=>1,-column=>2,-sticky=>'w');
  $lab_lab2       -> grid(-row=>1,-column=>3,-sticky=>'w');
  $entry_lab2     -> grid(-row=>1,-column=>4,-sticky=>'w');

#--- Organize all of the model frames into the model selection frame

  $frm_model1   -> grid(-row=>1,-column=>1);
  $frm_model2   -> grid(-row=>2,-column=>1);

#--- Organize all of the frames into the main window

  $frm_limits      -> grid(-row=>1,-column=>1);
  $frm_models      -> grid(-row=>2,-column=>1);
  $frm_display     -> grid(-row=>1,-column=>2);
  $frm_plot_format -> grid(-row=>2,-column=>2,-sticky=>'n');

#--- Add some control buttons at the bottom

  my $button_quit = $top -> Button(
      -text=>'Quit without saving',
      -command=>sub{ destroy $top; }) ->
          pack(-side=>'left',-expand=>1);

  my $button_save = $top -> Button(
      -text=>'Save settings',
      -command=>sub{ if( $prefs{display_size_mthd} eq 'autodetect' ) {
                       $prefs{display_width}  = $auto_display_width;
                       $prefs{display_height} = $auto_display_height;
                     }
                     my @models;
                     $models[0] = 'model1';
                     $prefs{n_models} = 1;
                     if( $prefs{model2} ne '' ) { 
                       $prefs{n_models}=2;
                       $models[1] = 'model2';
                     }
                     my $extension;
                     my $model_status = 0;
                     foreach my $model (@models) {
                       if(      $prefs{$model} eq 'apa32'     ) {
                         $extension = 'apa32'; 
                       } elsif( $prefs{$model} eq 'apa35'     ) {
                         $extension = 'apa35'; 
                       } elsif( $prefs{$model} eq 'viper30'  ) {
                         $extension = 'vpr30'; 
                       } elsif( $prefs{$model} eq 'viper20'   ) {
                         $extension = 'vpr20'; 
                       } else {
                         $model_status++;
                         print "model = $prefs{$model}\n";
                       }
                       if( $model eq 'model1' ) {
                         $prefs{ext1} = $extension;
                       } else {
                         $prefs{ext2} = $extension;
                       }
                     }
                     if( $model_status != 0 ) {
                       $top -> messageBox(
                              -message=>"Invalid model type",
                              -type=>'OK',-title=>'Invalid Model');
                     } else {
                       open(FILE,"+>State/prefs.txt") or die 
                         "$0:Could not open prefs.txt\n";
                       foreach my $key (@keys) {
                         print FILE "$key $prefs{$key}\n";
                       }
                       close FILE;
                       $update_prefs = 'true';
                       destroy $top;
                     }
          }) -> pack(-side=>'left',-expand=>1);

  my $button_reset = $top -> Button(
      -text=>'Restore Defaults',
      -command=>sub{ my ($default_ref, $keys_ref)  = defaultPreferences($top); 
                     my %default = %{$default_ref};
                     @keys = @$keys_ref;
                     foreach my $key (@keys) {
                       $prefs{$key} = $default{$key};
                     }
                     if ( $prefs{min_c_mthd} eq 'autoscale' ) {
                       $entry_auto_min_c -> configure( -state=>'normal'  );
                       $entry_spec_min_c -> configure( -state=>'disabled');
                     } else {
                       $entry_auto_min_c -> configure( -state=>'disabled');
                       $entry_spec_min_c -> configure( -state=>'normal'  );
                     }
                     if ( $prefs{max_c_mthd} eq 'autoscale' ) {
                       $entry_auto_max_c -> configure( -state=>'normal'  );
                       $entry_spec_max_c -> configure( -state=>'disabled');
                     } else {
                       $entry_auto_max_c -> configure( -state=>'disabled');
                       $entry_spec_max_c -> configure( -state=>'normal'  );
                     }
                     if ( $prefs{min_y_mthd} eq 'autoscale' ) {
                       $entry_auto_min_y -> configure( -state=>'normal'  );
                       $entry_spec_min_y -> configure( -state=>'disabled');
                     } else {
                       $entry_auto_min_y -> configure( -state=>'disabled');
                       $entry_spec_min_y -> configure( -state=>'normal'  );
                     }
                     if ( $prefs{max_y_mthd} eq 'autoscale' ) {
                       $entry_auto_max_y -> configure( -state=>'normal'  );
                       $entry_spec_max_y -> configure( -state=>'disabled');
                     } else {
                       $entry_auto_max_y -> configure( -state=>'disabled');
                       $entry_spec_max_y -> configure( -state=>'normal'  );
                     }
                     if ( $prefs{min_z_mthd} eq 'autoscale' ) {
                       $entry_auto_min_z -> configure( -state=>'normal'  );
                       $entry_spec_min_z -> configure( -state=>'disabled');
                     } else {
                       $entry_auto_min_z -> configure( -state=>'disabled');
                       $entry_spec_min_z -> configure( -state=>'normal'  );
                     }
                     if ( $prefs{max_z_mthd} eq 'autoscale' ) {
                       $entry_auto_max_z -> configure( -state=>'normal'  );
                       $entry_spec_max_z -> configure( -state=>'disabled');
                     } else {
                       $entry_auto_max_z -> configure( -state=>'disabled');
                       $entry_spec_max_z -> configure( -state=>'normal'  );
                     }
                     if ( $prefs{max_t_mthd} eq 'measured' || 
                          $prefs{max_t_mthd} eq 'model'       ) {
                       $entry_auto_max_t -> configure( -state=>'normal'  );
                       $entry_spec_max_t -> configure( -state=>'disabled');
                     } else {
                       $entry_auto_max_t -> configure( -state=>'disabled');
                       $entry_spec_max_t -> configure( -state=>'normal'  );
                     }
                     if ( $prefs{display_size_mthd} eq 'autodetect' ) {
                       $entry_spec_x_display_size -> 
                         configure(-state=>'disabled');
                       $entry_spec_y_display_size -> 
                         configure(-state=>'disabled');
                     } else {
                       $entry_spec_x_display_size -> 
                         configure(-state=>'normal');
                       $entry_spec_y_display_size -> 
                         configure(-state=>'normal');
                     }
                   }) ->
          pack(-side=>'left',-expand=>1);

#--- Hang around until the window is closed

  $top -> waitWindow;

  return( \%prefs, $update_prefs );

}

#-------------------------------------------------------------------------------
# Subroutine to read preference values from a file

sub readPreferences {

  my $parent_window = $_[0];

  my ($prefs_ref, $keys_ref) = &defaultPreferences($parent_window);
  my %prefs = %{$prefs_ref};

  if (-e 'State/prefs.txt') {
    open(FILE,"<State/prefs.txt") or die "$0:Could not open prefs.txt\n";
    while (! eof (FILE) ) {
      my $line = readline *FILE; chomp $line;
      if ($line =~ m/^\s*#|^\s*$|^\s*\/|^\s*\\/) {
        next
      } else {
        my( $key, $value ) = split(' ',$line);
        $prefs{$key} = $value;
      }
    }
    close FILE;
  }

  return( \%prefs, $keys_ref );

}

#-------------------------------------------------------------------------------
# Subroutine to set default preference values

sub defaultPreferences {

  my $parent_window = $_[0];

  my (@keys, %prefs);

  my ($display_width, $display_height);

  if( defined($parent_window) ) {
    $display_width  = $parent_window->screenwidth;
    $display_height = $parent_window->screenheight;
  } else {
    my $mw = new MainWindow();
    $display_width  = $mw->screenwidth;
    $display_height = $mw->screenheight;
    destroy $mw;
  }

  $keys[ 0] = 'min_c_mthd';
  $prefs{      min_c_mthd} = 'autoscale';
  $keys[ 1] = 'min_c_valu';
  $prefs{      min_c_valu} = 0;
  $keys[ 2] = 'min_c_step';
  $prefs{      min_c_step} = 50;
  $keys[ 3] = 'max_c_mthd';
  $prefs{      max_c_mthd} = 'autoscale';
  $keys[ 4] = 'max_c_valu';
  $prefs{      max_c_valu} = 350;
  $keys[ 5] = 'max_c_step';
  $prefs{      max_c_step} = 50;
  $keys[ 6] = 'min_y_mthd';
  $prefs{      min_y_mthd} = 'autoscale';
  $keys[ 7] = 'min_y_valu';
  $prefs{      min_y_valu} = -100;
  $keys[ 8] = 'min_y_step';
  $prefs{      min_y_step} = 20;
  $keys[ 9] = 'max_y_mthd';
  $prefs{      max_y_mthd} = 'autoscale';
  $keys[10] = 'max_y_valu';
  $prefs{      max_y_valu} = 100;
  $keys[11] = 'max_y_step';
  $prefs{      max_y_step} = 20;
  $keys[12] = 'min_z_mthd';
  $prefs{      min_z_mthd} = 'autoscale';
  $keys[13] = 'min_z_valu';
  $prefs{      min_z_valu} = 0;
  $keys[14] = 'min_z_step';
  $prefs{      min_z_step} = 20;
  $keys[15] = 'max_z_mthd';
  $prefs{      max_z_mthd} = 'autoscale';
  $keys[16] = 'max_z_valu';
  $prefs{      max_z_valu} = 300;
  $keys[17] = 'max_z_step';
  $prefs{      max_z_step} = 20;
  $keys[18] = 'max_t_mthd';
  $prefs{      max_t_mthd} = 'measured';
  $keys[19] = 'max_t_valu';
  $prefs{      max_t_valu} = 300;
  $keys[20] = 'max_t_step';
  $prefs{      max_t_step} = 20;
  $keys[21] = 'plot_font_size_bump';
  $prefs{      plot_font_size_bump} = 0;
  $keys[22] = 'display_size_mthd';
  $prefs{      display_size_mthd} = 'autodetect';
  $keys[23] = 'display_width';
  $prefs{      display_width}  = $display_width;
  $keys[24] = 'display_height';
  $prefs{      display_height} = $display_height;
  $keys[25] = 'main_window_x_offset';
  $prefs{      main_window_x_offset} = 200;
  $keys[26] = 'main_window_y_offset';
  $prefs{      main_window_y_offset} = 0;
  $keys[27] = 'plot_window_x_offset';
  $prefs{      plot_window_x_offset} = 0;
  $keys[28] = 'plot_window_y_offset';
  $prefs{      plot_window_y_offset} = 0;
  $keys[29] = 'runlist_lines';
  $prefs{      runlist_lines} = 25;
  $keys[30] = 'show_instability';
  $prefs{      show_instability} = 1;
  $keys[31] = 'y_plot_choice';
  $prefs{      y_plot_choice} = 'y';
  $keys[32] = 'n_models';
  $prefs{      n_models} = 2;
  $keys[33] = 'model1';
  $prefs{      model1} = 'viper20';
  $keys[34] = 'model2';
  $prefs{      model2} = '';
  $keys[35] = 'ext1';
  $prefs{      ext1} = 'vpr20';
  $keys[36] = 'ext2';
  $prefs{      ext2} = '';
  $keys[37] = 'lab1';
  $prefs{      lab1} = 'viper20';
  $keys[38] = 'lab2';
  $prefs{      lab2} = '';

  return( \%prefs, \@keys );

}
