#!/usr/local/bin/perl

# $Id:
#
# Author:  pjm
# Decription:
#
# The is "The Booth". It registers plates arriving in the West Pavilion (WP)
#
# A member of a team takes a number of loading plates down
# to the WP. When they get there, this program will be running on a specail
# machine. The user scans in their user ID barcode and then 1 or more 
# plate barcodes. When done they click Ok and a status is added to
#
#    LOADINGPLATE_STATUS
#
# for each plate. The widgets are cleared of previous input, ready for the next
# person to come along.
#
# NOTE: if you wish to turn debugging on ($debug = 1), hold down Control
# and press the middle mouse button over "Update Plates" label. As long as
# your not entering a user barcode that is (it grabs focus).
#
# $Id: update_plates.pl,v 1.8 1999/08/26 15:51:11 pjm Exp $


package update_plates;

use strict;
use Tk;
use Data::Dumper;
use Getopt::Long;
#use Barcode;
use Barcodelive;
use WrapDBI;
use Mail;

my $debug = 0;

# try to make sure the bell is ON
my $result = `xset b on`;

my $self = {
    dbUser       => 'fac_man',
#    dbUser       => 'dev1', # left in for debugging later...
    messageCount => 0,
    plateCount   => 0,
};

my $result = GetOptions("status=s" => \$self->{showStatus});

#warn Data::Dumper::Dumper($result) if $debug;
#warn Data::Dumper::Dumper($self)   if $debug;

# could bless $self here to make into an object.

&createWindow;

MainLoop;



sub createWindow {
    $self->{mw} = new MainWindow();

    $self->{mw}->title("Update Plates");
    $self->{mw}->Label(width   => 30)->pack;

    my $b = 
	$self->{mw}->Button(-font => '*-times-bold-r-normal--*-180-*-*-p-*-*-*',
			    -text        => "Update Plates",
			    -height      => 1,
			    -bg          => 'white',
			    -relief      => 'groove',
			    -borderwidth => '3',
			    )->pack(-side => 'top');

    $b->bindtags(['DebugButton',$b->toplevel,'all']);
    $b->bind('DebugButton', '<Control-Button-2>', sub{
	warn "debug was $debug. Setting to 1\n";
	$debug = 1;
    } );

    my $slb = 
	$self->{mw}->ScrlListbox(-width  => 60,
				 -height => 5,
				 -bg     => 'white',
				 )->pack(-side => 'top');
    $self->{messages} = $slb;

    $self->{mw}->Label()->pack;

    # User bar code
    my $userF = $self->{mw}->Frame()->pack;
    $userF->Label(-width  => 18,
		  -anchor => 'nw',
		  -text   => 'User barcode ID',
		  )->pack(-side => 'left');
    $self->{userWidget} = $userF->Entry(-width        => 24,
					-textvariable => \$self->{user},
					-bg => 'pale green'
					)->pack(-side => 'right');
 
    $self->{userWidget}->bind('<KeyPress-Return>', [\&addUser] );
    $self->{userWidget}->bind('<KeyPress-Tab>',    sub {Tk::break;} );
    $self->{userWidget}->bind('<ButtonPress>' ,    [\&setFocusPlateID] );

    # plate bar code
    my $plateF = $self->{mw}->Frame()->pack;
    $plateF->Label(-width        => 18,
		   -anchor       => 'nw',
		   -text         => 'Plate barcode ID',
		   )->pack(-side => 'left');
    $self->{plateWidget} = $plateF->Entry(-width        => 24,
					  -textvariable => \$self->{plate},
					  )->pack(-side => 'right');

    $self->{plateWidget}->bind('<KeyPress-Return>', \&addPlate );
    $self->{plateWidget}->bind('<KeyPress-Tab>', sub {Tk::break;} );

    # Plates
    my $outerF  = $self->{mw}->Frame()->pack;
    my $platesF = $outerF->Frame()->pack(-side => 'left');
    $platesF->Label(-width  => 18,
		    -anchor => 'nw',
		    -text   => 'Plates scanned in:',
		    )->pack;#(-side => 'left', -anchor => 'nw');
    $platesF->Label(-width        => 4,
		    -textvariable => \$self->{plateCount},
		    -bg           => 'LemonChiffon2',
		    -borderwidth  => 3,
		    -relief       => 'sunken',
		    )->pack;

    $self->{platesWidget} =
	$outerF->ScrlListbox(-width  => 21,
			     -height => 20)->pack(-side => 'right');
    $outerF->pack();

    # Status

    if( $self->{showStatus} ){
	my $statusF = $self->{mw}->Frame()->pack;
	$statusF->Label(-width  => 20,
			-anchor => 'nw',
			-text   => 'Status')->pack(-side => 'left');

	$statusF->BrowseEntry(-width => 20)->pack;
    }

    # Buttons
    my $buttsF = $self->{mw}->Frame()->pack;

    $buttsF->Button(-width   => 6,
		    -text    => 'Ok',
		    -command => sub {&okPressed;}
		    )->grid(-row => 1, -column => 1);

    $buttsF->Label(-width => 40)->grid(-row => 1, -column => 2);
    
    $buttsF->Button(-width   => 6,
		    -text    => 'Cancel',
		    -command => sub {
			if( $self->{plateCount} > 0 ){
			    my $answer = 
				&yesNo("Are you sure you want to clear the ".
				       "window and start again?");
			    &clearEverything() if $answer eq 'Yes';
			}
			else {
			    &clearEverything();
			}
		    },
		    )->grid(-row => 1, -column => 3);

    &showStartMessage();

    # set focus to User entry widget
    $self->{userWidget}->focus;
    $self->{userWidget}->grab;
}

sub addUser {
    warn "addUser $self->{user}\n" if $debug;

    my $refToHash = Barcodelive::Verifynumber($self->{user});

    print Data::Dumper::Dumper($refToHash)  if $debug;

    if( $refToHash->{Type} ne 'ID' || $refToHash->{Process} ne 'Good' ){
	&showMessage("You must enter the barcode that identifies you.");
	$self->{user} = '';
	return;
    }

    $self->{usedID} = $refToHash->{Number};

    # get users email initails to display instead of a barcode number
    my $dbh = $self->{dbi};

    eval {
	unless( $dbh ) {
	    $dbh         = WrapDBI->connect($self->{dbUser}, {RaiseError => 1});
	    $self->{dbi} = $dbh;
	}

	unless( defined $dbh ) {
	    $self->{dbi} = '';
	    $self->expire("Could not connect to database");
	}

	$dbh->{AutoCommit} = 0;

	my $count = $dbh->fetch_scalar("
            select count(*)
            from   PERSON
            where  ID_PERSON = $self->{usedID}");

	warn "count for ID_PERSON = $count. (zero if didn't exist)\n" if $debug;

	unless( defined($count) ){
	    &showMessage("Is that an old user barcode? It does not exist ".
			 "in Oracle");
	    $self->{usedID} = '';
	    $self->{user}   = '';
	    die "just return\n";
	}

	my $email_id = $dbh->fetch_scalar("
            select EMAIL
            from   PERSON
            where  ID_PERSON = $self->{usedID}");

	if( defined($email_id) || ($email_id ne '') ){
	    $self->{user} = $email_id;
	}
	else {
#	    &showMessage("You do not have an email address in Oracle.");
	}
    };
    if ($@) {
	return if $@ eq "just return\n";

	&showError("$@\n");
	$dbh->disconnect if $dbh;
	$self->{dbi} = '';
    }

    $self->{userWidget}->grabRelease();
    $self->{plateWidget}->focus();
#    $self->{plateWidget}->grab;

    $self->{userWidget}->configure( -bg => 'light grey');
    $self->{plateWidget}->configure(-bg => 'pale green');
}

sub addPlate {
    warn "to add $self->{plate}\n" if $debug;

    my $refToHash = Barcodelive::Verifynumber($self->{plate});

    if( $refToHash->{Type} ne 'LP' || $refToHash->{Process} ne 'Good' ){
	&showMessage("Incorrect barcode for a loading plate ($self->{plate})",
		     1);
	$self->{plate} = '';
	return;
    }

    my $loadingplate = $refToHash->{Whole};

    print Data::Dumper::Dumper($refToHash) if $debug;

    if( $self->{plates}->{$loadingplate} ){
	&showMessage("You have already scanned in this plate ($loadingplate)",
		     0);
	$self->{plate} = '';
	return;
    }

    $self->{plates}->{$loadingplate} = $refToHash->{Number};
    $self->{platesWidget}->insert('end', $loadingplate);
    $self->{plate} = '';

    $self->{plateCount}++;
}

sub okPressed {
    unless( defined($self->{plates}) ){
	&showMessage("You must enter at least one plate first!");
	return;
    }

    my $dbh = $self->{dbi};

    eval {
	unless( $dbh ) {
	    $dbh         = WrapDBI->connect($self->{dbUser}, {RaiseError => 1});
	    $self->{dbi} = $dbh;
	}

	if( !defined $dbh ) {
	    $self->{dbi} = '';
	    $self->expire("Could not connect to database");
	}

	$dbh->{AutoCommit} = 0;

	my $session_id =
	    $dbh->fetch_scalar("select SEQ_SESSION.NEXTVAL FROM DUAL");

	my $next_plate = 0;
PLATE:
	foreach (sort keys %{$self->{plates}}) {

	    my $id_loading_plate = $self->{plates}->{$_};
	    warn "id_loading_plate = $id_loading_plate\n" if $debug;

	    # check on status's already entered for this plate
	    my $arrayOfArrays = $dbh->fetch_all("
                select *
                from   LOADINGPLATE_STATUS
                where  ID_LOADINGPLATE = $id_loading_plate
                and    ISCURRENT       = 1");

	    print "all lp status's wi ISCURRENT == 1\n",
	          Data::Dumper::Dumper($arrayOfArrays) if $debug;

	    if( scalar(@{$arrayOfArrays}) > 1 ){
		&mailBug("Plate $_ had more than one ISCURRENT status",
			 $arrayOfArrays);
	    }

	    if( scalar(@{$arrayOfArrays}) < 1 ){
		# it is possible for user to guess a fake plate ID with the
		# correct check digit/char on the end - 

		my $count = $dbh->fetch_scalar("
                    select count(ID_LOADINGPLATE)
                    from   LOADINGPLATE_STATUS
                    where  ID_LOADINGPLATE = $id_loading_plate");

		if( $count == 0 ){
		    &mailBug("Plate $_ did not exist in DB. ".
			     "Scanned in by user $self->{user}");

		    &showError("Plate $_ did not exist in DB! An email has ".
			       "been sent to bug. Please contact bug now.");
		    next PLATE;
		}
		else {
		    &mailBug("Plate $_ (ID $id_loading_plate) had no status ".
                             "with ISCURRENT set to 1. ".
			     "Scanned in by user $self->{user}");
		}
	    }

	    foreach my $rowRef ( @{$arrayOfArrays} ){
		if( $rowRef->[1] > 1 ){ # 2 == submitted, 3 gel assigned etc

		    &showError("Plate '$_' has already been ".
			       "submitted. If this is not the case ".
			       "please contact bug.");

		    next PLATE;
		}
	    }

	    # set all ISCURRENTs to 0
	    $dbh->do("
                update LOADINGPLATE_STATUS 
                set    ISCURRENT = 0
                where  ID_LOADINGPLATE = $id_loading_plate");

	    # finally add status record		
	    $dbh->do("
                insert into LOADINGPLATE_STATUS
                       (ID_LOADINGPLATE,
                        STATUS,
                        ISCURRENT,
                        STATUSDATE,
                        SESSIONID,
                        PROGRAM,
                        OPERATOR)
                values ($id_loading_plate,
	                2,
	                1,
	                SYSDATE,
	                $session_id,
	                '$0',
	                '$self->{user}')");
	}
    };

    # check eval executed correctly
    if ($@) {
	&showError("$@\n");
	$dbh->disconnect if $dbh;
	$self->{dbi} = '';
    }
    else {
	$dbh->commit     if $dbh;
	&clearEverything();
    }
}

# as long as usedID is set, it must be a valid user...
sub setFocusPlateID {

    if( $self->{usedID} ){

        $self->{userWidget}->grabRelease();
        $self->{plateWidget}->focus();

        $self->{userWidget}->configure( -bg => 'light grey');
        $self->{plateWidget}->configure(-bg => 'pale green');
    }
}

sub clearEverything {
    delete $self->{plates};

    $self->{messageCount} = 0;
    $self->{messages}->delete('0', 'end');
    $self->{user}         = '';
    $self->{usedID}       = '';
    $self->{userWidget}->configure(-bg => 'pale green');
    $self->{plateWidget}->configure(-bg => 'light grey');
    $self->{platesWidget}->delete('0', 'end');

    $self->{plateCount} = 0;

    &showStartMessage();

    # set focus to User entry widget
    $self->{userWidget}->focus;
    $self->{userWidget}->grab;
}

sub showStartMessage {
    $self->{messages}->insert('end',
			      "Scan in your personal barcode then one or".
			      " more plate barcodes");
}

sub showError {
    my ($message) = @_;

    warn "ERROR: $message\n" if $debug;

    $self->{mw}->bell();
    $self->{mw}->bell();
    $self->{mw}->bell();

    my $dialog = $self->{mw}->Dialog (
				      -title          => "Error",
				      -text           => "$message",
				      -default_button => 'OK',
				      -buttons        => ['OK']);
    $dialog->Show();
}

sub showMessage {
    my ($message, $bell) = @_;

    $bell = 1 unless defined($bell);

    warn "ERROR: $message\n" if $debug;

    $self->{messageCount}++;

warn "bell == $bell\n" if $debug;

    if( $bell ){
	$self->{messages}->bell();
	$self->{messages}->bell();
	$self->{messages}->bell();
    }

    $self->{messages}->insert('end', $message);
    $self->{messages}->yview($self->{messageCount});
}

sub yesNo {
    my ($message) = @_;

    $self->{messages}->bell();

    my $dialog = $self->{mw}->Dialog (
				      -title          => "Are You Sure?",
				      -text           => "$message",
				      -default_button => 'No',
				      -buttons        => ['Yes', 'No']);
    return $dialog->Show();
}

# $ref is a reference to a data structure - Data::Dumper will be used to 
# show whats in it. $ref is optional.

sub mailBug {
    my ($message, $ref) = @_;
    
    if( defined($ref) ){
	$message .= "\n\n".(Data::Dumper::Dumper($ref));
    }

    $message .= "\n\nprogram: $0";

    Mail::sendMail( -to      => 'bug',
		    -subject => "Error Submitting plates to WP", 
		    -message => $message);
}


#
# $Log: update_plates.pl,v $
# Revision 1.8  1999/08/26 15:51:11  pjm
# you can no longer click in the user widget to get focus. It will give
# the Plate Barcode entry widget focus instead.
#
# Revision 1.7  1999/08/26 14:37:50  pjm
# mail now sent to bug and not pjm.
#
# Revision 1.6  1999/08/26 14:08:58  dn1
# *** empty log message ***
#
# Revision 1.5  1999/08/26 14:02:11  pjm
# added $Id: update_plates.pl,v 1.8 1999/08/26 15:51:11 pjm Exp $  and  $Log: update_plates.pl,v $
# added $Id: update_plates.pl,v 1.7 1999/08/26 14:37:50 pjm Exp pjm $  and  Revision 1.8  1999/08/26 15:51:11  pjm
# added $Id: update_plates.pl,v 1.7 1999/08/26 14:37:50 pjm Exp pjm $  and  you can no longer click in the user widget to get focus. It will give
# added $Id: update_plates.pl,v 1.7 1999/08/26 14:37:50 pjm Exp pjm $  and  the Plate Barcode entry widget focus instead.
# added $Id: update_plates.pl,v 1.7 1999/08/26 14:37:50 pjm Exp pjm $  and
# added $Id: update_plates.pl,v 1.8 1999/08/26 15:51:11 pjm Exp $  and  Revision 1.7  1999/08/26 14:37:50  pjm
# added $Id: update_plates.pl,v 1.8 1999/08/26 15:51:11 pjm Exp $  and  mail now sent to bug and not pjm.
# added $Id: update_plates.pl,v 1.8 1999/08/26 15:51:11 pjm Exp $  and
# added $Id: update_plates.pl,v 1.8 1999/08/26 15:51:11 pjm Exp $  and  Revision 1.6  1999/08/26 14:08:58  dn1
# added $Id: update_plates.pl,v 1.8 1999/08/26 15:51:11 pjm Exp $  and  *** empty log message ***
# added $Id: update_plates.pl,v 1.8 1999/08/26 15:51:11 pjm Exp $  and to top and bottom of file
#
#
