#!/local/bin/perl

=head1 NAME

sourceplot - display a plot of astronomical sources on adjustable axes

=head1 SYNOPSIS

    sourceplot [--help | --version]

=head1 PURPOSE

Source Plot was created to help observers decide which sources to observe
at particular times to optimise the observing time at the telescope.
The main purpose of this program is to plot the movement of a source
throughout the night.  The movement can be plotted by the source's
elevation, azimuth, parallactic angle, or by time.

=head1 DESCRIPTION

Source Plot is designed to display the path of a source throughout
a night.  This path can be displayed in several ways, using Time,
Elevation, Parallactic Angle, and Azimuth as the different axes.
The sources can either be taken from a catalog or manually inserted.
The first thing most observers will want to double click on is a source
in the Catalog Window, which will plot that source.  Currently the only
moving sources that can be plotted are planets, the Sun and the Moon,
which can be added via the 'Planets' button in the Edit Window.

=head2 Plotting Window

The Plotting Window contains the actual plot and has control over the
other windows.  The display itself has several features.  Each colored
line in the Plotting Window is associated with the source with the same
color in the Edit Window.  In the event that two lines have the same or
similar color, moving the mouse over a plotted source will highlight the
source in the Edit Window.  The large dot along the plotted source is
the position of the source at the current time, called from here on a
'location dot'.  These dots are updated automatically as time passes.
Moving the mouse over a location dot will display the elevation and
azimuth for the source in respect to an RA-Dec graph, where Dec is
the y-axis.  This feature does not work in the
L<Azimuth-Elevation graph|/"Elevation vs Azimuth Mode">.  The small
dots along the plotted lines are 15 minutes apart, showing the precise
time the source will be at a given location.

There are several buttons in this window.  Starting from the left,
here's an explanation of each:

=over 4

=item B<Options>

Opens a window in which the relevant telescope, x-axis and y-axis can
be changed.  The time the plot is centred around can also be changed.
To apply these changes without closing the window, press the 'Apply'
button.

=item B<UT Date>

A window will appear with the current UT Date in it which can be modified
to see future or past dates.

=item B<Edit>

This button will open the Edit Window if it is closed.  This button
becomes disabled when the Edit Window is open.

=item B<Catalog>

Like the 'Edit' button, the button opens the Catalog Window if it is
closed.  This button will be disabled if the Catalog Window is open to
prevent more than one Catalog Window from being created.

=item B<Print>

See L</"Printing the Graph"> for a description of this button.

=item B<Exit>

Exits the program, closing all associated windows.

=back

=head2 Edit Window

This window contains the list of sources chosen by the observer.
Only the sources that are active will be shown in the plot.  The first
thing that should be known is how to select sources so they can be added,
deleted, or deactivated.  To select a source, single click on it in the
Edit Window.  The source will turn red indicating it has been selected.
Several sources can be selected by clicking on each one individually.
To deselect a source, single click on the source again.

There are several small features in this window.  Moving the mouse
over a source in the Edit Window will highlight its plotted line in
the Plot Window.  To edit a source's coordinates, double click on it.
A window will appear in which the source's information can be changed.
The final set of features require the use of the Edit Window Buttons.
The following is a description of each, starting from the left:

=over 4

=item B<On/Off>

This button will activate or disable the selected sources.  Disabled
sources will not be displayed in the Plotting Window

=item B<Delete All>

This button will remove the sources in the Edit Window.  It will not
delete the source from the Catalog Window.

=item B<Delete>

The selected sources will be removed from the Edit Window.

=item B<Undo>

This button will undo the last major command.  Major commands are
considered to be deletions, additions, and source coordinate changes.

=item B<New>

This will allow a source to be created manually, inserting the appropriate
coordinates and a name.  The new source will be added to the list in
the Edit Window and to the plot.  The RA/Dec coordinates can be entered
with spaces or colons separating the parts.  If only the first one or
two parts are inserted, the remaining parts will be filled with 0's.

=item B<Planets>

By pressing this button, a list of the planets will appear.  Selecting one
will add it to the list of sources in the Edit Window and to the plot.

=item B<Done>

This button will close the Edit Window.  It can be re-opened by pressing
the 'Edit' button in the Plot Window.

=back

=head2 Catalog Window

The Catalog Window is provided by L<Tk::AstroCatalog> (part of the
L<Astro::Catalog> package).
Through it, the observer is able to add sources from
a catalog file to be plotted.  The JCMT unified source catalog, which
is included with this program, is initally shown in the Catalog Window.
There are
several features that are not obvious.  To select sources in the Catalog
Window, click the mouse button once over top of it.  The source will turn
red to indicate it has been selected.  Several sources can be selected
in this way, creating a list of selected sources to do actions on.
To deselect a source, click on it a second time.  Double clicking on a
source will add it and all the selected sources to the Edit Window where
the sources will be plotted.

The following are explanations of the features contained within the
buttons on the Catalog Window:

=over 4

=item B<Catalogs>

The 'Catalogs' button will allow the observer to load a default catalog
or to load a catalog from file.  If the file is chosen, a window will
appear in which to find the desired path and file.  The path and file
can be entered manually in the 'Catalog file:' field.  The default
catalog, to be loaded when the 'Default Catalog' menu entry is selected,
can be changed by setting the C<ASTRO_CATALOG_JCMT> environmental
variable
by typing C<setenv ASTRO_CATALOG_JCMT /path/catalog>.  Although Source Plot has
been programmed to accept different variations of catalogs, the Catalog
Window loads catalogs in the JCMT pointing catalog format.

=item B<Rescan>

'Rescan' rescans the currently selected catalog, displaying any entries
that may have been lost in a search.

=item B<Search>

Using 'Search' will display a window in which the user can fill one
or more fields in which to search for a specific source.  If any of
the fields is not filled in, the program will ignore that field and
search based on the other fields.  If only part of a field is known,
the program will display any sources containing the partial information.
For example, if the RA starts with '5' and the Dec begins with '-9 45',
type '5' in the RA field and '-9 45' in the Dec field and the resulting
search will display all the sources that have an RA starting with '5'
and a Dec starting with '-9 45'.  Since the other fields were not used,
the search will not be limited by them.

=item B<Add>

'Add' adds the selected sources to the Edit Window.

=item B<Done>

To close the Catalog Window, press 'Done'.  It can be re-opened by
pressing the 'Catalog' button in the Plot Window.

=back

=head2 Printing the Graph

Once all of your sources are plotted, press the 'Print' button in the
Plotting Window.  A window will appear.  Source Plot will let you print
to a printer or to a file.  Select the method you prefer by pressing the
diamond to the left of that option.  If using the 'To File' method, fill
in the 'Filename' field with the path and filename desired.  If using the
'To Printer' method, the command to print can be changed in the 'Printer
Command' field.  The default command is 'lp'.  Additional arguments
can be added to the line or a totally different command can be used by
replacing this line with the desired command.  For example, to print to
a specific printer, just add '-d printer' after 'lp'.  When everything
is ready, press 'Print'.

=head2 Elevation vs Azimuth Mode

The Elevation vs Azimuth Graph was created to better show the distance
between sources in the sky.  The plot will be shown in this mode if
the selected axes are azimuth and either elevation or air mass.

The elevation is indicated by the circular
lines, with the white outside circle 0 degrees and the middle of the graph
90 degrees.  The azimuth rotates around the circle, 0 degrees at the top
and 180 degrees at the bottom.  Like the other graphs, the large dots
on the lines represent the position of the source at the current time.
The small dots are 15 minute intervals apart.  The times written on the
graph around the 30 degree mark for each source is the time, in HST,
that the source will be passing through that point.

=head1 FILES

=over 4

=item C<~/.splotcfg>

Stores the settings from the L<Options Window|/Options> when
'Save Setting' is selected.  This file is read to configure
sourceplot when it starts up.

=back

=cut

use strict;
#use warnings;

our $VERSION = '1.17';
my $locateBug = 0;

use Tk;
use Tk::Balloon;
use Tk::FileSelect;
use App::SourcePlot::Plotter::Tk;
use DateTime;
use DateTime::Format::Strptime;
use App::SourcePlot::Defaults;
use App::SourcePlot::Source;
use File::ShareDir qw/dist_file/;
use Tk::AstroCatalog;
use Astro::PAL;
use Astro::Telescope;
use Math::Trig;
use Astro::Coords::Planet 0.05;
use Pod::Usage;
use Getopt::Long;

my ($option_help, $option_version);
GetOptions('help|man' => \$option_help,
           'version' => \$option_version)
  or pod2usage(-verbose => 0);
pod2usage(-verbose => 2) if $option_help;

if ($option_version) {
  print 'SourcePlot version ' . $VERSION . "\n";
  exit(0);
}

my $MW = new MainWindow();
$MW->positionfrom('user');
$MW->geometry('+0+90');
$MW->title('Source Plot');
$MW->resizable(0, 0);
$MW->iconname('Source Plot');
$MW->update;



#global variables that will be used....

my $TODAY;
my $TIME;
my @SOURCE_LIST = ();
my @planets = map {ucfirst($_)} Astro::Coords::Planet::planets();

my $CATALOG_OPEN;
my $EDIT_OPEN;

my $LAST_COMMAND;
my @UNDO_LIST;
my $undoBut;
my $cBut;
my $TimeLap = 30000;    # time between white dot updates
my $dotSizeX = 4;
my $dotSizeY = 4;

my @axes = ('Time', 'Elevation', 'Air Mass', 'Azimuth', 'Parallactic Angle');
my %defaults = (
                TEL => 'JCMT',
                XAXIS => 'Time',
                YAXIS => 'Elevation',
                TIME => '1:30:00'
                );

# setting up default values for Source Plot Options
my $defaults = new App::SourcePlot::Defaults();
$defaults->file('.splotcfg');
$defaults->r_defaults(\%defaults);
my $TEL = $defaults->values('TEL');
my $X_AXIS = $defaults->values('XAXIS');
my $Y_AXIS = $defaults->values('YAXIS');
my $TIME = $defaults->values('TIME');
chomp($X_AXIS);
chomp($Y_AXIS);
chomp($TIME);
chomp($TEL);
my $telObject = new Astro::Telescope($TEL);

my ($minX,$minY);
my ($maxX,$maxY);

my $NUM_POINTS = 97;

my $BUSY = 0;

my $TIMER;

##### global windows

my $EditWin = {};
my $CatWin = {};
$EditWin->{'Changeable'} = 1;
$CatWin->{'Changeable'} = 0;

my $RESPONSE;

my @COLOR_LIST = qw/#ffaaaa #00ff00 #ff55ff #ffff00 #00ffff #ff00ff
                    #ffffff #ff5555 #55ff55 #55ffff #ffff55/;
my $COLOR_INDEX = 0;
my $H_LIGHT = undef;
my $H_WIDTH = 3;

#create the balloon used for help
my $balloon = $MW->Balloon();

# set the date to the current date
my ($ss, $mm, $hh, $md, $mo, $yr, $wd, $yd, $isdst) = gmtime(time);
$mo++;   # this catches the month up to the current date
$mo = '0'.$mo if length($mo) < 2;
$md = '0'.$md if length($md) < 2;
$yr += 1900;
my $DATE = "$yr\/$mo\/$md\/";
$TODAY = $DATE;
$TIME = "1:30:00";

#setup dimensions
my $xplot = 590;
my $xborder = 50;
my $yplot = 550;
my $yborder = 30;

my $canFrame = $MW->Frame(
                   -takefocus => 1,
                   -width => $xplot,
);

# Create a canvas and calculate the world to pixel ratio
my $plotter = new App::SourcePlot::Plotter::Tk($xplot, $yplot, 1, 1, $canFrame);
$plotter->setBackground('black');
$plotter->worldCenter($xborder, $yplot-$yborder);
$plotter->usingWorld(1);

# Set up the X Y coordinate feedback
#my ($XPOS, $YPOS);
#$plotter->monitorXY( \$XPOS, \$YPOS );

my $buttonFrame = $MW->Frame(
                   -takefocus => 1,
                   -width =>$xplot
);

my $exitBut = $buttonFrame->Button(
   -text         => 'Exit',
   -width        => 8,
   -command      => sub{destroy $MW;}
)->pack(-side=>'right');
$balloon->attach($exitBut,
                 -balloonmsg => "Press to Exit program");

my $printBut = $buttonFrame->Button(
   -text         => 'Print',
   -width        => 8,
   -command      => sub{
     my $choice = 'printer';

     my $Top = $MW->Toplevel();
     $Top->title('Source Plot Printer Options');
     $Top->resizable(0,0);
     my $radf = $Top->Frame()->pack(-padx=>10, -pady=>10, -side=>'top');
     my $tf = $Top->Frame(-relief=>'groove', -borderwidth =>2)->pack(-padx=>10, -side=>'top');

     # create the radio button for the file option
     my $radbut = $radf->Radiobutton( -text => "To File",
        -value => 'file',
        -variable => \$choice );
     $radbut->grid(-column=>0, -row=>0, -padx => 10);

     # create the print radio button
     my $radbut2 = $radf->Radiobutton( -text => "To Printer",
        -value => 'printer',
        -variable => \$choice );
     $radbut2->grid(-column=>1, -row=>0, -padx => 10);

     # create the file entry
     $tf->Label (
         -text => "Filename",
         -justify => 'right'
       )->grid(-sticky => 'e', -column=>2, -row=>0);
     my $fileEnt = $tf->Entry(-relief=>'sunken',
       -width=>20)->grid(-column=>3, -row=>0, -padx =>10, -pady=>5);

     # create the printer options box
     $tf->Label (
         -text => "Printer Command",
         -justify => 'right'
       )->grid(-column=>2, -row=>1, -sticky=>'e');
     my $printerEnt = 'lp';
     $tf->Entry(-relief=>'sunken',
                -textvariable=>\$printerEnt,
       -width=>20)->grid(-column=>3, -row=>1, -padx =>10, -pady=>5);

     # create the print button
     my $bf = $Top->Frame()->pack(-side=>'bottom', -pady=>10, -padx=>10);
     $bf->Button(
       -text         => 'Print',
       -width        => 8,
       -command      => sub {
         tagOnOff('white', 1, 'dark green');
         tagOnOff('black', 1, 'white');
         foreach my $source (@SOURCE_LIST) {
           tagOnOff($source->name(), 1, 'dark green');
         }
         if ($choice eq 'printer') {
           $plotter->printCanvas($choice, $printerEnt, $MW);
         } else {
           $plotter->printCanvas($choice, $fileEnt->get, $MW);
         }
         tagOnOff('white', 1, 'white');
         tagOnOff('black', 1, 'black');
         foreach my $source (@SOURCE_LIST) {
           tagOnOff($source->name(), 1, $source->color());
         }
         destroy $Top;
       }
     )->pack(-side=>'right', -padx => 10);

     my $optBut = $bf->Button(
       -text         => 'Cancel',
       -width        => 8,
       -command      => sub {destroy $Top;}
     )->pack(-side=>'right', -padx =>10);

     $Top->update;
     $Top->grab;
   })->pack(-side=>'right');
$balloon->attach($printBut,
                 -balloonmsg => "Press to print the graph");

my $optBut = $buttonFrame->Button(
   -text         => 'Options',
   -width        => 8,
   -command      => \&changeOpt
)->pack(-side=>'left');
$balloon->attach($optBut,
                 -balloonmsg => "Press to change the x and y axes");

my $dateBut = $buttonFrame->Button(
   -text         => 'UT Date',
   -width        => 8,
   -command      => \&changeDate
)->pack(-side=>'left');
$balloon->attach($dateBut,
                 -balloonmsg => "Press to change the UT date");

print "made it to just before the menu button, planet\n" if $locateBug;

my $eBut = $buttonFrame->Button(
   -text         => 'Edit',
   -width        => 8,
   -command      => sub {
     if (!$EDIT_OPEN) {
       $EDIT_OPEN = 1;
       &editSource ();
     }
   }
)->pack(-side=>'left');
$balloon->attach($eBut,
                 -balloonmsg => "Press to open the Edit Window");

$cBut = $buttonFrame->Button(
   -text         => 'Catalog',
   -width        => 8,
   -command      => sub {
     if (!$CATALOG_OPEN) {
       open_catalog();
     }
   }
)->pack(-side=>'left');
$balloon->attach($cBut,
                 -balloonmsg => "Press to open the Catalog Window");

$canFrame->grid(qw/-sticky nsew/);
$buttonFrame->grid(qw/-sticky nsew/);

print "made it to just before the windows come up\n" if $locateBug;

$MW->update;

$eBut->configure(-state=>'disabled');
&editSource ();
open_catalog();
$EDIT_OPEN = 1;

plot();
calcTime();

print "made it to just before the main loop\n" if $locateBug;

MainLoop;

=begin __PRIVATE_METHODS__

=head1 METHODS

=over 4

=item B<open_catalog>

Creates an Astro::Catalog object by reading the JCMT catalog which is
distributed with this module.  This catalog is then passed to the
constructor of Tk::AstroCatalog to open a catalog window.

Also sets the C<$CATALOG_OPEN> variable and disables the catalog button.

=cut

sub open_catalog {
  my $astrocat = new Astro::Catalog(Format => 'JCMT',
                       File => dist_file('App-SourcePlot', 'jcmt.cat'),
                       ReadOpt => {incplanets => 0});
  my $catalog = new Tk::AstroCatalog($MW, -addCmd => \&addCommand,
                   -onDestroy => \&reset, -upDate => \&update_status,
                   -catalog => $astrocat);
  $catalog->fillWithSourceList('full');
  $CATALOG_OPEN = 1;
  $cBut->configure(-state=> 'disabled');
}

=item B<reset>

Resets status relating to the catalog window.

Clears the C<$CATALOG_OPEN> variable and enables the catalog button.

=cut

sub reset
{
        $CATALOG_OPEN = 0;
        $cBut->configure(-state=>'normal');
}

=item B<addCommand>

This is the subroutine which is provided to C<Tk::AstroCatalog> to be called
when a source should be added to the display.

It recieves an C<Astro::Coords> object and uses it to construct an enclosing
C<App::SourcePlot::Source> object.

=cut

sub addCommand
{
        my $selected = shift;
        if(@{$selected} != ())
        {
                my $source;
                $LAST_COMMAND = 'Add';
                @UNDO_LIST = ();
                $undoBut->configure(-state => 'normal') if $EDIT_OPEN;
                foreach my $coords (@$selected)
                {
                        $source = new App::SourcePlot::Source($coords);

                        if(!isWithin($source, @SOURCE_LIST))
                        {
                                my $s = $source->copy();
                                $s->color(getColor());
                                push (@SOURCE_LIST, $s);
                                push (@UNDO_LIST, $source->copy());
                        }
                }
                if ($EDIT_OPEN) {
                        fillWithSourceList ($EditWin, 'full');
                }
                plot();
        }
}

=item B<waitForResponse>

Waits until the C<$RESPONSE> variable has been changed.

=cut

sub waitForResponse {
  $RESPONSE = 'NOTHING';
  while ($RESPONSE == 'NOTHING') {
    $MW->update;
  }
  return 0 if $RESPONSE == -1;
  return $RESPONSE;
}

=item B<isWithin>

Checks whether a source is already part of a list. The source is compared
to sources from the list by invoking the C<summary> method on their
C<Astro::Coords> objects.

    next if isWithin($source, @list);

=cut

sub isWithin {
  my $element = shift;
  my @array = @_;
  my $len = @array;
  foreach (@array) {
    if ($element->coords()->summary() eq $_->coords()->summary()) {
      return 1;
    }
  }
  return 0;
}

=item B<remove>

Removes entries from the list which match the given source.  The comparison
is performed in the same way as C<isWithin>.

    remove($source, \@list)

=cut

sub remove {
  my $element = shift;
  my $array = shift;
  my $len = @$array;
  my @temp;
  my $flag = 0;

  for (my $index = 0; $index < $len; $index++) {
    if ($element->coords()->summary() eq $$array[$index]->coords()->summary()) {
      $flag = -1;
    } else {
      $temp[$index+$flag] = $$array[$index];
    }
  }
  @$array = @temp;
}

=item B<update_status>

Invokes the update method of the main window.

=cut

sub update_status {
    $MW->update;
}

=item B<changeDate>

Changes the date to a new date.

=cut

sub changeDate {

  $dateBut->configure(-state => 'disabled');

  my @months = qw/January February March April May June July August
                  September October November December/;
  my $name;

  my $Top = $MW->Toplevel;
  $Top->title('Source Plot UT Date');
  $Top->resizable(0,0);
  my $topFrame = $Top->Frame(-relief=>'groove', -borderwidth =>2)->pack(-padx=>10, -pady=>10);

  # create the day entry
  $topFrame->Label (
                    -text => "Day:"
                   )->grid(-column=>0, -row=>0);
  my $dayEnt = $topFrame->Entry(-relief=>'sunken',
                                -width=>10)->grid(-column=>1, -row=>0, -padx =>10, -pady=>5);

  # create the month menu button
  $topFrame->Label (
                    -text => "Month:"
                   )->grid(-column=>0, -row=>1, -padx =>5, -pady=>5);

  my $strp = new DateTime::Format::Strptime(pattern => '%Y/%m/%d',
                                  time_zone => 'UTC', on_error => 'croak');
  my $dt = $strp->parse_datetime($DATE);
  my $monthEnt = $months[$dt->month() - 1];

  my $mb = $topFrame->Menubutton( -text=>$monthEnt, -relief => 'raised', -width => 10);
  foreach $name (@months) {
    $mb->command(-label =>$name, -command=> sub{
                   $mb->configure( -text => $name );
                   $monthEnt = $name;
                 });
  }
  $mb->grid(-column=>1, -row=>1, -padx =>10, -pady=>5, -sticky=>'w');

  # create the year entry
  $topFrame->Label (
                    -text => "Year:"
                   )->grid(-column=>0, -row=>2, -padx =>5, -pady=>5);
  my $yearEnt = $topFrame->Entry(-relief=>'sunken',
                                 -width=>10)->grid(-column=>1, -row=>2, -padx =>10, -pady=>5);
  $yearEnt->bind('<KeyPress-Return>' =>sub {
                     my $strp = new DateTime::Format::Strptime(
                       pattern => '%Y %B %d', on_error => 'croak');
                     my $dt = $strp->parse_datetime($monthEnt . ' ' .
                        $dayEnt->get() . ' ' . $yearEnt->get());
                     $DATE = $dt->strftime('%Y/%m/%d');
                     destroy $Top;
                });

  # create the update subroutine
  my $complete = sub {
    my $strp = new DateTime::Format::Strptime(
                pattern => '%B %d %Y', on_error => 'croak');
    my $dt = $strp->parse_datetime($monthEnt . ' ' .
                $dayEnt->get() . ' ' . $yearEnt->get());
    $DATE = $dt->strftime('%Y/%m/%d');
    foreach my $source (@SOURCE_LIST) {
      $source->erasePoints();
    }
    plot();
  };

  # create the apply button
  my $F = $Top->Frame->pack();
  my $buttonF = $F->Frame->pack(-side => 'left', -padx => 5, -pady => 10);
  my $okBut = $buttonF->Button(
                   -text         => 'Apply',
                   -command      => $complete
                  )->pack(-side=>'left');
  $okBut->bind('<KeyPress-Return>' => $complete);

  # create the accept button
  $buttonF = $F->Frame->pack(-side => 'right', -padx => 5, -pady => 10);
  my $okBut = $buttonF->Button(
                   -text         => 'Accept',
                   -command      => sub {&$complete; destroy $Top;}
                  )->pack(-side=>'right');
  $okBut->bind('<KeyPress-Return>' => sub {&$complete; destroy $Top;});

  # create the cancel button
  my $canBut = $buttonF->Button(
                   -text         => 'Cancel',
                   -command      => sub{destroy $Top;}
                  )->pack(-side=>'right');
  $canBut->bind('<KeyPress-Return>' =>sub {destroy $Top;});

  # Closing the window should reset $dateBut.
  $Top->bind('<Destroy>', sub {
    my $widget = shift;
    return unless $widget == $Top;
    $dateBut->configure(-state => 'normal');
  });

  $dayEnt->insert(0, $dt->day());
  $yearEnt->insert(0, $dt->year());

  $MW->update;
}

=item B<changeOpt>

Displays a window allowing the options to be changed.

=cut

sub changeOpt {
  my $name;
  my $telEnt = $TEL;
  my ($tb, $tb2);

  $optBut->configure(-state => 'disabled');

  my $Top = $MW->Toplevel;
  $Top->title('Source Plot Options');
  $Top->resizable(0,0);
  my $topFrame = $Top->Frame(-relief=>'groove', -borderwidth =>2)->pack(-padx=>10, -pady=>10);

  # place the telescope menuButton
  $topFrame->Label (
                    -text => "Telescope:"
                   )->grid(-column=>0, -row=>0);
  my $f = $topFrame->Frame()->
    grid(-column=>1, -row=>0, -padx =>10, -pady=>5, -sticky=>'w');
  my $f2 = $topFrame->Frame()->
    grid(-column=>1, -row=>1, -padx =>10, -pady=>5, -sticky=>'w');
  $tb = $f->Menubutton( -text=>$telEnt, -relief => 'raised',
                        -width => 15)->pack(-side=>'left');
  $tb->cascade(-label => 'A - C', -underline => 0);
  $tb->cascade(-label => 'D - F', -underline => 0);
  $tb->cascade(-label => 'G - I', -underline => 0);
  $tb->cascade(-label => 'J - L', -underline => 0);
  $tb->cascade(-label => 'M - O', -underline => 0);
  $tb->cascade(-label => 'P - R', -underline => 0);
  $tb->cascade(-label => 'S - U', -underline => 0);
  $tb->cascade(-label => 'V - X', -underline => 0);
  $tb->cascade(-label => 'Y - Z', -underline => 0);

  my $cm = $tb->cget(-menu);
  my $ac = $cm->Menu;
  my $df = $cm->Menu;
  my $gi = $cm->Menu;
  my $jl = $cm->Menu;
  my $mo = $cm->Menu;
  my $pr = $cm->Menu;
  my $su = $cm->Menu;
  my $vx = $cm->Menu;
  my $yz = $cm->Menu;

  $tb->entryconfigure('A - C', -menu => $ac);
  $tb->entryconfigure('D - F', -menu => $df);
  $tb->entryconfigure('G - I', -menu => $gi);
  $tb->entryconfigure('J - L', -menu => $jl);
  $tb->entryconfigure('M - O', -menu => $mo);
  $tb->entryconfigure('P - R', -menu => $pr);
  $tb->entryconfigure('S - U', -menu => $su);
  $tb->entryconfigure('V - X', -menu => $vx);
  $tb->entryconfigure('Y - Z', -menu => $yz);

  foreach $name ($telObject->telNames()) {
    if ($name =~ /^[A-Ca-c]/) {
      $ac->command(-label =>$name, -command=> sub{
                   $tb->configure( -text => $name );
                   $telEnt = $name;
                 });
    } elsif ($name =~ /^[D-Fd-f]/) {
      $df->command(-label =>$name, -command=> sub{
                   $tb->configure( -text => $name );
                   $telEnt = $name;
                 });
    } elsif ($name =~ /^[G-Ig-i]/) {
      $gi->command(-label =>$name, -command=> sub{
                   $tb->configure( -text => $name );
                   $telEnt = $name;
                 });
    }elsif ($name =~ /^[J-Lj-l]/) {
      $jl->command(-label =>$name, -command=> sub{
                   $tb->configure( -text => $name );
                   $telEnt = $name;
                 });
    }elsif ($name =~ /^[M-Om-o]/) {
      $mo->command(-label =>$name, -command=> sub{
                   $tb->configure( -text => $name );
                   $telEnt = $name;
                 });
    }elsif ($name =~ /^[P-Rp-r]/) {
      $pr->command(-label =>$name, -command=> sub{
                   $tb->configure( -text => $name );
                   $telEnt = $name;
                 });
    } elsif ($name =~ /^[S-Us-u]/) {
      $su->command(-label =>$name, -command=> sub{
                   $tb->configure( -text => $name );
                   $telEnt = $name;
                 });
    } elsif ($name =~ /^[V-Xv-x]/) {
      $vx->command(-label =>$name, -command=> sub{
                   $tb->configure( -text => $name );
                   $telEnt = $name;
                 });
    } elsif ($name =~ /^[Y-Zy-z]/) {
      $yz->command(-label =>$name, -command=> sub{
                   $tb->configure( -text => $name );
                   $telEnt = $name;
                 });
    }
  }

  # place the middle time field
  $topFrame->Label (
                    -text => "Center Time (in HST):"
                   )->grid(-column=>0, -row=>2, -padx =>5, -pady=>5);
  my $timeEnt = $TIME;
  $topFrame->Entry(-relief=>'sunken',
                   -textvariable=> \$timeEnt,
                   -width=>10)->grid(-column=>1, -row=>2, -padx =>10, -pady=>5);

  # place the y-axis menuButton
  $topFrame->Label (
                    -text => "y-axis:"
                   )->grid(-column=>0, -row=>4, -padx =>5, -pady=>5);
  my $yEnt = $Y_AXIS;
  my $yb = $topFrame->Menubutton( -text=>$yEnt, -relief => 'raised', -width => 15);
  foreach $name (@axes) {
    $yb->command(-label =>$name, -command=> sub{
                   $yb->configure( -text => $name );
                   $yEnt = $name;
                 });
  }
  $yb->grid(-column=>1, -row=>4, -padx =>10, -pady=>5, -sticky=>'w');

  # inserting cascading choices

  # place the x-axis menuButton
  $topFrame->Label (
                    -text => "x-axis:"
                   )->grid(-column=>0, -row=>3, -padx =>5, -pady=>5);
  my $xEnt = $X_AXIS;
  my $xb = $topFrame->Menubutton( -text=>$xEnt, -relief => 'raised', -width => 15);
  foreach $name (@axes) {
    $xb->command(-label =>$name, -command=> sub{
                   $xb->configure( -text => $name );
                   $xEnt = $name;
                 });
  }
  $xb->grid(-column=>1, -row=>3, -padx =>10, -pady=>5, -sticky=>'w');

  # place the Apply button
  my $F = $Top->Frame->pack();
  my $buttonF = $F->Frame->pack(-side => 'left', -padx => 5, -pady => 10);
  $buttonF->Button(
                   -text         => 'Apply',
                   -command      => sub{
                     $X_AXIS = $xEnt;
                     $Y_AXIS = $yEnt;
                     if ($TEL ne $telEnt || $TIME ne $timeEnt) {
                       foreach (@SOURCE_LIST) {$_->erasePoints()};
                     } else {
                       foreach (@SOURCE_LIST) {$_->eraseTimeDot()};
                     }
                     $TIME = $timeEnt;
                     $TIME =~ s/^\s+//;
                     $TIME =~ s/\s+$//;
                     $TIME =~ s/\s+/:/g;
                     $TEL = $telEnt;
                     $telObject->name($TEL);
                     plot();
                   }
                  )->pack(-side=>'left');

  # place the ok button
  $buttonF = $F->Frame->pack(-side => 'right', -padx => 5, -pady => 10);
  $buttonF->Button(
                   -text         => 'Accept',
                   -command      => sub{
                     $X_AXIS = $xEnt;
                     $Y_AXIS = $yEnt;
                     if ($TEL ne $telEnt || $TIME ne $timeEnt) {
                       foreach (@SOURCE_LIST) {$_->erasePoints()};
                     } else {
                       foreach (@SOURCE_LIST) {$_->eraseTimeDot()};
                     }
                     $TIME = $timeEnt;
                     $TIME =~ s/^\s+//;
                     $TIME =~ s/\s+$//;
                     $TIME =~ s/\s+/:/g;
                     $TEL = $telEnt;
                     $telObject->name($TEL);
                     plot();
                     destroy $Top;
                   }
                  )->pack(-side=>'right');

  # place the cancel button
  $buttonF->Button(
                   -text         => 'Cancel',
                   -command      => sub{
                     destroy $Top;
                   }
                  )->pack(-side=>'right');

  # Closing the window should reset $optBut.
  $Top->bind('<Destroy>', sub {
    my $widget = shift;
    return unless $widget == $Top;
    $optBut->configure(-state => 'normal');
  });

  $buttonF->Button(
                   -text         => 'Save Setting',
                   -command      => sub{
                        $X_AXIS = $xEnt;
                        $Y_AXIS = $yEnt;
                        $TEL = $telEnt;
                        $TIME = $timeEnt;
                        $defaults->values('TEL', $TEL);
                        $defaults->values('XAXIS', $X_AXIS);
                        $defaults->values('YAXIS', $Y_AXIS);
                        $defaults->values('TIME', $TIME);
                        $defaults->w_defaults();
                   }
                  )->pack(-side=>'right');
  $MW->update;
}

=item B<addPlanetSource>

Adds a planet source into the plotting list.  The planet number
is currently unused.

    addPlanetSource($name, $number);

=cut

sub addPlanetSource {
  my $name = shift;
  my $number = shift;
  my $source = new App::SourcePlot::Source($name);
  if (!isWithin ($source, @SOURCE_LIST)) {
    $source->color(getColor());
    push (@SOURCE_LIST, $source);
  }
}

=item B<getSource>

Prompts the user to enter source coords and name.
Can specify previous source object to edit.

Returns a Source object.

=cut

sub getSource {
  my $source = shift;
  my @Epocs = ('RJ', 'RB');
  my $name;

  my $Top = $MW->Toplevel;
  $Top->title('Source Plot');
  $Top->resizable(0,0);
  my $topFrame = $Top->Frame(-relief=>'groove', -borderwidth =>2, -width =>50)->pack(-padx=>10, -fill => 'x', -ipady=>10, -pady => 10);

  $topFrame->Label (
                    -text => "Name:"
                   )->grid(-column=>0, -row=>0);
  my $nameEnt = $topFrame->Entry(-relief=>'sunken',
                                -width=>15)->grid(-column=>1, -row=>0, -padx =>10, -pady=>3);
  $nameEnt->insert(0,$source->name());

  $topFrame->Label (
                    -text => "Ra:"
                   )->grid(-column=>0, -row=>1);
  my $raEnt = $topFrame->Entry(-relief=>'sunken',
                                -width=>15)->grid(-column=>1, -row=>1, -padx =>10, -pady=>3);
  $raEnt->insert(0,$source->ra());

  $topFrame->Label (
                    -text => "Dec:"
                   )->grid(-column=>0, -row=>2);
  my $decEnt = $topFrame->Entry(-relief=>'sunken',
                                -width=>15)->grid(-column=>1, -row=>2, -padx =>10, -pady=>3);
  $decEnt->insert(0,$source->dec());

  $topFrame->Label (
                    -text => "Epoc:"
                   )->grid(-column=>0, -row=>3, -padx =>5, -pady=>5);
  my $epocEnt = $source->epoc();
  my $epocB = $topFrame->Menubutton( -text=>$epocEnt, -relief => 'raised', -width => 15);
  foreach $name (@Epocs) {
    $epocB->command(-label =>$name, -command=> sub{
                   $epocB->configure( -text => $name );
                   $epocEnt = $name;
                 });
  }
  $epocB->grid(-column=>1, -row=>3, -padx =>10, -pady=>5, -sticky=>'w');

  my $buttonF = $Top->Frame->pack(-padx=>10, -pady=>10);
  $buttonF->Button(
                   -text         => 'Ok',
                   -command      => sub{
                     $source->configure($nameEnt->get(),
                                        $raEnt->get(),
                                        $decEnt->get(),
                                        $epocEnt);
                     destroy $Top;
                     $RESPONSE = 1;
                   }
                  )->pack(-side=>'right');
  $buttonF->Button(
                   -text         => 'Cancel',
                   -command      => sub{
                     destroy $Top;
                     $RESPONSE = -1;
                   }
                  )->pack(-side=>'right');
  $Top->update;
  $Top->grab;
}

=item B<searchFor>

Searches for sources that match the information
passed in the form of a partially filled source object.

=cut

sub searchFor {
  my $info = shift;
  my @Sources = @_;
  my @rSources = ();
  my $source;
  my $i;
  my $debug = 0;

  # set the info name
  my $iname = $info->name;
  $iname =~ tr/A-Z/a-z/;

  # set the info Ra
  my $iRa = $info->ra;
  my $RaDecimal = ($iRa =~ /\./);
  my @iraParts = split (/:/, $iRa);

  # set the info Dec
  my $iDec = $info->dec;
  my $idecNeg = ($iDec =~ /\-/);
  my $DecDecimal = ($iDec =~ /\./);
  my @idecParts = split (/:/, $iDec);

  foreach $source (@Sources) {
    my $passed = 1;

    # check the name
    if ($iname ne '') {
      my $name = $source->name;
      $name =~ tr/A-Z/a-z/;
      print "checking names  $iname   vs   $name" if $debug;
      if (!($name =~ /$iname/)) {
        print "...Did not match ...\n" if $debug;
        $passed = 0;
      } else {
        print "\n" if $debug;
      }
    }

    # check the Ra
    if ($iRa ne '') {
      my $Ra = $source->ra;
      $Ra =~ s/^\s+//;
      $Ra =~ s/\s+$//;
      $Ra =~ s/s+/:/g;
      $Ra =~ s/\..*// if !$RaDecimal;
      print "checking ra  $iRa   vs   $Ra\n" if $debug;
      my @raParts = split (/:/, $Ra);
      $i = 0;
      foreach (@iraParts) {
        print "     checking $_ vs $raParts[$i]\n" if $debug;
        if ($_ != $raParts[$i]) {
          $passed = 0;
        }
        $i++;
      }
    }

    # check the Dec
    if ($iDec ne '') {
      my $Dec = $source->dec;
      $Dec =~ s/^\s+//;
      $Dec =~ s/\s+$//;
      $Dec =~ s/\+//g;
      $Dec =~ s/\-\s+/\-/;
      $Dec =~ s/s+/:/g;
      my $decNeg = ($Dec =~ /\-/);
      if ($decNeg != $idecNeg) {
        $passed = 0;
      } else {
        $Dec =~ s/\..*// if !$DecDecimal;
        print "checking dec  $iDec   vs   $Dec\n" if $debug;
        my @decParts = split (/:/, $Dec);
        $i = 0;
        foreach (@idecParts) {
          print "     checking $_ vs $decParts[$i]\n" if $debug;
          if ($_ != $decParts[$i]) {
            $passed = 0;
          }
          $i++;
        }
      }
    }

    # is it ok to add?
    if ($passed) {
      push (@rSources, $source);
    }
  }
  return @rSources;
}

=item B<editSource>

Edits the existing source list.

=cut

sub editSource {
  my (@selected) = ();
  my $udeb = 0;   #debugger

  $eBut->configure(-state=>'disabled');

  my $Top = $MW->Toplevel ();
  $Top->geometry('+600+90');
  $Top->title('Source Plot: Edit Window');
  $Top->resizable(0,0);
  my $topFrame = $Top->Frame(-relief=>'groove', -borderwidth =>2, -width =>50)->pack(-padx=>10, -fill => 'x', -ipady=>3, -pady => 10);

  # create the header
  my $headFrame = $topFrame->Frame(-relief=>'flat', -borderwidth =>2)->grid(-row=>0, -sticky=>'nsew', -ipadx => 3);
  my $head = $topFrame->Text(
      -wrap       => 'none',
      -relief     => 'flat',
      -foreground => 'midnightblue',
      -width      => 50,
      -height     => 1,
      -font       => '-*-Courier-Medium-R-Normal--*-120-*-*-*-*-*-*',
      -takefocus  => 0
  )->grid (-sticky=>'ew', -row =>0);
  my $title = sprintf "%5s  %-16s  %-12s  %-13s  %-4s", 'Index', 'Name', 'Ra', 'Dec', 'Epoc';
  $head->insert ('end', $title);
  $head->configure(-state=>'disabled');

  # create the scollable text
  my $T = $topFrame->Scrolled('Text',
                              -scrollbars => 'e',
                              -background => '#333333',
                              -wrap       => 'none',
                              -width      => 60,
                              -height     => 15,
                              -font       => '-*-Courier-Medium-R-Normal--*-120-*-*-*-*-*-*',
                              -setgrid    => 1,
                             )->grid(qw/-sticky nsew/, -row=>1);
  $T->bindtags(qw/widget_demo/);        # remove all bindings but dummy "widget_demo"
 
  # create the done button
  my $buttonF = $Top->Frame->pack(-padx=>10, -pady=>10, -fill =>'x');
  my $doneBut = $buttonF->Button(
                   -text         => 'Done',
                   -width        => 4,
                   -command      => sub{
                     destroy $Top;
                   }
                  )->pack(-side=>'right');
  $balloon->attach($doneBut,
                 -balloonmsg => "Press to close the Edit Window");

  # Closing the window should reset $eBut.
  $Top->bind('<Destroy>', sub {
    my $widget = shift;
    return unless $widget == $Top;
    $eBut->configure(-state=>'normal');
    $EDIT_OPEN = 0;
  });

  # create the On / Off button
  my $OOBut = $buttonF->Button( -text=>'ON/Off',
                    -width        => 5,
                    -command=> sub{
                      my $source;
                      foreach $source (@selected) {
                        if ($source->active()) {
                          tagOnOff ($source->name(), 0);
                          $source->active(0);
                          $T->tag('configure', 'd'.$source->index(), -foreground => 'black');
                        } else {
                          tagOnOff ($source->name(), 1, $source->color(), 'yellow');
                          $source->active(1);
                          $T->tag('configure', 'd'.$source->index(), -foreground => $source->color());
                        }
                      }
                      @selected = ();
                    })->pack(-side => 'left');
  $balloon->attach($OOBut,
                 -balloonmsg => "Press to turn the selected\nsources On/Off");

  # create the delete all button
  my $manipF = $buttonF->Frame->pack(-side=>'left', -padx=>30);
  my $DABut = $manipF->Button(
                   -text         => 'Delete All',
                   -width        => 8,
                   -command      => sub{
                     $LAST_COMMAND = 'Delete';
                     foreach my $source (@SOURCE_LIST) {
                       tagOnOff ($source->name(), 1, $source->color(), 'yellow');
                       $source->active(1);
                       $EditWin->{Text}->tagDelete('d'.$source->index());
                     }
                     @UNDO_LIST = @SOURCE_LIST;
                     $undoBut->configure(-state => 'normal') if $EDIT_OPEN;
                     @SOURCE_LIST = ();
                     @selected = ();
                     fillWithSourceList ($EditWin, 'full');
                     plot();
                   }
                  )->pack(-side=>'left');
  $balloon->attach($DABut,
                 -balloonmsg => "Press to delete all sources\nfrom the Edit Window");

  # create the delete button
  my $delBut = $manipF->Button(
                   -text         => 'Delete',
                   -width        => 6,
                   -command      => sub{
                     my $len = @selected;
                     $LAST_COMMAND = 'Delete';
                     @UNDO_LIST = ();
                     if ($len > 0) {
                       $undoBut->configure(-state => 'normal');
                     } else {
                       $undoBut->configure(-state => 'disabled');
                     }
                     foreach my $source (@selected) {
                       tagOnOff ($source->name(), 1, $source->color(), 'yellow');
                       $source->active(1);
                       push (@UNDO_LIST, $source);
                       $plotter->delete('l'.$source->name());
                       $plotter->delete('fo'.$source->name());
                       $plotter->delete('t'.$source->name());
                       $plotter->delete('time'.$source->name());
                       $plotter->delete('ttimeDot'.$source->name());
                       $plotter->delete('ltimeDot'.$source->name());
                       $plotter->delete('timeDot'.$source->name());
                       $EditWin->{Text}->tagDelete('d'.$source->index());
                       remove ($source, \@SOURCE_LIST);
                     }
                     @selected = ();
                     fillWithSourceList ($EditWin, 'full');
                   }
                  )->pack(-side=>'left');
  $balloon->attach($delBut,
                 -balloonmsg => "Press to delete the\nselected sources");

  # create the delete button
  $undoBut = $manipF->Button(
                   -text         => 'Undo',
                   -command      => sub{
                     if ($LAST_COMMAND eq 'Add') {
                       print "Last command was add\n" if $udeb;
                       foreach my $source (@UNDO_LIST) {
                         remove ($source, \@SOURCE_LIST);
                         print "removing ".$source->name."\n" if $udeb;
                       }
                     } elsif ($LAST_COMMAND eq 'Delete') {
                       print "Last command was removed\n" if $udeb;
                       foreach my $source (@UNDO_LIST) {
                         push (@SOURCE_LIST, $source);
                         print "Adding ".$source->name."\n" if $udeb;
                       }
                     } elsif ($LAST_COMMAND eq 'Change') {
                       print "Last command was changed\n" if $udeb;
                       my $source = pop (@UNDO_LIST);
                       my $orig = pop (@UNDO_LIST);
                       print "Reconfiguring ".$source->name."\n" if $udeb;
                       $source->configure($orig);
                       print "Clearing ".$source->name."\n" if $udeb;
                       $source->erasePoints();
                     }
                     $LAST_COMMAND = '';
                     @UNDO_LIST = ();
                     @selected = ();
                     $undoBut->configure(-state => 'disabled') if $EDIT_OPEN;
                     fillWithSourceList ($EditWin, 'full');
                     plot();
                   }
                  )->pack(-side=>'left');
  $undoBut->configure(-state => 'disabled') if $EDIT_OPEN;
  $balloon->attach($undoBut,
                 -balloonmsg => "Press to undo the last\nmajor command");

  # create the add button
  my $newBut = $manipF->Button( -text=>'New',
                    -width        => 4,
                    -command=> sub{
                        my $source = new App::SourcePlot::Source();
                        &getSource ($source);
                        my $res = &waitForResponse();
                        if ($res && !isWithin ($source, @SOURCE_LIST)) {
                          $source->color(getColor());
                          push (@SOURCE_LIST, $source);
                          fillWithSourceList ($EditWin, 'full');
                          $LAST_COMMAND = 'Add';
                          @UNDO_LIST = ();
                          $undoBut->configure(-state => 'normal') if $EDIT_OPEN;
                          push (@UNDO_LIST, $source);
                          plot();
                        }
                      })->pack(-side => 'left');
  $balloon->attach($newBut,
                 -balloonmsg => "Press to manually\nadd a source");

  # create the planet button
  my $planBut = $manipF->Menubutton(
     -text         =>'Planets',
     -width        => 7,
     -relief       => 'raised');
  {
      my $k = 0;
      foreach my $plan (@planets) {
          my $c = $k;
          $planBut->command(-label=>$plan, -command=> sub{
              &addPlanetSource ($plan, $c);
              print "$TEL is tel  \n" if $locateBug;
              fillWithSourceList ($EditWin, 'full');
              plot();
          });
          $k++;
      }
  }
  $planBut->command(-label=>'All', -command=> sub{
                      my $j = 0;
                      foreach (@planets) {
                        &addPlanetSource ($_, $j);
                        $j++;
                      }
                      fillWithSourceList ($EditWin, 'full');
                      plot();
               });
  $planBut->pack(-side => 'left');
  $balloon->attach($planBut,
                 -balloonmsg => "Press to add a planet\nto the plot");

  $EditWin->{'Window'} = $Top;
  $EditWin->{'Text'} = $T;
  $EditWin->{'Selected'} = \@selected;
  $EditWin->{'Sources'} = \@SOURCE_LIST;

  fillWithSourceList ($EditWin, 'full');

  $MW->update;
}

=item B<fillWithSourceList>

Fills a Text box with the list of current sources.

=cut

sub fillWithSourceList {
  my(@bold, @normal);
  my $Window = shift;
  my $T = $Window->{'Text'};
  my $selected = $Window->{'Selected'};
  my $arrayOfSources = $Window->{'Sources'};
  my $task = shift;
  my $sort = shift;
  my $index = shift;
  my (@sources);
  my ($source);
  my @entered = ();
  my($line,$itag);

  @sources = @$arrayOfSources;
  #@sources = sort by_name @$arrayOfSources;

  if(defined $sort)
  {
    for($sort)
    {
        /unsorted/ and do { @sources = @$arrayOfSources;last;};
        /name/          and do { @sources = sort by_name @$arrayOfSources;last;};
        /ra/          and do { @sources = sort by_ra @$arrayOfSources;last;};
        /dec/          and do { @sources = sort by_dec @$arrayOfSources;last;};
                die "Unknown value for form variable \$sort \n";
    }
  }

  # Enable infobox for access
  $T->configure(-state=>'normal');

  # Clear the existing widgets
  if (defined $task && $task eq 'full') {
    $T->delete('1.0','end');
    foreach my $source (@sources) {
      $T->tagDelete('d'.$source->index());
    }
  }

  # Set up display styles
  if ($T->depth > 1) {
    @bold   = (-background => "#eeeeee", qw/-relief raised -borderwidth 1/);
    @normal = (-background => undef, qw/-relief flat/);
  } else {
    @bold   = (qw/-foreground white -background black/);
    @normal = (-foreground => undef, -background => undef);
  }
  $T->tag(qw/configure normal -foreground blue/);
  $T->tag(qw/configure inactive -foreground black/);
  $T->tag(qw/configure selected -foreground red/);
  foreach ( @COLOR_LIST ){
    $T->tag('configure',$_, -foreground => $_);
  }

  # Insert the current values
  if (defined $task && $task eq 'full') {
    my $len = @sources;
    for ($index=0; $index < $len; $index++) {
      $source = $sources[$index];
      $source->index($index);
      $line = $source->dispLine();
      if (&isWithin ($source, @$selected)) {
        inswt($T,"$line\n","d$index",'selected');
      } else {
        if ($source->active()) {
          if ($source->color() ne '') {
            inswt($T,"$line\n","d$index",$source->color());
          } else {
            inswt($T,"$line\n","d$index",'normal');
          }
        } else {
          inswt($T,"$line\n","d$index",'inactive');
        }
      }
    }

    $len = @sources;
    for ($itag=0; $itag < $len; $itag++) {
      my $dtag = "d$itag";
      $T->tag('bind', $dtag, '<Any-Enter>' =>
              sub {
                shift->tag('configure', $dtag, @bold);
                if ($Window->{'Changeable'} && $sources[substr($dtag,1,99)]->active()) {
                  $plotter->configureTag ('l'.$sources[substr($dtag,1,99)]->name(), -width => 3);
                }
              }
             );
      $T->tag('bind', $dtag, '<Any-Leave>' =>
              sub {
                shift->tag('configure', $dtag, @normal);
                if ($Window->{'Changeable'} && $sources[substr($dtag,1,99)]->active()) {
                  $plotter->configureTag ('l'.$sources[substr($dtag,1,99)]->name(), -width => 1);
                }
              }
             );
      $T->tag('bind', $dtag, '<ButtonRelease-1>' =>
              sub {
                if (!$BUSY){
                  if (! &isWithin ($sources[substr($dtag,1,99)], @$selected) ) {
                    shift->tag('configure', $dtag, -foreground => 'red');
                    push (@$selected, $sources[substr($dtag,1,99)]);
                  } else {
                    if ($sources[substr($dtag,1,99)]->color() ne '') {
                      shift->tag('configure', $dtag, -foreground => $sources[substr($dtag,1,99)]->color());
                    } else {
                      shift->tag('configure', $dtag, -foreground => 'blue');
                    }
                    &remove ($sources[substr($dtag,1,99)], $selected);
                  }
                }
              }
             );
      if ($Window->{'Changeable'}) {
        $T->tag('bind', $dtag, '<Double-1>' => sub {
                  my $source = $sources[substr($dtag,1,99)];
                  $LAST_COMMAND = 'Change';
                  @UNDO_LIST = ($source->coords());
                  &getSource ($source);
                  my $res = &waitForResponse();
                  if( $res ) {
                    $undoBut->configure(-state => 'normal') if $EDIT_OPEN;
                  } else {
                    $undoBut->configure(-state => 'disabled') if $EDIT_OPEN;
                  }
                  push (@UNDO_LIST, $source);
                  $source->erasePoints();
                  fillWithSourceList ($EditWin, 'full');
                  plot();
              });
      }else {
        $T->tag('bind', $dtag, '<Double-1>' => sub {
                  $BUSY = 1;
                  my $source = $sources[substr($dtag,1,99)];
                  push (@$selected, $source);
                  $LAST_COMMAND = 'Add';
                  @UNDO_LIST = ();
                  $undoBut->configure(-state => 'normal') if $EDIT_OPEN;
                  $MW->update();
                  my $T = shift;
                  foreach $source (@$selected) {
                    if (!isWithin ($source, @SOURCE_LIST)) {
                      my $s = $source->copy();
                      $s->color(getColor());
                      push (@SOURCE_LIST, $s);
                      push (@UNDO_LIST, $s);
                    }
                    $T->tag('configure', 'd'.$source->index(), -foreground => 'blue');
                  }
                  @$selected = ();
                  if ($EDIT_OPEN) {
                    fillWithSourceList ($EditWin, 'full');
                  }
                  plot();
                  $BUSY = 0;
                });
      }
    }
  }

  $T->mark(qw/set insert 1.0/);

  # Disable access to infobox
  $T->configure(-state=>'disabled');

}

=item B<plot>

Plots the graphs, including axis.

=cut

sub plot {
  print "Entered plot\n" if $locateBug;
  my ($xworldRatio, $yworldRatio);
  my $debug = 0;
  $TIME =~ s/^\s+//;
  $TIME =~ s/\s+$//;
  $TIME =~ s/\s+/:/g;
  my ($timeH, $min, $sec) = split (/:/, $TIME,3);
  my $XSpaceForTime = 0;
  my $YSpaceForTime = 0;
  my $special = 0;
  my $lstDiffX;
  my $lstDiffY;

  $XSpaceForTime = $xborder if $Y_AXIS =~ /time/i;
  $YSpaceForTime = $yborder if $X_AXIS =~ /time/i;
  $timeH += $min/60 + $sec/3600;

  #clear the plot
  $plotter->clean();

  # calc the world coords
  print "    Calculating the world coordinate system\n" if $locateBug;
  if ($X_AXIS =~ /time/i) {
    my $strp = new DateTime::Format::Strptime(
                 pattern => '%Y/%m/%d %H:%M:%S',
                 on_error => 'croak');

    my $DATESTR = $DATE;
    $DATESTR =~ s/\/$//;
    my $dt = $strp->parse_datetime($DATESTR . ' ' . $TIME);

    $dt->subtract(hours => 2);

    my ($lst, $mjd) = ut2lst($dt->year(), $dt->month(), $dt->day(),
                             $dt->hour(), $dt->minute(), $dt->second(),
                             $telObject->long_by_rad());

    $dt->add(hours => 1);

    my ($lst2, $mjd2) = ut2lst($dt->year(), $dt->month(), $dt->day(),
                               $dt->hour(), $dt->minute(), $dt->second(),
                               $telObject->long_by_rad());

    if ($lst2 < $lst) {
      $lst2 += 2*pi;
    }

    $lstDiffX = $lst2 - $lst;
    $xworldRatio = (24*$lstDiffX)/($xplot - $xborder*2 - $XSpaceForTime);
    $minX = $lst;
    $maxX = $lst + 24*$lstDiffX;
    print "x-axis is time\n" if $debug;
  } elsif ($X_AXIS =~ /air mass/i) {
    $xworldRatio = 90/($xplot - $xborder*2 - $XSpaceForTime);
    $minX = 0;
    $maxX = 90;
    print "x-axis is ele\n" if $debug;
  } elsif ($X_AXIS =~ /elevation/i) {
    $xworldRatio = 90/($xplot - $xborder*2 - $XSpaceForTime);
    $minX = 0;
    $maxX = 90;
    print "x-axis is ele\n" if $debug;
  } elsif ($X_AXIS =~ /azimuth/i) {
    $xworldRatio = 360/($xplot - $xborder*2 - $XSpaceForTime);
    $minX = 0;
    $maxX = 360;
    print "x-axis is pa\n" if $debug;
  } elsif ($X_AXIS =~ /parallactic angle/i) {
    $xworldRatio = 360/($xplot - $xborder*2 - $XSpaceForTime);
    $minX = -180;
    $maxX = 180;
    print "x-axis is az\n" if $debug;
  } else {
    print "ERROR:  X axis undefined!!\n\n";
    $minX = 0;
    $maxX = 0;
  }
  if ($Y_AXIS =~ /time/i) {
    my $strp = new DateTime::Format::Strptime(
                 pattern => '%Y/%m/%d %H:%M:%S',
                 on_error => 'croak');

    my $dt = $strp->parse_datetime($DATE . ' ' . $TIME);

    $dt->subtract(hours => 2);

    my ($lst, $mjd) = ut2lst($dt->year(), $dt->month(), $dt->day(),
                             $dt->hour(), $dt->minute(), $dt->section(),
                             $telObject->long_by_rad());

    $dt->add(hours => 1);

    my ($lst2, $mjd2) = ut2lst($dt->year(), $dt->month(), $dt->day(),
                               $dt->hour(), $dt->minute(), $dt->section(),
                               $telObject->long_by_rad());

    if ($lst2 < $lst) {
      $lst2 += 2*pi;
    }

    $lstDiffY = $lst2 - $lst;
    $yworldRatio = (-24*$lstDiffY)/($yplot - $yborder*2 - $YSpaceForTime);
    $maxY = $lst + 24 * $lstDiffY;
    $minY = $lst;
    print "y-axis is time\n" if $debug;
  } elsif ($Y_AXIS =~ /air mass/i) {
    $yworldRatio = -90/($yplot - $yborder*2- $YSpaceForTime);
    $maxY = 90;
    $minY = 0;
    print "y-axis is ele\n" if $debug;
  } elsif ($Y_AXIS =~ /elevation/i) {
    $yworldRatio = -90/($yplot - $yborder*2- $YSpaceForTime);
    $maxY = 90;
    $minY = 0;
    print "y-axis is ele\n" if $debug;
  } elsif ($Y_AXIS =~ /azimuth/i) {
    $yworldRatio = -360/($yplot - $yborder*2- $YSpaceForTime);
    $minY = 0;
    $maxY = 360;
    print "y-axis is az\n" if $debug;
  } elsif ($Y_AXIS =~ /parallactic angle/i) {
    $yworldRatio = -360/($yplot - $yborder*2- $YSpaceForTime);
    $minY = -180;
    $maxY = 180;
    print "y-axis is pa\n" if $debug;
  } else {
    print "ERROR:  Y axis undefined!!\n\n";
    $minY = 0;
    $maxY = 0;
  }
  if ((($Y_AXIS =~ /azimuth/i) && ($X_AXIS =~ /elevation/i)) || (($X_AXIS =~ /azimuth/i) && ($Y_AXIS =~ /elevation/i))|| (($Y_AXIS =~ /azimuth/i) && ($X_AXIS =~ /air mass/i)) || (($X_AXIS =~ /azimuth/i) && ($Y_AXIS =~ /air mass/i))) {
    $yworldRatio = -180/($yplot - $yborder*2);
    $xworldRatio = 180/($xplot - $xborder*2);
    $minY = 0;
    $maxY = 180;
    $minX = 0;
    $maxX = 180;
    $plotter->usingWorld(0);
    $plotter->worldCenter($xplot/2, $yplot/2);
    $plotter->usingWorld(1);
    if(($X_AXIS =~ /elevation/i) || ($Y_AXIS =~ /elevation/i))
    {
            $special = 1;
    }
    else  # air mass case
    {
        $special = 2;
    }
    print "axes is special\n" if $debug;
  }
  print "    Setting the world coordinate system\n" if $locateBug;
  $plotter->worldToPixRatio($xworldRatio, $yworldRatio);
  $plotter->worldAtZero($minX, $minY);

  # draw the grid lines - x axis
  $plotter->fontColor('White');
  $plotter->drawColor('dark green');
  if (($special == 1) ||($special == 2)) {
    # draw the angle grid lines
    for (my $z = 0; $z < 360; $z += 15) {
      my $tz = (90 - $z) * pi / 180;
      my $x = 92 * cos $tz;
      my $y = 92 * sin $tz;
      $plotter->drawLine (0,0,$x, $y, 'grid');
    }
    #label the angle grid lines
    for (my $z = 0; $z < 360; $z += 15) {
      my $tz = (90 - $z) * pi / 180;
      my $x = 95 * cos $tz;
      my $y = 95 * sin $tz;
      if ($z == 0) {
        $plotter->drawText ($x, $y, 'N', 'twhite');
      } elsif ($z == 90) {
        $plotter->drawText ($x, $y, 'E', 'twhite');
      } elsif ($z == 180) {
        $plotter->drawText ($x, $y, 'S', 'twhite');
      } elsif ($z == 270) {
        $plotter->drawText ($x, $y, 'W', 'twhite');
      } else {
        $plotter->drawText ($x, $y, $z, 'twhite');
      }
    }

    # draw the outside circle
    $plotter->drawColor('white');
    $plotter->penWidth(2);
    $plotter->drawOval(-90,-90,90,90, 'owhite');
    $plotter->penWidth(1);

   if($special == 1) # elevation -azimuth case
   {
           #draw the elevation labels
             $plotter->drawColor ('dark green');
            my $texty = $plotter->toWy(5) - $plotter->toWy(0);
            for (my $i = 0; $i<90; $i+=10) {
                      $plotter->drawOval(-$i, -$i, $i, $i, 'grid');
                      $plotter->drawText(0,$i-$texty,90 - $i, 'twhite');
            }

            $plotter->usingWorld(0);
            $plotter->worldCenter($xborder, $yplot-$yborder);
            $plotter->usingWorld(1);
   }
   if ($special == 2)  #azimuth - air mass case
   {
    #draw the elevation labels
    $plotter->drawColor ('dark green');
    my $ytext = $plotter->toWx(5) - $plotter->toWx(0);
    for (qw/1.0 1.25 1.5 1.75 2.0 3.0 4.0 5.0/)
    {
        my $new_el = 90 - am_to_deg($_);
        $plotter->drawOval(-$new_el, -$new_el, $new_el, $new_el, 'grid');
    }
    $plotter->drawText (0, 0,1.0,'twhite');
    $plotter->drawText (0, 39,1.25,'twhite');
    $plotter->drawText (0, 50,1.5,'twhite');
    $plotter->drawText (0, 57,1.75,'twhite');
    $plotter->drawText (0, 61,2.0,'twhite');
    $plotter->drawText (0, 71,3.0,'twhite');
    $plotter->drawText (0, 76,4.0,'twhite');
    $plotter->drawText (0, 80,5.0,'twhite');
    $plotter->usingWorld(0);
    $plotter->worldCenter($xborder, $yplot-$yborder);
    $plotter->usingWorld(1);
   } 
  }elsif ($X_AXIS =~ /time/i) {
    my $ho = $timeH - 8;
    for ( my $hour = $minX+$lstDiffX*4; $hour < $maxX; $hour += $lstDiffX*4 ) {
      my $tel = $telObject;
      $plotter->drawLine($hour, $minY, $hour, $maxY, 'grid');

      # calculate the HST time
      my $ti = $ho;
      $ti -= 24 if $ti >= 24;
      $ti += 24 if $ti < 0;
      my ($h, $m) = split (/\./, $ti);
      $m = ('.'.$m) * 60;
      $m = '0'.$m if $m < 10;
      my $y = $plotter->toWy ($yplot - $yborder*3/2);
      $plotter->drawText($hour, $y, sprintf("%2s:%2s", $h, $m), 'twhite');

      # calculate the ut time
      my $uh = $h + 10;
      $uh -= 24 if $uh >= 24;
      my $uy = $plotter->toWy ($yborder/2);
      $plotter->drawText($hour, $uy, sprintf("%2s:%2s", $uh, $m), 'twhite');

      #calculate the lst time
      my $lst;
      my $si = '+';
      my @parts;
      $si = '-' if ($hour < 0);
      $lst = $hour;
      while ($lst > 2 * pi) {
        $lst -= 2*pi;
      }
      my ($si, @hms) = palDr2tf(2, $lst);
      my ($lh, $lm, $ls, undef) = @hms;
      $lm += 1 if $ls >= 30;
      if ($lm >= 60) {
        $lm -= 60;
        $lh += 1;
        $lh -= 24 if $lh > 24;
      }
      $lm = '0'.$lm if $lm < 10;
      my $ly = $plotter->toWy ($yborder*3/2);
      $plotter->drawText($hour, $ly, sprintf("%2s:%2s", $lh, $lm), 'twhite');
      $ho += 4;
    }
  } elsif ($X_AXIS =~ /elevation/i) {
    my $y = $plotter->toWy ($yplot - $yborder - 10);
    for ( my $deg = $minX+20; $deg < $maxX; $deg += 20 ) {
      $plotter->drawLine($deg, $minY, $deg, $maxY, 'grid');
      $plotter->drawText($deg, $y, $deg, 'twhite');
    }
  } elsif ($X_AXIS =~ /air mass/i) {
      my $dAt12 = 90 - (180 / pi * acos (1/1.25));
      my $dAt15 = 90 - (180 / pi * acos (1/1.5));
      my $dAt17 = 90 - (180 / pi * acos (1/1.75));
      my $dAt3 = 90 - (180 / pi * acos (1/3));
      my $dAt4 = 90 - (180 / pi * acos (1/4));
      my $dAt5 = 90 - (180 / pi * acos (1/5));
      $plotter->drawLine(30, $minY,30, $maxY, 'grid');
      $plotter->drawLine($dAt12, $minY, $dAt12, $maxY, 'grid');
      $plotter->drawLine($dAt15, $minY, $dAt15, $maxY, 'grid');
      $plotter->drawLine($dAt17, $minY, $dAt17, $maxY, 'grid');
      $plotter->drawLine($dAt3, $minY, $dAt3, $maxY, 'grid');
      $plotter->drawLine($dAt4, $minY, $dAt4, $maxY, 'grid');
      $plotter->drawLine($dAt5, $minY, $dAt5, $maxY, 'grid');
      my $y = $plotter->toWy ($yplot - $yborder - 10);
      $plotter->drawText($dAt12, $y, '1.25', 'twhite');
      $plotter->drawText($dAt15, $y, '1.5', 'twhite');
      $plotter->drawText($dAt17, $y, '1.75', 'twhite');
      $plotter->drawText(30, $y, '2', 'twhite');
      $plotter->drawText($dAt3, $y, '3', 'twhite');
      $plotter->drawText($dAt4, $y, '4', 'twhite');
      $plotter->drawText($dAt5, $y, '5', 'twhite');
  } elsif ($X_AXIS =~ /azimuth/i) {
    for ( my $deg = $minX+40; $deg < $maxX; $deg += 40 ) {
      $plotter->drawLine($deg, $minY, $deg, $maxY, 'grid');
      my $y = $plotter->toWy ($yplot - $yborder - 10);
      $plotter->drawText($deg, $y, $deg, 'twhite');
    }
  } elsif ($X_AXIS =~ /parallactic angle/i) {
    for ( my $deg = $minX+40; $deg < $maxX; $deg += 40 ) {
      $plotter->drawLine($deg, $minY, $deg, $maxY, 'grid');
      my $y = $plotter->toWy ($yplot - $yborder - 10);
      $plotter->drawText($deg, $y, $deg, 'twhite');
    }
  }

  # draw the grid lines - y axis
  if (($special == 1) || ($special == 2))  {}
  elsif ($Y_AXIS =~ /time/i) {
    my $ho = $timeH - 8;
    for ( my $hour = $minY+$lstDiffY*4; $hour < $maxY; $hour += $lstDiffY*4 ) {
      # draw the time lines
      my $tel = $telObject;
      $plotter->drawLine($minX, $hour, $maxX, $hour, 'grid');

      # calculate the HST time
      my $ti = $ho;
      $ti -= 24 if $ti >= 24;
      $ti += 24 if $ti < 0;
      my ($h, $m) = split (/\./, $ti);
      $m = ('.'.$m) * 60;
      $m = '0'.$m if $m < 10;
      $m = '0'.$m if $m < 10;
      my $x = $plotter->toWx ($xborder*3/2);
      $plotter->drawText($x, $hour, sprintf("%2s:%2s", $h, $m), 'twhite');

      # calculate the ut time
      my $uh = $h + 10;
      $uh -= 24 if $uh >= 24;
      my $ux = $plotter->toWx ($xplot - $xborder/2);
      $plotter->drawText($ux, $hour, sprintf("%2s:%2s", $uh, $m), 'twhite');

      #calculate the lst time
      my $lst;
      my $si = '+';
      my @parts;
      $si = '-' if ($hour < 0);
      $lst = $hour;
      while ($lst > 2 * pi) {
        $lst -= 2*pi;
      }
      my ($si, @hms) = palDr2tf(2, $lst);
      my ($lh, $lm, $ls, undef) = @hms;
      $lm += 1 if $ls >= 30;
      if ($lm >= 60) {
        $lm -= 60;
        $lh += 1;
        $lh -= 24 if $lh > 24;
      }
      $lm = '0'.$lm if $lm < 10;
      my $lx = $plotter->toWx ($xplot - $xborder*3/2);
      $plotter->drawText($lx, $hour, sprintf("%2s:%2s", $lh, $lm), 'twhite');
      $ho += 4;
    }
  } elsif ($Y_AXIS =~ /elevation/i) {
    for ( my $deg = $minY+20; $deg < $maxY; $deg += 20 ) {
      $plotter->drawLine($minX, $deg, $maxX, $deg, 'grid');
      my $x = $plotter->toWx ($xborder + 10);
      $plotter->drawText($x, $deg, $deg, 'twhite');
    }
  } elsif ($Y_AXIS =~ /air mass/i) {
        my $dAt12 = 90 - (180 / pi * acos (1/1.25));
            my $dAt15 = 90 - (180 / pi * acos (1/1.5));
            my $dAt17 = 90 - (180 / pi * acos (1/1.75));
        my $x = $plotter->toWx ($xborder +15);
        for my $am (qw/1 2 3 4 5/)
        {
           my $dAt = 90 - (180 / pi * acos (1/$am));
           $plotter->drawLine($minX, $dAt, $maxX, $dAt, 'grid');
           $plotter->drawText ($x, $dAt, $am, 'twhite');
        }
        $plotter->drawLine($minX, $dAt12, $maxX, $dAt12, 'grid');
        $plotter->drawLine($minX, $dAt15, $maxX, $dAt15, 'grid');
        $plotter->drawLine($minX, $dAt17, $maxX, $dAt17, 'grid');
        $plotter->drawText ($x, $dAt12, '1.25', 'twhite');
        $plotter->drawText ($x, $dAt15, '1.5', 'twhite');
        $plotter->drawText ($x, $dAt17, '1.75', 'twhite');
  } elsif ($Y_AXIS =~ /azimuth/i) {
    for ( my $deg = $minY+40; $deg < $maxY; $deg += 40 ) {
      $plotter->drawLine($minX, $deg, $maxX, $deg, 'grid');
      my $x = $plotter->toWx ($xborder + 10);
      $plotter->drawText($x, $deg, $deg, 'twhite');
    }
  } elsif ($Y_AXIS =~ /parallactic angle/i) {
    for ( my $deg = $minY+40; $deg < $maxY; $deg += 40 ) {
      $plotter->drawLine($minX, $deg, $maxX, $deg, 'grid');
      my $x = $plotter->toWx ($xborder + 10);
      $plotter->drawText($x, $deg, $deg, 'twhite');
    }
  }

  if (!$special) {
    # erase any mess under the y axis or to the left of the x axis
    my $bottom = $plotter->toWy($yplot+10);
    my $top = $plotter->toWy(-10);
    my $west = $plotter->toWx(-10);
    my $east = $plotter->toWx($xplot + 10);
    $plotter->drawColor('black');
    $plotter->drawBox($west, $maxY, $east, $top, 'foblack');
    $plotter->drawBox($west, $minY, $east, $bottom, 'foblack');
    $plotter->drawBox($west, $bottom, $minX, $top, 'foblack');
    $plotter->drawBox($maxX, $bottom, $east, $top, 'foblack');

    # plot the axes and graphs - last to make look neat
    print "    Plotting the grid border and labels\n" if $locateBug;
    $plotter->drawColor('White');
    $plotter->fontColor('White');
    $plotter->drawLine($minX, $minY, $minX, $maxY, 'lwhite');
    $plotter->drawLine($minX, $minY, $maxX, $minY, 'lwhite');
    $plotter->drawLine($maxX, $minY, $maxX, $maxY, 'lwhite');
    $plotter->drawLine($minX, $maxY, $maxX, $maxY, 'lwhite');
    $plotter->raiseAbove('lwhite', 'foblack');
    $plotter->raiseAbove('twhite', 'foblack');
  }

  # label the axes
  $plotter->usingWorld(0);
  if ($special) {}
  elsif ($X_AXIS =~ /time/i) {
    $plotter->drawText($xplot/2,$yplot - $yborder/2, 'HST', 'twhite');
    $plotter->drawText($xplot/2,$yborder, 'UT', 'twhite');
    $plotter->drawText($xplot/2,$yborder*2, 'LST', 'twhite');
    $plotter->drawLine($xborder, $yborder, $xplot - $xborder, $yborder, 'lwhite');
    $plotter->drawLine($xborder, $yborder, $xborder, $yborder + $YSpaceForTime, 'lwhite');
    $plotter->drawLine($xplot - $xborder, $yborder, $xplot - $xborder, $yborder + $YSpaceForTime, 'lwhite');
  } elsif ($X_AXIS =~ /elevation/i) {
    $plotter->usingWorld(1);
    my $yoff = $maxY + $plotter->toWy (5) - $plotter->toWy(0);
    my $toff = $plotter->toWy (10) - $plotter->toWy(0);
    $plotter->drawLine (30, $maxY, 30, $yoff, 'lwhite');
    my $dAt12 = 90 - (180 / pi * acos (1/1.25));
    my $dAt15 = 90 - (180 / pi * acos (1/1.5));
    my $dAt17 = 90 - (180 / pi * acos (1/1.75));
    my $dAt3 = 90 - (180 / pi * acos (1/3));
    my $dAt4 = 90 - (180 / pi * acos (1/4));
    my $dAt5 = 90 - (180 / pi * acos (1/5));
    $plotter->drawLine ($dAt12, $maxY, $dAt12, $yoff, 'lwhite');
    $plotter->drawLine ($dAt15, $maxY, $dAt15, $yoff, 'lwhite');
    $plotter->drawLine ($dAt17, $maxY, $dAt17, $yoff, 'lwhite');
    $plotter->drawLine ($dAt3, $maxY, $dAt3, $yoff, 'lwhite');
    $plotter->drawLine ($dAt4, $maxY, $dAt4, $yoff, 'lwhite');
    $plotter->drawLine ($dAt5, $maxY, $dAt5, $yoff, 'lwhite');
    $plotter->drawText (90, $maxY + $toff, '1', 'twhite');
    $plotter->drawText (30, $maxY + $toff, '2', 'twhite');
    $plotter->drawText ($dAt12, $maxY + $toff, '1.25', 'twhite');
    $plotter->drawText ($dAt15, $maxY + $toff, '1.5', 'twhite');
    $plotter->drawText ($dAt17, $maxY + $toff, '1.75', 'twhite');
    $plotter->drawText ($dAt3, $maxY + $toff, '3', 'twhite');
    $plotter->drawText ($dAt4, $maxY + $toff, '4', 'twhite');
    $plotter->drawText ($dAt5, $maxY + $toff, '5', 'twhite');
    $plotter->usingWorld(0);
    $plotter->drawText($xplot/2,$yborder/2, 'Air Mass', 'twhite');
    $plotter->drawText($xplot/2,$yplot - $yborder/2, 'Elevation', 'twhite');
  } elsif ($X_AXIS =~ /air mass/i) {
    $plotter->usingWorld(1);
    my $yoff = $maxY + $plotter->toWy (5) - $plotter->toWy(0);
    my $toff = $plotter->toWy (10) - $plotter->toWy(0);
    for ( my $deg = $minX+20; $deg < $maxX; $deg += 20 ) {
              $plotter->drawLine ($deg, $maxY, $deg, $yoff, 'lwhite');
            $plotter->drawText ($deg, $maxY + $toff, $deg, 'twhite');
    }
    $plotter->usingWorld(0);
    $plotter->drawText($xplot/2,$yborder/2, 'Elevation', 'twhite');
    $plotter->drawText($xplot/2,$yplot - $yborder/2, 'Air Mass', 'twhite');
  } elsif ($X_AXIS =~ /azimuth/i) {
    $plotter->drawText($xplot/2,$yplot - $yborder/2, 'Azimuth', 'twhite');
  } elsif ($X_AXIS =~ /parallactic angle/i) {
    $plotter->drawText($xplot/2,$yplot - $yborder/2, 'Parallactic Angle', 'twhite');
  }
  if ($special) {}
  elsif ($Y_AXIS =~ /time/i) {
    $plotter->usingWorld(1);
    my $y = $plotter->toPy(4) - $plotter->toPy(0);
    $plotter->usingWorld(0);
    $plotter->drawText($xborder/2, $yplot/2 + $y/2, 'HST', 'twhite');
    $plotter->drawText($xplot - $xborder, $yplot/2 + $y/2,'UT', 'twhite');
    $plotter->drawText($xplot - $xborder*2, $yplot/2 + $y/2, 'LST', 'twhite');
    $plotter->drawLine($xplot - $xborder, $yborder, $xplot - $xborder, $yplot- $yborder, 'lwhite');
    $plotter->drawLine($xplot - $xborder, $yborder, $xplot - $xborder - $XSpaceForTime, $yborder, 'lwhite');
    $plotter->drawLine($xplot - $xborder, $yplot - $yborder, $xplot - $xborder - $XSpaceForTime, $yplot - $yborder, 'lwhite');
  } elsif ($Y_AXIS =~ /elevation/i)  {
    $plotter->usingWorld(1);
    my $xoff = $maxX - ($plotter->toWx (5) - $plotter->toWx(0));
    my $toff = $plotter->toWx (15) - $plotter->toWx(0);
    my $dAt12 = 90 - (180 / pi * acos (1/1.25));
    my $dAt15 = 90 - (180 / pi * acos (1/1.5));
    my $dAt17 = 90 - (180 / pi * acos (1/1.75));
    my $dAt3 = 90 - (180 / pi * acos (1/3));
    my $dAt4 = 90 - (180 / pi * acos (1/4));
    my $dAt5 = 90 - (180 / pi * acos (1/5));
    my $dAt1 = 90 - (180 / pi * acos (1));
    my $dAt2 = 90 - (180 / pi * acos (1/2));
    $plotter->drawLine ($maxX, $dAt1, $xoff, $dAt1, 'lwhite');
    $plotter->drawLine ($maxX, $dAt2, $xoff, $dAt2, 'lwhite');
    $plotter->drawLine ($maxX, $dAt12, $xoff, $dAt12, 'lwhite');
    $plotter->drawLine ($maxX, $dAt15, $xoff, $dAt15, 'lwhite');
    $plotter->drawLine ($maxX, $dAt17, $xoff, $dAt17, 'lwhite');
    $plotter->drawLine ($maxX, $dAt3, $xoff, $dAt3, 'lwhite');
    $plotter->drawLine ($maxX, $dAt4, $xoff, $dAt4, 'lwhite');
    $plotter->drawLine ($maxX, $dAt5, $xoff, $dAt5, 'lwhite');
    $plotter->drawText ($maxX-$toff, 90, '1', 'twhite');
    $plotter->drawText ($maxX-$toff, $dAt2, '2', 'twhite');
    $plotter->drawText ($maxX-$toff, $dAt12, '1.25', 'twhite');
    $plotter->drawText ($maxX-$toff, $dAt15, '1.5', 'twhite');
    $plotter->drawText ($maxX-$toff, $dAt17, '1.75', 'twhite');
    $plotter->drawText ($maxX-$toff, $dAt3, '3', 'twhite');
    $plotter->drawText ($maxX-$toff, $dAt4, '4', 'twhite');
    $plotter->drawText ($maxX-$toff, $dAt5, '5', 'twhite');
    $plotter->usingWorld(0);
    $plotter->drawTextVert($xplot - $xborder/2,$yplot/2, 'Air Mass', 'twhite');
    $plotter->drawTextVert($xborder/2,$yplot/2, 'Elevation', 'twhite');
  } elsif ($Y_AXIS =~ /air mass/i) {
    $plotter->usingWorld(1);
    my $xoff = $maxX - ($plotter->toWx (5) - $plotter->toWx(0));
    my $x = $plotter->toWx ($xplot - $xborder -10);
    for ( my $deg = $minY+20; $deg < $maxY; $deg += 20 ) {
               $plotter->drawText($x, $deg, $deg, 'twhite');
            $plotter->drawLine ($maxX, $deg, $xoff, $deg, 'twhite');
    }
    $plotter->usingWorld(0);
    $plotter->drawTextVert($xplot - $xborder/2,$yplot/2, 'Elevation', 'twhite');
    $plotter->drawTextVert($xborder/2,$yplot/2, 'Air Mass', 'twhite');

  } elsif ($Y_AXIS =~ /azimuth/i) {
    $plotter->drawTextVert($xborder/2,$yplot/2, 'Azimuth', 'twhite');
  } elsif ($Y_AXIS =~ /parallactic angle/i) {
    $plotter->drawTextVert($xborder/2,$yplot/2, 'Parallactic Angle', 'twhite');
  }
  $plotter->usingWorld(1);

  # now interact them
  print "    Plotting the grid lines\n" if $locateBug;
  if (($X_AXIS eq $Y_AXIS) || (($X_AXIS =~ /elevation/i) && 
     ($Y_AXIS =~ /air mass/i)) || (($X_AXIS =~ /air mass/i) && 
     ($Y_AXIS =~ /elevation/i))) {
    $plotter->drawColor('purple');
    $plotter->drawLine ($minX, $minY, $maxX, $maxY);
  } else {
    my ($y, $mo, $d) = split (/\//, $DATE, 3);
    my @points = ();
    my $Top;
    foreach my $source (@SOURCE_LIST) {
      if ($source->active()) {
        $source->calcPoints($DATE, $TIME, $NUM_POINTS, $MW, $telObject);
        if ($X_AXIS =~ /time/i) {
          if (($Y_AXIS =~ /elevation/i) || ($Y_AXIS =~ /air mass/i)){
            @points = $source->time_ele_points();
          } elsif ($Y_AXIS =~ /azimuth/i) {
            @points = $source->time_az_points();
          } elsif ($Y_AXIS =~ /parallactic angle/i) {
            @points = $source->time_pa_points();
          }
        } elsif (($X_AXIS =~ /elevation/i) || ($X_AXIS =~ /air mass/i)) {
          if ($Y_AXIS =~ /time/i) {
            @points = $source->ele_time_points();
          } elsif ($Y_AXIS =~ /azimuth/i) {
            @points = $source->ele_az_points();
          } elsif ($Y_AXIS =~ /parallactic angle/i) {
            @points = $source->ele_pa_points();
          }
        } elsif ($X_AXIS =~ /azimuth/i) {
          if ($Y_AXIS =~ /time/i) {
            @points = $source->az_time_points();
          } elsif (($Y_AXIS =~ /elevation/i) || ($Y_AXIS =~ /air mass/i)){
            @points = $source->ele_az_points();
          } elsif ($Y_AXIS =~ /parallactic angle/i) {
            @points = $source->az_pa_points();
          }
        } elsif ($X_AXIS =~ /parallactic angle/i) {
          if ($Y_AXIS =~ /time/i) {
            @points = $source->pa_time_points();
          } elsif (($Y_AXIS =~ /elevation/i) || ($Y_AXIS =~ /air mass/i)){
            @points = $source->pa_ele_points();
          } elsif ($Y_AXIS =~ /azimuth/i) {
            @points = $source->pa_az_points();
          }
        }

        $plotter->penWidth($source->lineWidth());
        $plotter->penWidth($H_WIDTH) if ($H_LIGHT == $source);
        $plotter->drawColor($source->color());
        print "color plotted is ".$source->color()."\n" if $debug;

        my @times = $source->time_ele_points();
        if (($special == 1) || ($special == 2)) {
          my $i;
          my $len = @points;
          my @newpoints = ();
          my $prevr;
          my $prevt;
          my $dotColor = "#55ffff";
          for ($i = 0; $i < $len; $i += 2) {
            my $r = $points[$i];
              $r = 90 - $r;
              my $theta = $points[$i+1];
              $theta = (90 - $theta)*pi/180;
              my $x = 90 + $r * cos $theta;
              my $y = 90 + $r * sin $theta;
            my $len2 = @newpoints;
            if ($r < 90 ) {
              if ($len2 == 0 && defined $prevr && $prevr > 90) {
                my $dr = 90 - $r;
                my $pdr = $prevr - 90;
                my $nt = $dr / ($dr + $pdr) * ($prevt - $theta) + $theta;
                my $x2 = 90+90 * cos $nt;
                my $y2 = 90+90 * sin $nt;
                push (@newpoints, $x2);
                push (@newpoints, $y2);
              }
              if ($r > 60 && defined $prevr && $prevr < 60){
                my $time = $timeH - 12 + int($i/2) * ( 24 / ($NUM_POINTS - 1));
                $time += 24 if $time < 0;
                $time -= 24 if $time > 24;
                my ($h, $m) = split (/\./, $time);
                $m = ('.'.$m) * 60;
                $m = '0'.$m if $m < 10;
                $h = '0'.$h if $h < 10;
                $time = sprintf ("%2s:%2s", $h, $m);
                $plotter->fontColor('#ffff00');
                $plotter->drawText($x, $y+3, "$time", 'time'.$source->name());
                $plotter->drawFillOval ($x-1, $y-1, $x+1, $y+1, 'fo'.$source->name());
              } elsif ($r < 60 && defined $prevr && $prevr > 60) {
                my $time = $timeH - 12 + int($i/2) * ( 24 / ($NUM_POINTS - 1));
                my $di = 24 / ($NUM_POINTS - 1);
                $time -= $di;
                $time += 24 if $time < 0;
                $time -= 24 if $time > 24;
                my ($h, $m) = split (/\./, $time);
                $m = ('.'.$m) * 60;
                $m = '0'.$m if $m < 10;
                $h = '0'.$h if $h < 10;
                $time = sprintf ("%2s:%2s", $h, $m);
                my $x2 = 90 + $prevr * cos $prevt;
                my $y2 = 90 + $prevr * sin $prevt;
                $plotter->fontColor('#ffff00');
                $plotter->drawText($x2, $y2+3, "$time", 'time'.$source->name());
                $plotter->drawFillOval ($x2-1, $y2-1, $x2+1, $y2+1, 'fo'.$source->name());
              }
              $plotter->drawFillOval ($x-.5, $y-.5, $x+.5, $y+.5, 'fo'.$source->name());
              push (@newpoints, $x);
              push (@newpoints, $y);
            } elsif ($len2 > 0 && defined $prevr && $prevr < 90) {
              my $dr = $r - 90;
              my $pdr = 90 - $prevr;
              my $nt = $dr / ($dr + $pdr) * ($prevt - $theta) + $theta;
              $x = 90+90 * cos $nt;
              $y = 90+90 * sin $nt;
              $plotter->fontColor($source->color());
              $plotter->drawTextFromLeft($x+5, $y, $source->name(), 't'.$source->name());
              push (@newpoints, $x);
              push (@newpoints, $y);
              $plotter->drawSmoothLine (@newpoints, 'l'.$source->name());
              @newpoints = ();
            } elsif (defined $len2 and $len2 >= 4) {
              $plotter->drawSmoothLine (@newpoints, 'l'.$source->name());
              @newpoints = ();
            }
            $prevr = $r;
            $prevt = $theta;
          }
          @points = @newpoints;
        } else {
             #give the points some labels
          my $max = $points[1];
          my $xm = $points[0];
          my $len = @points;
          my $xw = $plotter->toWx(1) - $plotter->toWx(0);
          my $yw = $plotter->toWy(1) - $plotter->toWy(0);
          for (my $i = 1; $i < $len; $i+=2) {
            my $x = $points[$i-1];
            my $y = $points[$i];
            $plotter->drawFillOval ($x-$xw, $y-$yw, $x+$xw, $y+$yw, 'fo'.$source->name());
            if ($points[$i] > $max) {
              $max = $points[$i];
              $xm = $points[$i-1];
            }
          }
          my $ya = $plotter->toWy(5) - $plotter->toWy(0);
          $plotter->fontColor($source->color());
          $plotter->drawTextFromLeft($xm, $max-$ya, $source->name(), 't'.$source->name());

          my @second = ();
          my $prevx = $points[0];
          my $prevy = $points[1];
          my $plotNow = 0;
          for (my $i = 3; $i < $len; $i+=2) {
            my $x = $points[$i-1];
            my $y = $points[$i];
            my $plotx = $x;
            my $ploty = $y;
            my $plotxn = $x;
            my $plotyn = $y;
            push (@second, $prevx);
            push (@second, $prevy);
            if ($Y_AXIS =~ /parallactic angle/i) {
              if ($prevy < -80 && $y > 80) {
                my $len2 = @second;
                if ($len2 > 0) {
                  $ploty = $y - 360;
                  $plotyn = $prevy + 360;
                  $plotNow = 1;
                }
              } elsif ($y < -80 && $prevy > 80) {
                my $len2 = @second;
                if ($len2 > 0) {
                  $ploty = $y + 360;
                  $plotyn = $prevy - 360;
                  $plotNow = 1;
                }
              }
            } elsif ($X_AXIS =~ /parallactic angle/i) {
              if ($prevx < -80 && $x > 80) {
                my $len2 = @second;
                if ($len2 > 0) {
                  $plotx = $x - 360;
                  $plotxn = $prevx + 360;
                  $plotNow = 1;
                }
              } elsif ($x < -80 && $prevx > 80) {
                my $len2 = @second;
                if ($len2 > 0) {
                  $plotx = $x + 360;
                  $plotxn = $prevx - 360;
                  $plotNow = 1;
                }
              }
            }
            if ($Y_AXIS =~ /azimuth/i) {
              if ($prevy < 100 && $y > 260) {
                my $len2 = @second;
                if ($len2 > 0) {
                  $ploty = $y - 360;
                  $plotyn = $prevy + 360;
                  $plotNow = 1;
                }
              } elsif ($y < 100 && $prevy > 260) {
                my $len2 = @second;
                if ($len2 > 0) {
                  $ploty = $y + 360;
                  $plotyn = $prevy - 360;
                  $plotNow = 1;
                }
              }
            } elsif ($X_AXIS =~ /azimuth/i) {
              if ($prevx < 100 && $x > 260) {
                my $len2 = @second;
                if ($len2 > 0) {
                  $plotx = $x - 360;
                  $plotxn = $prevx + 360;
                  $plotNow = 1;
                }
              } elsif ($x < 100 && $prevx > 260) {
                my $len2 = @second;
                if ($len2 > 0) {
                  $plotx = $x + 360;
                  $plotxn = $prevx - 360;
                  $plotNow = 1;
                }
              }
            }


            if ($plotNow) {
              $plotNow = 0;
              push (@second, $plotx);
              push (@second, $ploty);
              $plotter->drawSmoothLine (@second, 'l'.$source->name());
              @second = ();
              push (@second, $plotxn);
              push (@second, $plotyn);
            } elsif ($i == $len - 1) {
              push (@second, $x);
              push (@second, $y);
            }

            $prevx = $x;
            $prevy = $y;
          }
          @points = @second;


        }
        my $len2 = @points;
        $plotter->drawSmoothLine (@points, 'l'.$source->name()) if ($len2 > 0);

        my @bold   = (-background => "#bbbbbb", -foreground => 'black', qw/-relief raised -borderwidth 1/);
        my @normal = (-background => undef, -foreground => $source->color(), qw/-relief flat/);
        $plotter->bindTag( 'l'.$source->name(), '<Any-Enter>' =>
                sub {
                  my $s = $source;
                  if ($s->active()) {
                    $EditWin->{'Text'}->tag('configure', 'd'.$s->index(), @bold) if $EDIT_OPEN;
                    $plotter->configureTag ('l'.$s->name(), -width => 3);
                  }
                });
        $plotter->bindTag( 'l'.$source->name(), '<Any-Leave>' =>
                sub {
                  my $s = $source;
                  if ($s->active()) {
                    $EditWin->{'Text'}->tag('configure', 'd'.$s->index(), @normal) if $EDIT_OPEN;
                    $plotter->configureTag ('l'.$s->name(), -width => 1);
                  }
                });
      }
      $plotter->penWidth(1);

      #calculate where the time dots go.
      calcTime($source);

      if ($plotter->existTag('foblack')) {
        if ($plotter->existTag('timeDot'.$source->name())){
          $plotter->raiseAbove('timeDot'.$source->name(),'l'.$source->name());
          $plotter->raiseAbove('foblack', 'timeDot'.$source->name());
        } elsif  ($plotter->existTag('l'.$source->name())){
          $plotter->raiseAbove('foblack', 'l'.$source->name());
        }
        $plotter->raiseAbove('t'.$source->name(), 'foblack') if $plotter->existTag('t'.$source->name());
        $plotter->raiseAbove('lwhite', 'foblack');
        $plotter->raiseAbove('twhite', 'foblack');
      } else {
        $plotter->raiseAbove('lwhite', 'l'.$source->name()) if $plotter->existTag('l'.$source->name());
        $plotter->raiseAbove('twhite', 'l'.$source->name()) if $plotter->existTag('l'.$source->name());
      }
    }
    if ($Top != undef) {
      destroy $Top;
    }
    $plotter->penWidth(1);
  }

  print "Exit plot\n" if $locateBug;
}

=item B<am_to_deg>

Converts air mass to degrees.

=cut

sub am_to_deg {
        (180/pi)*asin(1/$_[0]);
}

=item B<getColor>

Returns a color.

=cut

sub getColor {
  my $color = $COLOR_LIST[$COLOR_INDEX];
  my $len = @COLOR_LIST;
  $COLOR_INDEX++;
  $COLOR_INDEX = $COLOR_INDEX % $len;
  return $color;
}

=item B<calcTime>

Draws a dot at the current time on each source.

=cut

sub calcTime {
  $TIMER->cancel if defined $TIMER;
  my $so = shift;
  my $timeBug = 0;
  my ($ss, $mm, $hh, $md, $mo, $yr, $wd, $yd, $isdst) = gmtime(time);
  $mo++;   # this catches the month up to the current date
  $mo = '0'.$mo if length($mo) < 2;
  $md = '0'.$md if length($md) < 2;
  $mm = '0'.$mm if length($mm) < 2;
  $ss = '0'.$ss if length($ss) < 2;
  $yr += 1900;
  my ($sety, $setm, $setd) = split (/\//, $DATE);
  if ((!$yr =~ /$sety/) || $setm != $mo || $setd != $md) {
    return;
  }
  print "The gm time is $hh:$mm:$ss and date is $yr\/$mo\/$md\n" if $timeBug;

  #calculate the local time
  my $strp = new DateTime::Format::Strptime(
                 pattern => '%Y/%m/%d %H:%M:%S',
                 on_error => 'croak');

  my $dt = $strp->parse_datetime("$yr\/$mo\/$md $hh:$mm:$ss");

  $dt->subtract(hours => 10);

  my $t = $dt->strftime('%H:%M:%S');
  my $d = $dt->strftime('%Y/%m/%d');
  #my $time = $hh2+$mm2/60+$ss2/3600;

  $plotter->drawColor ('white');
  foreach my $source (@SOURCE_LIST) {
    next if (!$source->active());
    next if (defined $so && $source != $so);
    if (($so == undef) || ($so->timeDotX() eq '')) {

      $plotter->delete ('timeDot'.$source->name());

      print "Real time = $TIME and real date = $DATE\n" if $timeBug;
      print "Date = $d and time = $t before calcpoint\n" if $timeBug;
      my ($lst, $ele, $az, $pa, $elex, $eley, $azx, $azy) = $source->calcPoint($d, $t, $telObject);
      if ($lst < $minX) {
        $lst += 2*pi;
      } elsif ($lst > $maxX) {
        $lst -= 2*pi;
      }
      my ($x, $y);

      if ($X_AXIS =~ /time/i) {
        $x = $lst;
      } elsif (($X_AXIS =~ /elevation/i) || ($X_AXIS =~ /air mass/i)) {
        $x = $ele;
      } elsif ($X_AXIS =~ /azimuth/i) {
        $x = $az;
      } elsif ($X_AXIS =~ /parallactic angle/i) {
        $x = $pa;
      }
      if ($Y_AXIS =~ /time/i) {
        $y = $lst;
      } elsif (($Y_AXIS =~ /elevation/i)  || ($Y_AXIS =~ /air mass/i)) {
        $y = $ele;
      } elsif ($Y_AXIS =~ /azimuth/i) {
        $y = $az;
      } elsif ($Y_AXIS =~ /parallactic angle/i) {
        $y = $pa;
      }

      if ((($Y_AXIS =~ /azimuth/i) && ($X_AXIS =~ /elevation/i)) || (($X_AXIS =~ /azimuth/i) && ($Y_AXIS =~ /elevation/i)) || (($Y_AXIS =~ /azimuth/i) &&
         ($X_AXIS =~ /air mass/i)) || (($Y_AXIS =~ /air mass/i) &&
         ($X_AXIS =~ /azimuth/i))) {
        $x = $ele;
        $y = $az;
      }

      $source->timeDotX($x);
      $source->timeDotY($y);

      $elex = $plotter->toWx($elex) - $plotter->toWx(0);
      $eley = $plotter->toWy($eley) - $plotter->toWy(0);
      $azx = $plotter->toWx($azx) - $plotter->toWx(0);
      $azy = $plotter->toWy($azy) - $plotter->toWy(0);

      # draw the time dot
      if ($ele > 0) {
        $plotter->drawColor($source->color());
        if ((($Y_AXIS =~ /azimuth/i) && ($X_AXIS =~ /elevation/i)) || (($X_AXIS =~ /azimuth/i) && ($Y_AXIS =~ /elevation/i)) || (($Y_AXIS =~ /azimuth/i) &&
         ($X_AXIS =~ /air mass/i)) || (($Y_AXIS =~ /air mass/i) &&
         ($X_AXIS =~ /azimuth/i))) {
          my $r = 90 - $source->timeDotX();
          if ($r < 90) {
            my $theta = (90 - $source->timeDotY()) * pi / 180;
            my $x2 = 90 + $r * cos $theta;
            my $y2 = 90 + $r * sin $theta;
            $plotter->drawFillOval($x2 - 2, $y2 - 2, $x2 + 2, $y2+2, 'timeDot'.$source->name());
            $plotter->bindTag( 'timeDot'.$source->name(), '<Any-Enter>' => sub {});
            $plotter->bindTag('ltimeDot'.$source->name(), '<Any-Leave>' => sub {});
          }
        }
        else {
          my ($sX, $sY) = $plotter->toW($dotSizeX, $dotSizeY);
          $sX -= $plotter->toWx(0);
          $sY -= $plotter->toWy(0);
          my $x2 = $source->timeDotX();
          my $y2 = $source->timeDotY();
          if ($x2 ne '' && $y2 ne '') {
            $plotter->drawFillOval($x2 - $sX, $y2 - $sY, $x2 + $sX, $y2+$sY, 'timeDot'.$source->name());
            $plotter->bindTag( 'timeDot'.$source->name(), '<Any-Enter>' =>
              sub {
                $plotter->drawColor($source->color());
                $plotter->drawFillOval($x2 - $sX, $y2 - $sY, $x2 + $sX, $y2+$sY, 'ltimeDot'.$source->name());
                # draw AZ-EL pointers
                $plotter->drawColor('red');
                $plotter->fontColor('red');
                $plotter->penWidth(2);
                $plotter->drawLine ($x2 - $elex, $y2 - $eley, $x2, $y2, 'ltimeDot'.$source->name());
                $plotter->drawLine ($x2 - $azx, $y2 - $azy, $x2, $y2, 'ltimeDot'.$source->name());
                $plotter->penWidth(1);
                my ($xoff, $yoff) = $plotter->toW(7,7);
                $xoff -= $plotter->toWx(0);
                $yoff -= $plotter->toWy(0);
                $plotter->drawText ($x2 - $elex-$xoff, $y2 - $eley-$yoff, 'El', 'ltimeDot'. $source->name());
                # and RA-Dec box
                my $bx = 1.5*sqrt($azx*$azx+$elex*$elex);
                my $by = 1.5*sqrt($azy*$azy+$eley*$eley);
                $plotter->drawLine ($x2 - $bx, $y2 - $by, $x2 - $bx, $y2 + $by, 'ltimeDot'.$source->name());
                $plotter->drawLine ($x2 - $bx, $y2 + $by, $x2 + $bx, $y2 + $by, 'ltimeDot'.$source->name());
                $plotter->drawLine ($x2 + $bx, $y2 + $by, $x2 + $bx, $y2 - $by, 'ltimeDot'.$source->name());
                $plotter->drawLine ($x2 + $bx, $y2 - $by, $x2 - $bx, $y2 - $by, 'ltimeDot'.$source->name());
                $plotter->drawText ($x2, $y2 - 1.2*$by, 'R.A.', 'ltimeDot'. $source->name());
                $plotter->drawText ($x2 - 1.12*$bx, $y2+0.2*$by, 'D', 'ltimeDot'. $source->name());
                $plotter->drawText ($x2 - 1.1*$bx, $y2, 'e', 'ltimeDot'. $source->name());
                $plotter->drawText ($x2 - 1.1*$bx, $y2-0.2*$by, 'c', 'ltimeDot'. $source->name());
                $plotter->fontColor($source->color());
              });
            $plotter->bindTag('ltimeDot'.$source->name(), '<Any-Leave>' => 
              sub {
                $plotter->delete ('ltimeDot'.$source->name());
              });
            $source->AzElOffsets($elex, $eley, $azx, $azy);
          }
        }
      }
    }
    else {
      # draw the time dot
      if ($source->elevation() > 0) {
        $plotter->drawColor($source->color());
        if ((($Y_AXIS =~ /azimuth/i) && ($X_AXIS =~ /elevation/i)) || (($X_AXIS =~ /azimuth/i) && ($Y_AXIS =~ /elevation/i)) || (($Y_AXIS =~ /azimuth/i) &&
         ($X_AXIS =~ /air mass/i)) || (($Y_AXIS =~ /air mass/i) &&
         ($X_AXIS =~ /azimuth/i))) {
          my $r = 90 - $source->timeDotX();
          if ($r < 90) {
            my $theta = (90 - $source->timeDotY()) * pi / 180;
            my $x2 = 90 + $r * cos $theta;
            my $y2 = 90 + $r * sin $theta;
            $plotter->drawFillOval($x2 - 2, $y2 - 2, $x2 + 2, $y2+2, 'timeDot'.$source->name());
            $plotter->bindTag( 'timeDot'.$source->name(), '<Any-Enter>' => sub {});
            $plotter->bindTag('ltimeDot'.$source->name(), '<Any-Leave>' => sub {});
          }
        }
        else {
          my ($sX, $sY) = $plotter->toW($dotSizeX, $dotSizeY);
          $sX -= $plotter->toWx(0);
          $sY -= $plotter->toWy(0);
          my $x2 = $source->timeDotX();
          my $y2 = $source->timeDotY();
          if ($x2 ne '' && $y2 ne '') {
            my ($elex, $eley, $azx, $azy) = $source->AzElOffsets();
            $plotter->drawColor($source->color());
            $plotter->drawFillOval($x2 - $sX, $y2 - $sY, $x2 + $sX, $y2+$sY, 'timeDot'.$source->name());
            $plotter->bindTag( 'timeDot'.$source->name(), '<Any-Enter>' =>
              sub {
                $plotter->drawColor($source->color());
                $plotter->drawFillOval($x2 - $sX, $y2 - $sY, $x2 + $sX, $y2+$sY, 'ltimeDot'.$source->name());
                $plotter->drawColor('red');
                $plotter->fontColor('red');
                $plotter->penWidth(2);
                # draw AZ-EL pointers
                $plotter->drawLine ($x2 - $elex, $y2 - $eley, $x2, $y2, 'ltimeDot'.$source->name());
                $plotter->drawLine ($x2 - $azx, $y2 - $azy, $x2, $y2, 'ltimeDot'.$source->name());
                $plotter->penWidth(1);
                my ($xoff, $yoff) = $plotter->toW(7,7);
                $xoff -= $plotter->toWx(0);
                $yoff -= $plotter->toWy(0);
                $plotter->drawText ($x2 - $elex-$xoff, $y2 - $eley-$yoff, 'El', 'ltimeDot'. $source->name());
                # and RA-Dec box
                my $bx = 1.5*sqrt($azx*$azx+$elex*$elex);
                my $by = 1.5*sqrt($azy*$azy+$eley*$eley);
                $plotter->drawLine ($x2 - $bx, $y2 - $by, $x2 - $bx, $y2 + $by, 'ltimeDot'.$source->name());
                $plotter->drawLine ($x2 - $bx, $y2 + $by, $x2 + $bx, $y2 + $by, 'ltimeDot'.$source->name());
                $plotter->drawLine ($x2 + $bx, $y2 + $by, $x2 + $bx, $y2 - $by, 'ltimeDot'.$source->name());
                $plotter->drawLine ($x2 + $bx, $y2 - $by, $x2 - $bx, $y2 - $by, 'ltimeDot'.$source->name());
                $plotter->drawText ($x2, $y2 - 1.2*$by, 'R.A.', 'ltimeDot'. $source->name());
                $plotter->drawText ($x2 - 1.12*$bx, $y2+0.2*$by, 'D', 'ltimeDot'. $source->name());
                $plotter->drawText ($x2 - 1.1*$bx, $y2, 'e', 'ltimeDot'. $source->name());
                $plotter->drawText ($x2 - 1.1*$bx, $y2-0.2*$by, 'c', 'ltimeDot'. $source->name());
                $plotter->fontColor($source->color());
              });
            $plotter->bindTag('ltimeDot'.$source->name(), '<Any-Leave>' =>
              sub {
                $plotter->delete ('ltimeDot'.$source->name());
              });
          }
        }
      }
    }
  }

  $TIMER = $MW->after($TimeLap, \&calcTime );
}

=item B<tagOnOff>

Configures all object with the tag name off or on.

=cut

sub tagOnOff {
  my $tag = shift;
  my $turnOn = shift;
  my $color = shift;
  my $color2 = shift;

  if (!$turnOn) {
    $plotter->configureTag('l'.$tag, -fill=>'black');
    $plotter->configureTag('fo'.$tag, -fill=>'black', outline=>'black');
    $plotter->configureTag('o'.$tag, outline=>'black');
    $plotter->configureTag('t'.$tag, -fill=>'black');
    $plotter->configureTag('time'.$tag, -fill=>'black');
    $plotter->configureTag('timeDot'.$tag, -fill=>'black', -outline => 'black');
    if (!($tag =~/(white)/i)) {
      $plotter->lowerBelow('l'.$tag, 'grid');
      $plotter->lowerBelow('o'.$tag, 'grid');
      $plotter->lowerBelow('fo'.$tag, 'grid');
      $plotter->lowerBelow('t'.$tag, 'grid');
      $plotter->lowerBelow('time'.$tag, 'grid');
      $plotter->lowerBelow('timeDot'.$tag, 'grid');
    }
  } else {
    $plotter->configureTag('l'.$tag, -fill=>$color);
    $plotter->configureTag('fo'.$tag, -fill=>$color, outline=>$color);
    $plotter->configureTag('o'.$tag, outline=>$color);
    $plotter->configureTag('timeDot'.$tag, -fill=>$color, outline=>$color);
    $plotter->configureTag('t'.$tag, -fill=>$color);
    if (defined $color2) {
      $plotter->configureTag('time'.$tag, -fill=>$color2);
    } else {
      $plotter->configureTag('time'.$tag, -fill=>$color);
    }
    $plotter->raiseAbove('l'.$tag, 'grid');
    $plotter->raiseAbove('o'.$tag, 'grid');
    $plotter->raiseAbove('fo'.$tag, 'grid');
    $plotter->raiseAbove('t'.$tag, 'grid');
    $plotter->raiseAbove('time'.$tag, 'grid');
    $plotter->raiseAbove('timeDot'.$tag, 'grid');
  }
}

=item B<error>

Displays an error message in Tk.

=cut

sub error {
  my $MW = shift;
  my $errWin = $MW->Toplevel(-borderwidth=>10);
  $errWin->title('Observation Log Error!');
  $errWin->resizable(0,0);
  $errWin->Button(
     -text         => 'Ok',
     -command      => sub{
       destroy $errWin;
  })->pack(-side=>'bottom');
  my $message = shift;
  $errWin->Label (
    -text => "\nError!\n\n   ".$message."   \n",
    -relief=>'sunken'
  )->pack(-side=>'bottom', -pady => 10);
  $errWin->title(shift) if @_;
  $MW->update;
  $errWin->grab;
}

=item B<inswt>

The "Insert With Tags" procedure inserts text into a given text widget
and applies one or more tags to that text.

Parameters:

    $w     -  Window in which to insert
    $text  -  Text to insert (it's inserted at the "insert" mark)
    $args  -  One or more tags to apply to text.  If this is empty 
              then all tags are removed from the text.

Returns:  Nothing

=cut

sub inswt {

    my($w, $text, @args) = @_;
    my $start = $w->index('insert');

    $w->insert('insert', $text);
    foreach my $tag ($w->tag('names', $start)) {
        $w->tag('remove', $tag, $start, 'insert');
    }
    foreach my $i (@args) {
        $w->tag('add', $i, $start, 'insert');
    }

}

__END__

=back

=end __PRIVATE_METHODS__

=head1 SEE ALSO

L<Astro::Coords>
L<Astro::Catalog>
L<Tk::AstroCatalog>

=head1 AUTHORS

Casey Best (University of Victoria),
Pam Shimek (University of Victoria),
Tim Jenness (Joint Astronomy Centre),
Remo Tilanus (Joint Astronomy Centre),
Graham Bell (Joint Astronomy Centre).

=head1 COPYRIGHT

Copyright (C) 2012 Science and Technology Facilities Council.
Copyright (C) 1998, 1999 Particle Physics and Astronomy Research
Council. All Rights Reserved.

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.

=cut
