
#
# $Id: LemurRequestJob.pm,v 1.34 2005/11/14 16:30:51 mdf Exp $
#

package LemurRequestJob;

require Exporter;

use     strict;
use     WrapDBI;
use     Mail;

use     Tk;
use     Tk::NoteBook;
require LemurUtils;
#require "/nfs/weka2/pjm/badger-bin/LemurUtils.pm";
use     Data::Dumper;
use     OORepository;

require NewBrowseEntry;

# The old BrowseEntry.pm doesn't support deletes. Let's try the new one instead
#require "/nfs/disk68/dn1/badger-bin/gull/NewBrowseEntry.pm";
#require "/nfs/weka2/pjm/work/library-making/NoteBook.pm";


use POSIX qw(strtod);                     # string to digit? See isValidNumbr()

#my $dbuser = 'dev2';                      # for testing purposes only

##########################################
# CONSTANTS
##########################################

*MAIN::ENZYME_FILE = \ "/nfs/disk8/mq1/seqfiles/enzyme.dat";
*MAIN::NUM_BANDS   = \ 3; #loop goes from 0..*MAIN::NUM_BANDS, so inc value by 1

##########################################
# GLOBALS
##########################################

my $debug    = 0; # This can be set to 1 by mouse-middle-button & CTRL pressed
my $bug_mail = 'bug';

sub new {
    my ($type, $parentWindow, $dbUser, $session_id, $startedByFiniher) = @_;
    my $realUserName = getpwuid($<);

    my $self = {
	dbUser            => $dbUser,
	session_id        => $session_id,
	realUserName      => "$realUserName",
	startedByFinisher => "$startedByFiniher",
    };

    bless($self, $type);

    # setup hash tables gets a db handle to Oracle.
    $self->setupHashTables();
    $self->prepare_sql();

    # create new window
    if( $parentWindow ) {
	$self->{mw} = $parentWindow->Toplevel();
    }
    else {
	$self->{mw} = new MainWindow;
    }

    # make sure windiw is a set size

    $self->{mw}->wm('minsize', 450, 745); 
    $self->{mw}->wm('maxsize', 450, 745);
    my $f = $self->{mw}->Frame(-height => 450, -width => 745);
    $f->pack();
    $self->{mw}->idletasks();
 #   $self->{mw}->packPropagate(0);
    $f->packForget();

    $self->{mw}->protocol('WM_DELETE_WINDOW' => sub { 
	if( $parentWindow ){
	    $self->hide();
	}
	else {
	    $self->{mw}->destroy;
	}
    });

    $self->{mw}->title('Enter Subclone Job');
#    $self->{mw}->Label(font    => '*-times-bold-r-normal--*-180-*-*-p-*-*-*',
#		       text    => "Request a Small Insert Library ('Job')",
#		       height       => 1,
#		       -bg          => 'white',
#		       -relief      => 'groove',
#		       -borderwidth => '3',
#		       )->pack(-side => 'top');

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

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

    $self->{mw}->bind('<Delete>', 'Backspace');

    my $mf = $self->{mw}->Frame(-relief      => 'groove',
				#-borderwidth => '3',
				);

    # create Selection frame $sf
    # create Submitter and Clone frame ($cf). It will be embedded into the 
    # selection frame 'cos of the Mapped & Unmapped widgets

    my $sf = $mf->Frame();
    my $cf = $sf->Frame(-relief => 'groove', -borderwidth => 3);

    my $temp = 
        $cf->Label(-width  => 17,
	       -text   => 'Submitter', 
	       -anchor => 'w'
	       )->grid(-row    => 1,
		       -column => 1,);
    
    my $w1 =
        $cf->BrowseEntry(-width     => 18,
			 -relief    => 'sunken',
			 -variable  => \$self->{submitter},
			 -choices   => [sort keys %{$self->{finisherHash}} ],
			 -state     => 'readonly',
			 -browsecmd => sub { 
#			     $self->getClonesForFinisher();
#			     my $ref   = $self->{clonesForFinisher};
#			     my $array = $ref->{$self->{submitter}};

			     my $array = $self->getClonesForFinisher();
			     $self->{searchWidget}->configure(-choices => 
							      $array);
			 },
			 )->grid(-row    => 1, 
				 -column => 2, 
				 -sticky => 'nw');

    $self->setBrowseEntryLemon($w1);

    my $b1 = $self->{mw}->Balloon('-state' => 'balloon');
    $b1->attach($w1,
		-balloonmsg => "A list of all finishers.\nPick your name!",
		);

    $self->{balloon} = $b1;

    # destroy the balloons when I am destroyed:
    #  - we add bindings to all widgets which we now want 
    #    to remove if we can.

    $self->{mw}->OnDestroy(sub { $b1->destroy; });

    # Clone Name

    $cf->Label(-width  => 17,
	       -text   => 'Clone Name', 
	       -anchor => 'w'
	       )->grid(-row    => 2,
		       -column => 1,);
    
    $self->{searchWidget} =
        $cf->BrowseEntry(-width     => 18,
			 -relief    => 'sunken',
			 -variable  => \$self->{cloneName},
			 -choices   => sub {
			     warn shift;
			     warn shift;
			     my $array = $self->getClonesForFinisher();
			     $self->{searchWidget}->configure(-choices => 
							      $array);
			 },
			 )->grid(-row        => 2, 
				 -column     => 2, 
				 -sticky     => 'nw',
				 -columnspan => 2,);

    my $array = $self->getClonesForFinisher();
    $self->{searchWidget}->configure(-choices => $array);


    $self->setBrowseEntryLemon($self->{searchWidget});

    $self->{searchWidget}->bind('<KeyPress-Return>', sub { 
	$self->searchForCloneName; 
    });
    $self->{searchWidget}->bind('<KeyPress-Tab>', sub { 
	$self->searchForCloneName; 
    });

    $b1->attach($self->{searchWidget},
		-balloonmsg => "You can search for a clone name\n Enter ".
		               "part of the name and press return",
		);

    # create SELECTION frame

    $self->createSelectionFrame($sf, $cf);


    # FRAGMENT SIZES REQUIRED

    my $bf                = $mf->Frame(-relief => 'groove', -borderwidth => 3);
    $self->{libSizeFrame} = $bf;

    my @fromToArray;
    $self->{BandsArray} = \@fromToArray;

    $bf->Label (-width  => 17,
		-text   => 'Required',
		-anchor => 'w',
		)->grid(-row    => 2,
			-column => 1,);

    $bf->Label (-width  => 5,
		-text   => 'From',
		)->grid(-row    => 2,
			-column => 2,);

    $bf->Label (-width  => 5,
		-text   => 'To',
		)->grid(-row    => 2,
			-column => 3);

    my @widgets;
    my $bg;
    my $message = "You request at least 1 library size of X to Y\n".
	          "Example: 300 - 500";

    foreach my $x ( 0..$MAIN::NUM_BANDS ) {
	$bf->Label (-width  => 17,
		    -text   => "Library size ".($x+1),
		    )->grid(-row    => $x+3,
			    -column => 1,
			    -sticky => 'nw');

	if( $x == 0 ) {
	    $widgets[$x][0] =
		$bf->Entry(-width        => 7,
			   -relief       => 'sunken',
			   -bg           => 'lemonchiffon2',
			   -textvariable => \$fromToArray[$x][0],
			   )->grid(-row    => $x+3,
				   -column => 2,
				   -sticky => 'nw');
	    $widgets[$x][1] = 
		$bf->Entry(-width        => 7,
			   -relief       => 'sunken',
			   -bg           => 'lemonchiffon2',
			   -textvariable => \$fromToArray[$x][1],
			   )->grid(-row    => $x+3,
				   -column => 3,
				   -sticky => 'nw',
				   -padx   => 6);
	}
	else {
	    $widgets[$x][0] =
		$bf->Entry(-width        => 7,
			   -relief       => 'sunken',
			   -textvariable => \$fromToArray[$x][0],
			   )->grid(-row    => $x+3,
				   -column => 2,
				   -sticky => 'nw');
	    $widgets[$x][1] = 
		$bf->Entry(-width        => 7,
			   -relief       => 'sunken',
			   -textvariable => \$fromToArray[$x][1],
			   )->grid(-row    => $x+3,
				   -column => 3,
				   -sticky => 'nw',
				   -padx   => 6);
	}

	$bf->Label(-width => 3,
		   -text  => 'bp',
		   )->grid(-row    => $x+3,
			   -column => 4,
			   -sticky => 'nw',);

	$b1->attach($widgets[$x][0],
		    -balloonmsg => $message,
		    );

	$b1->attach($widgets[$x][1],
		    -balloonmsg => $message,
		    );
    }

    # create CLONE INTO VECTOR frame $vf

    my $vec_list = $self->getVectorList();
    my $vf       = $mf->Frame(-relief => 'groove', -borderwidth => 3);

    $self->{cloneIntoVectorFrame} = $vf;

    $vf->Label(-width  => 16,
	       -text   => 'Clone into Vector', 
	       -anchor => 'w'
	       )->grid(-row    => 2,
		       -column => 1,);

    $self->{vectorWidget} =
        $vf->BrowseEntry(-width     => 18,
			 -relief    => 'sunken',
			 -variable  => \$self->{cloneIntoVector},
			 -choices   => $vec_list,
                         -state     => 'readonly',
			 )->grid(-row    => 2, 
				 -column => 2, 
				 -sticky => 'nw');

    LemurUtils->setBrowseEntryGrey($self->{vectorWidget});

    $b1->attach($self->{vectorWidget},
		-balloonmsg => "Optional field. You maybe more specific ".
		               "if you wish",
		);

    # create comment frame $comf

    my $comf = $mf->Frame(-relief => 'groove', -borderwidth => 3);

    $comf->Label(-width  => 23,
		 -text   => 'Comment to Subcloner', 
		 -anchor => 'w'
		 )->grid(-row    => 1,
			 -column => 1,
                         -sticky => 'nw');

    $comf->Entry(-width        => 38,
                 -relief       => 'sunken',
                 -textvariable => \$self->{comment},
                )->grid(-row    => 2, 
                        -column => 1, 
			-sticky => 'nw');

    # BUTTONS

    my $okCancel = $mf->Frame();

    $okCancel->Button(-width   => 10,
                      -text    => 'Add',
		      -command => sub { 
			  if( $self->addPressed() ) {
			      $self->clearWidgets();
			  }
		      },
                      )->grid(-row    => 1, 
                              -column => 1, 
			      -sticky => 'nw');

    $okCancel->Button(-width   => 10,
                      -text    => 'Reports',
		      -command => sub {
			  if( $self->{dbUser} eq 'dev1' ){
			      system '/nfs/galyep/pjm/badger-bin/gull/Reports.pjm -prog lemur &';
			  } else {
			      system 'Reports -prog lemur &';
			  }
		      },
                      )->grid(-row    => 1, 
                              -column => 2, 
			      -sticky => 'nw');

    $okCancel->Button(-width => 10,
                      -text  => 'Done',
                      -command =>
                          sub { $self->disconnect;
				if( $self->{startedByFinisher} ){
				    $self->{mw}->destroy();
				}
				else {
				    $self->hide();
				}
			    },
                      )->grid(-row    => 1, 
                              -column => 4, 
			      -sticky => 'ne');

    $sf->pack(-padx => 10);     # selection frame
#    $cf->pack(-padx => 10);     # clone, submitter name
    $bf->pack(-padx => 10);     # fragment sizes desired - was Bands frame
    $vf->pack(-padx => 10);     # clone into Vector
    $comf->pack(-padx => 10);   # Comment frame

    $mf->pack  (-padx => 10);

    $okCancel->pack(-padx => 10, -expand => 1, -fill => 'both');


    return $self;
}

sub show {
    my ($self) = @_;

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

sub hide {
    my ($self) = @_;

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

# If the Oracle connection has been blown away ('cos Oracle crashed) ignore it.
sub disconnect {
    my ($self) = @_;

    eval {
	$self->{dbi}->disconnect if $self->{dbi};
    };

    if( $@ && 
	$@ !~ /disconnect failed: ORA-03113: end-of-file on communication/ ){

	LemurUtils->showError("Error: LemurRequestJob: $@");
    }

    $self->{dbi} = undef;
}

#
# Sub Clone details
#

sub createSubCloneFrame {
    my ($self, $f) = @_;

    $f->Label( -width  => 17,
	       -text   => 'Sub Clone (pUC)', 
	       -anchor => 'nw'
	       )->grid(-row    => 4,
		       -column => 1,);

    my $tF = $f->Frame();

    $tF->Label(-width  => 9,
	       -text   => 'Plate Name', 
	       )->grid(-row    => 1,
		       -column => 1,);

    $tF->Label(-width  => 5,
	       -text   => 'Row', 
	       )->grid(-row    => 1,
		       -column => 2,);

    $tF->Label(-width  => 5,
	       -text   => 'Col', 
	       )->grid(-row    => 1,
		       -column => 3,);

    $tF->Entry(-width        => 9,
	       -textvariable => \$self->{plateName},
	       -bg           => 'lemonchiffon2',
	       )->grid(-row    => 2,
		       -column => 1,);

    $tF->Entry(-width        => 5,
	       -textvariable => \$self->{row},
	       -bg           => 'lemonchiffon2',
	       )->grid(-row    => 2,
		       -column => 2,);

    $tF->Entry(-width        => 5,
	       -textvariable => \$self->{col},
	       -bg           => 'lemonchiffon2',
	       )->grid(-row    => 2,
		       -column => 3,);

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

    $f->Label(-width  => 17,
	       -text   => 'Plate Format', 
	       )->grid(-row    => 5,
		       -column => 1,);

    my $t1 =
	$f->BrowseEntry(-width     => 18,
			-relief    => 'sunken',
			-variable  => \$self->{plateFormat},
			-choices   => [sort keys %{$self->{plateFormats}}],
			-state     => 'readonly',
			)->grid(-row        => 5, 
				-column     => 2,);

    $self->setBrowseEntryLemon($t1);

    # default to 96 well plate (if in DB)

    if( exists($self->{plateFormats}->{"96 - well plate"} )) {
	$self->{plateFormat} = "96 - well plate";
    }


    my $arrayRef = $self->getVectorList();
    if( $self->{vectorsWithEnzymes}->{"puc18 (SmaI)"} ){
	$self->{isInVector} = "puc18 (SmaI)";
    }

    $f->Label(-width  => 17,
	      -text   => 'is in vector', 
	      )->grid(-row    => 6,
		      -column => 1,);

    my $t2 =
	$f->BrowseEntry(-width     => 18,
			-relief    => 'sunken',
			-variable  => \$self->{isInVector},
			-choices   => $arrayRef,
                              #[keys %{$self->{vectorsWithEnzymes}}],
			-state     => 'readonly',
			)->grid(-row        => 6, 
				-column     => 2,);

    $self->setBrowseEntryLemon($t2);
    $self->{balloon}->attach($t2,
		      -balloonmsg => "This is in the format 'Vector (enzyme)'".
			             " . \nPick SmaI if you don't know the ".
			             "enzyme");

    $self->createApproxGapSizeFrame($f);
}

# APPROX GAP SIZE

sub createApproxGapSizeFrame {
    my ($self, $bf) = @_;

#    my $bf = $mf->Frame();

    $bf->Label(-width  => 17,
	       -text   => "Approx Gap size",
	       -anchor => 'w',
	       )->grid(-row    => 10,
		       -column => 1,);

    my $f4 = $bf->Frame();
    my $t1 = 
	$f4->Entry(-width  => 17,
		   -textvariable => \$self->{GapSize},
		   -bg           => 'lemonchiffon2',
		   )->grid(-row    => 1,
			   -column => 1,);

    $f4->Label(-width  => 2,
	       -text   => "Kb",
	       -anchor => 'w',
	       )->grid(-row    => 1,
		       -column => 2,
		       -sticky => 'w',);

    $f4->grid(-row        => 10,
              -column     => 2,
	      -columnspan => 3);

    $self->{balloon}->attach($t1,
		-balloonmsg => "The size of the gap you are trying to close.\n".
		               "Guess if you don't know.",
		);
#    $bf->grid(-row => 1, -column => 1);
}

# Sets the Browse Entry widget to LemonChiffon2 - the 'must enter' colour

sub setBrowseEntryLemon {
    my ($self, $widget) = @_;

    my $e = $widget->Subwidget("entry")->Subwidget("entry");
    $e->configure(-bg => 'LemonChiffon2');
}

################################################################################
# connects to DB and handles any errors. Calls various subroutines to setup
# hash tables with data from dictionaries.
################################################################################

sub setupHashTables {

    my ($self) = @_;
    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;

	$self->getRecoveryMethods   ($dbh);
	$self->getFragMethods       ($dbh);
#	$self->getSuggestedEnzymes  ($MAIN::ENZYME_FILE);
	$self->getEnzymes           ($dbh);
#	$self->getOligos            ($dbh);
#	$self->getOligoPrimers      ($dbh);
#	$self->getSTS               ($dbh);
#	$self->getOperators         ($dbh);
	$self->getVectorsWithEnzymes($dbh);
	$self->getFinishers         ($dbh);
	$self->getPlateFormats      ($dbh);
	$self->getClonesForFinisher ($dbh);

    };

    if ($@) {
#	$dbh->disconnect if $dbh;
	$self->expire("$@ : Occured in setupHashtables()");
    }

#    $dbh->disconnect if $dbh;
}

sub prepare_sql {
    my ($self) = @_;

    $self->{sth_is_valid_plate_name} =
        $self->{dbi}->prepare(q[select count(*)  from BECKMAN_BOX
                                where  NAME = ? ]);

}


################################################################################
# setup  '%recoveryMethodHash'
################################################################################

sub getRecoveryMethods {

    my ($self, $dbh, $args) = @_;
    my ($arrayOfArrays, $arrayRef);

    $arrayOfArrays = $dbh->fetch_all(
        "select ID_DICT, DESCRIPTION
         from   FragRecoveryDict");

    foreach $arrayRef (@$arrayOfArrays) {
	$self->{recoveryMethodHash}->{@$arrayRef[1]} = @$arrayRef[0];
    }
}


################################################################################
# setup '%fragMethodHash'
#        %FragSizeDict      (hash to a list)
################################################################################

sub getFragMethods {

    my ($self, $dbh, $args) = @_;
    my ($arrayOfArrays, $arrayRef);;

    $arrayOfArrays = $dbh->fetch_all(
        "select ID_DICT, DESCRIPTION
         from   FragMethodDict");

    foreach $arrayRef (@$arrayOfArrays) {
	$self->{fragMethodHash}->{@$arrayRef[1]} = @$arrayRef[0];
    }

    foreach my $method (keys %{$self->{fragMethodHash}} ) {

	my @temp;

	$arrayOfArrays = $dbh->fetch_all(
	    "select SIZE_FROM_KB, SIZE_TO_KB
             from   FragSizeDict
             where  ID_FragMethod = $self->{fragMethodHash}->{$method}");

	foreach my $row (@$arrayOfArrays) {
	    push @temp, "@$row[0] - @$row[1]";
	}

	$self->{fragSizeHash}->{$method} = \@temp;
    }
}


################################################################################
#
# not sure if need to store CUTSITE, METHYLATIONSITE
# out of date code?
#
################################################################################

sub getEnzymes {

    my ($self, $dbh) = @_;
    my ($arrayOfArrays, $arrayRef);

    $arrayOfArrays = $dbh->fetch_all(
         "select ENZYMENAME, CUTSITE, METHYLATIONSITE
          from   ENZYME
          where  ISAVAILABLE = 1"); 

    foreach $arrayRef (@$arrayOfArrays) {

	$self->{enzymeHash}->{$arrayRef->[0]} = 
	    {CUTSITE         => $arrayRef->[1],
	     METHYLATIONSITE => $arrayRef->[2],};
    }
}


################################################################################
#
################################################################################

sub getOligos {
    my ($self, $dbh) = @_;
    my ($arrayOfArrays, $arrayRef);

    $arrayOfArrays = $dbh->fetch_all("
          select ID_OLIGO, OLIGONAME, OLIGO_SEQUENCE
          from   OLIGO"); 

    foreach $arrayRef (@$arrayOfArrays) {

	$self->{oligoHash}->{(@$arrayRef[0])} = 
	     {name     => @$arrayRef[1],
	      sequence => @$arrayRef[2]};
    }
}


################################################################################
#
################################################################################

sub getOligoPrimers {
    my ($self, $dbh) = @_;
    my ($arrayOfArrays, $arrayRef);


    $arrayOfArrays = $dbh->fetch_all("
          select ID_OLIGOPRIMER, PARENT_NAME, ID_STS, IS_SENSE, ID_OLIGO
          from   OLIGO_PRIMER"); 

    foreach $arrayRef (@$arrayOfArrays) {

	$self->{oligoPrimerHash}->{(@$arrayRef[0])} = 
	    {parent_name => @$arrayRef[1],
	     id_sts      => @$arrayRef[2],
	     is_sense    => @$arrayRef[3],
	     id_oligo    => @$arrayRef[4],};
    }
}

################################################################################
# Produces the hash table $self->{STSHash}, which also contains a hash via a
# refernce to $self->{OligoPrimer}->{the key}. Structure looks like;
#
# $self->{STSHash}->{ID_STS} => {
#                            sts_prefix => 2,
#
#                            forward    => {
#				is_sense    => 1,
#				parent_name => 'My parent',
#				id_oligo    => 1,
#				id_sts      => 1
#				},
#
#                            reverse    => {
#				is_sense    => '0',
#				parent_name => 'My parent',
#				id_oligo    => 2,
#				id_sts      => 1
#				},
#                          },
#
################################################################################

# CURRENTLY NOT CALLED...
sub getSTS {
    my ($self, $dbh) = @_;
    my ($arrayOfArrays, $arrayRef);


    $arrayOfArrays = $dbh->fetch_all("
          select ID_STS, STS_PREFIX
          from   STS"); 

    foreach $arrayRef (@$arrayOfArrays) {
	my ($key, $value);
	my ($forward, $reverse);

	while( ($key, $value) = each(%{$self->{oligoPrimerHash}})) {

	    if( $value->{id_sts} == @$arrayRef[0] ) {

		unless($forward){
		    $forward = $self->{oligoPrimerHash}->{$key};
		    next;
		}
		else {
		    $reverse = $self->{oligoPrimerHash}->{$key};
		    last;
		}
	    }
	}

	$self->{STSHash}->{ (@$arrayRef[0]) } = 
	    {sts_prefix => @$arrayRef[1],
	     forward    => $forward,
	     reverse    => $reverse,};
    }
}



################################################################################
# setup $self->{vectorsWithEnzymes} hash table.
# only gets the vectors with entries in the VECTORSITE_ENZYME table
#
# glues vector name to enzyme, which becomes then lookups return the 
# ID_VECTORSITE e.g.
#
#    $self->{vectorsWithEnzymes}->{"puc18 (HindIII)"  => 1,
#                                  "mp13mp18 (BamHI)" => 2}
#
################################################################################

sub getVectorsWithEnzymes {

    my ($self, $dbh) = @_;
    my ($arrayOfArrays, $arrayRef);
    my %vectors;

    $arrayOfArrays = $dbh->fetch_all("
        select v.VECTORNAME, ve.ENZYMENAME, v.ID_VECTORSITE
        from   VECTORSITE v, VECTORSITE_ENZYME ve
        where  v.ID_VECTORSITE = ve.ID_VECTORSITE"); 
 
    foreach $arrayRef (@$arrayOfArrays) {
	$vectors{"$arrayRef->[0] ($arrayRef->[1])"} = $arrayRef->[2];
    }

    $self->{vectorsWithEnzymes} = \%vectors;
}

sub getVectorList {
    my ($self) = @_;

    my (@vector_list)  = sort keys %{$self->{vectorsWithEnzymes}};
    
    my $x = 0;

    foreach (@vector_list) {
        if( $_ eq 'm13mp18 (SmaI)' ) {
            my $temp = splice(@vector_list, $x, 1);
            unshift(@vector_list, $temp);
            last;
        }
        ++$x;
    }

    $x = 0;

    foreach (@vector_list) {
        if( $_ eq 'puc18 (SmaI)' ) {
            my $temp = splice(@vector_list, $x, 1);
            unshift(@vector_list, $temp);
            last;
        }
        ++$x;
    }

    return \@vector_list;
}

################################################################################
# sets up
#
#      $self->{finisherHash}->{'Paul Mooney' => 100001,
#                              'Rob Smith'   => 100002,
#                              etc...                   }
#
# where the number is the ID_ROLE in TEAM_PERSON_ROLE
#
# NOTE: it also gets subcloners, since they may request jobs sometimes....
#
################################################################################

sub getFinishers {
    my ($self, $dbh) = @_;
    my $arrayOfArrays;
    my (%finishers, %email_id_of);

    $arrayOfArrays = $dbh->fetch_all("
	select tpr.ID_ROLE, p.FORENAME, p.SURNAME||' - '||tpr.teamname,p.EMAIL
        from   TEAM_PERSON_ROLE tpr, PERSON p
        where  ROLETYPE      in ('Finishing', 'Subcloning')
        and    tpr.ISCURRENT = 1
        and    tpr.ID_PERSON = p.ID_PERSON
	and p.iscurrent = 1");

    foreach my $finisherDet (@{$arrayOfArrays}) {
	my $fullName = $finisherDet->[1]." ".$finisherDet->[2];

	$finishers{$fullName}   = $finisherDet->[0];
	$email_id_of{$fullName} = $finisherDet->[3];

	if($self->{realUserName} eq $finisherDet->[3]) {
	    $self->{submitter} = $finisherDet->[1]." ".$finisherDet->[2];
	}
    }

    $self->{finisherHash} = \%finishers;
    $self->{email_id_of}  = \%email_id_of;
}

################################################################################
#
################################################################################

sub getPlateFormats {

    my ($self, $dbh) = @_;
    my $arrayOfArrays;
    my %plateFormats;

    $arrayOfArrays = $dbh->fetch_all("
        select ID_DICT, DESCRIPTION
        from   MTPFORMATDICT");

    foreach my $plateType (@{$arrayOfArrays}) {
	$plateFormats{$plateType->[1]} = $plateType->[0];
    }

    $self->{plateFormats} = \%plateFormats;
}

################################################################################
# it sets up a cache of clones for each finisher (submitter). The first time
# it is called by setupHashTables() and is given $dbh. After that it has to 
# re-connect to the DB.
################################################################################

sub getClonesForFinisher {

    my ($self, $dbh) = @_;
    my $arrayOfArrays;
    my @clones;

    return unless $self->{submitter};

    if( $self->{clonesForFinisher}->{ $self->{submitter} } ) {
	return $self->{clonesForFinisher}->{ $self->{submitter} };
    }

    my $finisher_id_role = $self->{finisherHash}->{$self->{submitter}};

    if( defined $dbh ) {
	$arrayOfArrays = $dbh->fetch_all("
             select cp.CLONENAME
             from   PROJECT_ROLE pr, CLONE_PROJECT cp
             where  pr.ID_ROLE     = $finisher_id_role
             and    pr.PROJECTNAME = cp.PROJECTNAME
	     order by cp.CLONENAME");

	foreach my $clone (@{$arrayOfArrays}) {
	    push @clones, $clone->[0];
	}

	$self->{clonesForFinisher}->{$self->{submitter}} = \@clones
    }
    else {
	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;

	    $arrayOfArrays = $dbh->fetch_all("
                select cp.CLONENAME
                from   PROJECT_ROLE pr, CLONE_PROJECT cp
                where  pr.ID_ROLE     = $finisher_id_role
                and    pr.PROJECTNAME = cp.PROJECTNAME
		order by cp.CLONENAME");

	    foreach my $clone (@{$arrayOfArrays}) {
		push @clones, $clone->[0];
	    }
	    $self->{clonesForFinisher}->{$self->{submitter}} = \@clones;
	};

	# Let user know if anything bad happened while accessing the database.

	if($@) {
	    my $error = $@;
	    LemurUtils->unSetWait([$self->{mw}, $self->{searchWidget}]);
	    LemurUtils->showError($self->{mw}, "$error");
	}
    }

    return \@clones;
}

################################################################################
# bound to <Return> key press on Clone Entry widget.
################################################################################

sub searchForCloneName {

    my ($self) = @_;
    my $goodCloneName = 1;
    my $arrayOfArrays;
    my $searchValue = $self->{cloneName};

    LemurUtils->setWait([$self->{mw}, $self->{searchWidget}]);

    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;

	$arrayOfArrays = $dbh->fetch_all("
            select CLONENAME
            from   CLONE
            where  CLONENAME like '%$searchValue%'");

	$self->{searchWidget}->delete('0', 'end');

	foreach my $array ( @$arrayOfArrays ) {
	    $self->{searchWidget}->insert('end', (@$array)[0]);
	}

	LemurUtils->unSetWait([$self->{mw}, $self->{searchWidget}]);

	# display the drop down window. 
        # Note: BtnDown is not a 'public' method.

	$self->{searchWidget}->BtnDown if ($self->{searchWidget}->{"popped"});
        $self->{searchWidget}->BtnDown;
    };

    # Let user know if anything bad happened while accessing the database.

    if($@) {
	my $error = $@;
	LemurUtils->unSetWait([$self->{mw}, $self->{searchWidget}]);
	LemurUtils->showError($self->{mw}, "$error");
    }

#    $dbh->disconnect if $dbh;
}

################################################################################
# bound to <Return> key press on Clone Entry widget.
################################################################################

sub searchForVector {

    my ($self)        = @_;
    my $goodCloneName = 1;
    my $arrayOfArrays;
    my $searchValue   = $self->{cloneIntoVector};

    LemurUtils->setWait([$self->{mw}]);

    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;

warn "search value = $searchValue\n" if $debug;

	$arrayOfArrays = $dbh->fetch_all("
            select VECTORNAME
            from   VECTOR
            where  VECTORNAME like '%$searchValue%'");

	$self->{vectorWidget}->delete('0', 'end');

	foreach my $array ( @$arrayOfArrays ) {

warn"$array->[0]\n" if $debug;

	    $self->{vectorWidget}->insert('end', $array->[0]);
	}

	# display the drop down window. 
        # Note: BtnDown is not a 'public' method.

	$self->{vectorWidget}->BtnDown if ($self->{vectorWidget}->{"popped"});
        $self->{vectorWidget}->BtnDown;
    };

    LemurUtils->unSetWait([$self->{mw}]);

    # Let user know  if anything bad happened while accessing the database.

    if($@) {
	LemurUtils->showError($self->{mw}, "$@");
    }  
}


################################################################################
# Arguments;
#           selectionF  - Frame to put gadgets in
################################################################################

sub createSelectionFrame {

    my ($self, $selectionF, $submitterFrame) = @_;

    $selectionF->Label(# -text => 'You require a',
		       -width => 2,
		       -anchor => 'w',
		       )->grid(-row    => 2,
			       -column => 1);
    

    $selectionF->Radiobutton(-variable => \$self->{frameChoice},
			  -text     => 'PCR for SIL',
			  -value    => 'PCR for SIL',
			  -width    => 15,
			  -anchor   => 'w',
			  -command  => sub { $self->changeSelectionFrame },
			  )->grid(-row    => 1,
				  -column => 2);

    $selectionF->Radiobutton(-variable => \$self->{frameChoice},
			  -text     => 'Sub Clone for SIL',
			  -value    => 'Sub Clone for SIL',
			  -width    => 15,
			  -anchor   => 'w',
			  -command  => sub { $self->changeSelectionFrame },
			  )->grid(-row    => 2,
				  -column => 2);

    $selectionF->Radiobutton(-variable => \$self->{frameChoice},
			  -text     => 'Transposon',
			  -value    => 'Transposon',
			  -width    => 15,
			  -anchor   => 'w',
			  -command  => sub { $self->changeSelectionFrame },
			  )->grid(-row    => 3,
				  -column => 2);

    $selectionF->Radiobutton(-variable => \$self->{frameChoice},
			  -text     => 'Clone PCR',
			  -value    => 'Clone PCR',
			  -width    => 15,
			  -anchor   => 'w',
			  -command  => sub { $self->changeSelectionFrame },
			  )->grid(-row    => 4,
				  -column => 2);

    my $gw = # blow this away
	$selectionF->Radiobutton(-variable => \$self->{frameChoice},
				 -text     => 'Genome Walk',
				 -value    => 'Genome Walk',
				 -width    => 15,
				 -anchor   => 'w',
				 -command  => sub { 
				     $self->changeSelectionFrame();
				 },
				 )->grid(-row    => 1,
					 -column => 3);

    $selectionF->Radiobutton(-variable => \$self->{frameChoice},
			  -text     => 'Oligo Screening',
			  -value    => 'Oligo Screening',
			  -width    => 15,
			  -anchor   => 'w',
			  -command  => sub { $self->changeSelectionFrame },
			  )->grid(-row    => 2,
				  -column => 3);

    $selectionF->Radiobutton(-variable => \$self->{frameChoice},
			  -text     => 'Restriction',
			  -value    => 'Restriction',
			  -width    => 15,
			  -anchor   => 'w',
			  -command  => sub { $self->changeSelectionFrame },
			  )->grid(-row    => 3,
				  -column => 3);



    $self->{PCRF}            = $selectionF->Frame(-relief      => 'groove',
						  -borderwidth => 3,       );

    $self->{pucF}            = $selectionF->Frame(-relief      => 'groove',
						  -borderwidth => 3,       );

    $self->{TransposonF}     = $selectionF->Frame(-relief      => 'groove',
						  );
    $self->{ClonePCRF}       = $selectionF->Frame(-relief      => 'groove',
						  -borderwidth => 3,
						  );

    $self->{WalkF}           = $selectionF->Frame(-relief      => 'groove',
						  -borderwidth => 3,       );

    $self->{OligoScreeningF} = $selectionF->Frame(-relief      => 'groove',
						  -borderwidth => 3,       );

    $self->{RestrictionF}    = $selectionF->Frame(-relief      => 'groove',
						  );

    $selectionF->Label(
		       )->grid(-row    => 4,
			       -column => 1);
    
    # EMBEDDED SUBMITTER FRAME - NASTY!!!

    $submitterFrame->grid(-row        => 5,
			  -column     => 1,
			  -columnspan => 3);


    $self->createPCRFrame           ($self->{PCRF});
    $self->createPucFrame           ($self->{pucF});
    $self->createTransposonFrame    ($self->{TransposonF});
    $self->createClonePCRFrame      ($self->{ClonePCRF});
    $self->createWalkFrame          ($self->{WalkF});
    $self->createOligoScreeningFrame($self->{OligoScreeningF});
    $self->createRestrictionFrame   ($self->{RestrictionF});

    $self->{PCRF}->grid(            -row => 7, -column => 1, -columnspan => 3);
    $self->{pucF}->grid(            -row => 7, -column => 1, -columnspan => 3);
    $self->{TransposonF}->grid(     -row => 7, -column => 1, -columnspan => 3);
    $self->{ClonePCRF}->grid(       -row => 7, -column => 1, -columnspan => 3);

    $self->{WalkF}->grid(           -row => 7, -column => 1, -columnspan => 3);
    $self->{OligoScreeningF}->grid( -row => 7, -column => 1, -columnspan => 3);
    $self->{RestrictionF}->grid(    -row => 7, -column => 1, -columnspan => 3);

    # whenever a frame is Mapped it should unmap itself.
    # Mapping is when the X Server actually draws something on the screen.
    # The geometry is remembered - I presume this is a low level call to the
    # X Server thus by-passing the geometry mangers when it is re-mapped later.

#    $self->{PCRF}->bind("<Map>",  
#			sub {
#			    $self->{PCRF}->UnmapWindow();
#			});
    $self->{pucF}->bind("<Map>",  
                        sub {
			    $self->{pucF}->UnmapWindow();
			});
    $self->{TransposonF}->bind("<Map>",  
	                sub {
			    $self->{TransposonF}->UnmapWindow();
			});
    $self->{ClonePCRF}->bind("<Map>",  
	                sub {
			    $self->{ClonePCRF}->UnmapWindow();
			});
    $self->{WalkF}->bind("<Map>",  
	                 sub {
			     $self->{WalkF}->UnmapWindow();
			 });
    $self->{OligoScreeningF}->bind("<Map>",  
	                 sub {
			     $self->{OligoScreeningF}->UnmapWindow();
			 });
    $self->{RestrictionF}->bind("<Map>",  
	                 sub {
			     $self->{RestrictionF}->UnmapWindow();
			 });

    # default frame is ...

    $self->{frameChoice} = 'PCR for SIL';
}


################################################################################
# depending on which radio button was picked, maps one window and unmaps the
# rest.
################################################################################

sub changeSelectionFrame {
    my ($self)               = @_;

    $self->hidePCRFrame();
    $self->hidePUCFrame();
    $self->hideWalkFrame();
    $self->hideOligoScreeningrame();
    $self->hideRestrictionFrame();
    $self->hideTransposonFrame();
    $self->hideClonePCRFrame();

    if($self->{frameChoice} eq 'Transposon') {

	$self->{TransposonF}->bind("<Map>", sub {});
	$self->{TransposonF}->MapWindow();
    }
    elsif($self->{frameChoice} eq 'PCR for SIL') {

	$self->{PCRF}->bind("<Map>", sub {});
	$self->{PCRF}->MapWindow();
    }
    elsif($self->{frameChoice} eq 'Sub Clone for SIL') {

	$self->{pucF}->bind("<Map>", sub {});
	$self->{pucF}->MapWindow();
    }
    elsif($self->{frameChoice} eq 'Clone PCR' ){

	$self->{ClonePCRF}->bind("<Map>", sub {});
	$self->{ClonePCRF}->MapWindow();
    }
    elsif($self->{frameChoice} eq 'Genome Walk' ){
	
	$self->{WalkF}->bind("<Map>", sub {});
	$self->{WalkF}->MapWindow();
    }
    elsif($self->{frameChoice} eq 'Oligo Screening') {
	
        $self->{OligoScreeningF}->bind("<Map>", sub {});
	$self->{OligoScreeningF}->MapWindow();
    }
    elsif($self->{frameChoice} eq 'Restriction') {
	
	$self->{RestrictionF}->bind("<Map>", sub {});
        $self->{RestrictionF}->MapWindow();
    }
    else {
	warn "changeSelectionFrame::ERROR: unknow frame\n";
	warn "                      frame choice equals $self->{frameChoice}\n";
    }

    if( $self->needLibrarySizes() ){
	$self->showLibrarySizeFrame();
    } else {
	$self->hideLibrarySizeFrame();
    }

    if( $self->needCloneIntoVector() ){
	$self->showCloneIntoVectorFrame();
    } else {    
	$self->hideCloneIntoVectorFrame();
    }
}

sub hidePCRFrame {
    my ($self) = @_;

    $self->{PCRF}->UnmapWindow();
    $self->{PCRF}->bind ("<Map>",  sub { $self->{PCRF}->UnmapWindow()    } );
}

sub hidePUCFrame {
    my ($self) = @_;

    $self->{pucF}->UnmapWindow();
    $self->{pucF}->bind ("<Map>",  sub { $self->{pucF}->UnmapWindow();   } );
}

sub hideWalkFrame {
    my ($self) = @_;

    $self->{WalkF}->UnmapWindow();
    $self->{WalkF}->bind ("<Map>", sub { $self->{WalkF}->UnmapWindow()   } );
}

sub hideOligoScreeningrame {
    my ($self) = @_;

    $self->{OligoScreeningF}->UnmapWindow();
    $self->{OligoScreeningF}->bind ("<Map>",
				    sub {
					$self->{OligoScreeningF}->UnmapWindow();
				   } );
}

sub hideTransposonFrame {
    my ($self) = @_;

    $self->{TransposonF}->UnmapWindow();
    $self->{TransposonF}->bind ("<Map>",
				   sub { 
				       $self->{TransposonF}->UnmapWindow();
				   } );
}

sub hideClonePCRFrame {
    my ($self) = @_;

    $self->{ClonePCRF}->UnmapWindow();
    $self->{ClonePCRF}->bind ("<Map>",
				   sub { 
				       $self->{ClonePCRF}->UnmapWindow();
				   } );
}

sub hideRestrictionFrame {
    my ($self) = @_;

    $self->{RestrictionF}->UnmapWindow();
    $self->{RestrictionF}->bind ("<Map>",
				   sub { 
				       $self->{RestrictionF}->UnmapWindow();
				   } );
}

# if the finisher wants Genome Walk (or what ever), they don't need to enter 
# library sizes - hide the frame

sub hideLibrarySizeFrame {
    my ($self) = @_;

    $self->{libSizeFrame}->bind("<Map>", sub {
	$self->{libSizeFrame}->UnmapWindow();
    });

    $self->{libSizeFrame}->UnmapWindow();
}

sub showLibrarySizeFrame {
    my ($self) = @_;

    $self->{libSizeFrame}->bind("<Map>", sub {} );
    $self->{libSizeFrame}->MapWindow();
}

# if the finisher wants Genome Walk (or what ever), they don't need to enter 
# library sizes - hide the frame

sub hideCloneIntoVectorFrame {
    my ($self) = @_;

    $self->{cloneIntoVectorFrame}->bind("<Map>", sub {
	$self->{cloneIntoVectorFrame}->UnmapWindow();
    });

    $self->{cloneIntoVectorFrame}->UnmapWindow();
}

sub showCloneIntoVectorFrame {
    my ($self) = @_;

    $self->{cloneIntoVectorFrame}->bind("<Map>", sub {} );
    $self->{cloneIntoVectorFrame}->MapWindow();
}

################################################################################
# need to store STS
################################################################################

sub createPCRFrame {
    my ($self, $pcrF) = @_;

    $pcrF->Label(-width  => 17,
		 -text   => "Est. Product Size",
		 -anchor => 'w',
		 )->grid(-row    => 2,
			 -column => 1,);

    my $t = $pcrF->Frame();

    $t->Entry(-width  => 20,
	      -textvariable => \ $self->{sizeOfPCR},
	      -bg           => 'lemonchiffon2',
	      )->grid(-row    => 1,
		      -column => 1,);

    $t->Label(-width  => 2,
	      -text   => "Kb",
	      -anchor => 'w',
	      )->grid(-row    => 1,
		      -column => 2,
		      -sticky => 'w',);

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

    $pcrF->Label(-width  => 17,
		 -text   => "Primer Names",
		 -anchor => 'w',
		 )->grid(-row    => 3,
			 -column => 1,);

    $pcrF->Label(-width  => 14,
		 -text   => "Forward",
		 )->grid(-row    => 4,
			 -column => 1,);

    $pcrF->Label(-width  => 14,
		 -text   => "Reverse",
		 )->grid(-row    => 5,
			 -column => 1,);


    # FORWARD OLIGO
    my $temp1;
    my $temp2;

    $temp1 = 
	$pcrF->Entry(-width        => 20,
		     -textvariable => \ $self->{PCRforwardPrimerName},
		     -bg           => 'LemonChiffon2',
		     )->grid(-row        => 4,
			     -column     => 2,);

    # REVERSE OLIGO
    $temp2 = 
	$pcrF->Entry(-width        => 20,
		     -textvariable => \ $self->{PCRreversePrimerName},
		     -bg           => 'LemonChiffon2',
		     )->grid(-row        => 5,
			     -column     => 2,);
	
    # KINASE
    my $kinaseLabel = 
	$pcrF->Label(-text   => 'Kinase',
                     -width  => 17,
		     -anchor => 'w',
		     )->grid(-row    => 7,
			     -column => 1,);

    my $temp4 = $pcrF->Frame();

    my $kinaseButt1 = 
	$temp4->Radiobutton(-variable => \$self->{kinase},
			    -text     => 'Yes',
			    -value    => 'Yes',
			    -width    => 3,
			    -anchor   => 'w',
			    )->grid(-row    => 6,
				    -column => 2,);

    my $kinaseButt2 = 
	$temp4->Radiobutton(-variable => \$self->{kinase},
			    -text     => 'No',
			    -value    => 'No',
			    -width    => 3,
			    -anchor   => 'w',
			    )->grid(-row    => 6,
				    -column => 3,);

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

    $self->{kinase} = 'Yes';

    $self->{balloon}->attach($kinaseButt1,
		-balloonmsg => "Default is Yes.\nRetrieve the end fragments ".
                               "near start/end of gap "
		);
    $self->{balloon}->attach($kinaseButt2,
		-balloonmsg => "Default is Yes.\nRetrieve the end fragments ".
                               "near start/end of gap "
		);

    $self->createPurifyGelFrame($pcrF);
}


################################################################################
# this small frame is in it's own sub because it used in
#    . PCR for SIL
#    . Retriction PCR
#    . Clone PCR
#
# The variable $self->{purifyGel} is used in all the frames.
################################################################################

sub createPurifyGelFrame {
    my ($self, $pgF) = @_;

    my $purifyLabel =
	$pgF->Label(-text   => 'Purify from Gel',
		    -width  => 17,
		    -anchor => 'w',
		    )->grid(-row    => 8,
			    -column => 1,);

    my $tempF = $pgF->Frame();

    my $purifyButt1 =
	$tempF->Radiobutton(-variable => \$self->{purifyGel},
			    -text     => 'Yes',
			    -value    => 'Yes',
			    -width    => 3,
			    -anchor   => 'w',
			    )->grid(-row    => 1,
				    -column => 2,);

    my $purifyButt2 =
	$tempF->Radiobutton(-variable => \$self->{purifyGel},
			    -text     => 'No',
			    -value    => 'No',
			    -width    => 3,
			    -anchor   => 'w',
			    )->grid(-row    => 1,
				    -column => 3,);

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

    $self->{purifyGel} = 'No';

    # balloons

    $self->{balloon}->attach($purifyButt1,
		-balloonmsg => "If the PCR contains more than 1 band, click ".
			       "Yes"
		);
    $self->{balloon}->attach($purifyButt2,
		-balloonmsg => "If the PCR contains more than 1 band, click ".
			       "Yes"
		);
}


################################################################################
#
################################################################################

sub createPucFrame {
    my ($self, $pucF) = @_;

#    $pucF->Label(-width  => 22,
#		 -text   => "No details needed here",
#		 -anchor => 'w',
#		 )->grid(-row    => 1,
#			 -column => 1,);

    $self->createSubCloneFrame($pucF);
}

################################################################################
# create the 2 tab frames within the Notebook (pUC & PCR).
#
# When the Transposon tab is selcted a check must be made to see if 
# 'Puirify from Gel' widgets must be disabled, hence the transposonTabSelected
# flag stored in $self.
################################################################################

sub createTransposonFrame {
    my ($self, $tF) = @_;


    $self->{nbF}            = $tF->NoteBook(-ipadx => 6, -ipady => 6);

    $self->{trabsposonPucF} =
	$self->{nbF}->add("puc",
			  -label     => "Sub Clone",
			  -anchor    => 'nw',
			  -raisecmd  => sub {
#			      $self->hidePurifyWidgets();
			      $self->{transposonTabSelected} = 'Subclone';}
			  );

    $self->{transposonPCRF} = 
	$self->{nbF}->add("pcr",
			  -label     => "PCR",
			  -anchor    => 'nw',
			  -raisecmd  => sub {
#			      $self->showPurifyWidgets();
			      $self->{transposonTabSelected} = 'PCR';},
			  );

    # PUC (Sub Clone) frame
    $self->createSubCloneFrame($self->{trabsposonPucF});


    # PCR frame
    my $f = $self->{transposonPCRF};

    $f->Label(-width  => 17,
	      -text   => "Est. Product size",
	      -anchor => 'w',
	      )->grid(-row    => 1,
		      -column => 1,);

    my $f2 = $f->Frame();

    $f2->Entry(-width        => 18,
	       -textvariable => \$self->{sizeOfTranposonPCR},
	       -bg           => 'lemonchiffon2',
	       )->grid(-row        => 1,
		       -column     => 2,);

    $f2->Label(-width  => 2,
	      -text   => "Kb",
	      -anchor => 'w',
	      )->grid(-row    => 1,
		      -column => 3,
		      -sticky => 'w',);

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

    $f->Label(-width  => 17,
		-text   => "Primer Names",
		-anchor => 'w',
		)->grid(-row    => 3,
			-column => 1,);

    $f->Label(-width  => 14,
		-text   => "Forward",
		)->grid(-row    => 4,
			-column => 1,);

    $f->Label(-width  => 14,
		-text   => "Reverse",
		)->grid(-row    => 5,
			-column => 1,);


    # FORWARD OLIGO

    my $temp1;
    my $temp2;

    $temp1 = $f->Entry(-width        => 18,
		       -bg           => 'LemonChiffon2',
		       -textvariable => \ $self->{transForwardPrimerName},
		       )->grid(-row        => 4,
			       -column     => 2,);


    # REVERSE OLIGO

    $temp2 = $f->Entry(-width        => 18,
		       -bg           => 'LemonChiffon2',
		       -textvariable => \ $self->{transReversePrimerName},
		       )->grid(-row        => 5,
			       -column     => 2,);


    # position Note Book Frame
    $self->{nbF}->grid(-row    => 1,
                       -column => 1,);
}

sub createClonePCRFrame {
    my ($self, $clonePCRF) = @_;

    # Est. Product Size
    $clonePCRF->Label(-width  => 17,
		 -text   => "Est. Product Size",
		 -anchor => 'w',
		 )->grid(-row    => 2,
			 -column => 1,);

    my $t = $clonePCRF->Frame();

    $t->Entry(-width  => 20,
	      -textvariable => \ $self->{sizeOfClonePCR},
	      -bg           => 'lemonchiffon2',
	      )->grid(-row    => 1,
		      -column => 1,);

    $t->Label(-width  => 2,
	      -text   => "Kb",
	      -anchor => 'w',
	      )->grid(-row    => 1,
		      -column => 2,
		      -sticky => 'w',);

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

    # PRIMERS
    $clonePCRF->Label(-width  => 17,
		 -text   => "Primer Names",
		 -anchor => 'w',
		 )->grid(-row    => 3,
			 -column => 1,);

    $clonePCRF->Label(-width  => 14,
		 -text   => "Forward",
		 )->grid(-row    => 4,
			 -column => 1,);

    $clonePCRF->Label(-width  => 14,
		 -text   => "Reverse",
		 )->grid(-row    => 5,
			 -column => 1,);

    # FORWARD PRIMER
    my $temp1;
    my $temp2;

    $temp1 = 
	$clonePCRF->Entry(-width        => 20,
		     -textvariable => \ $self->{ClonePCRforwardPrimerName},
		     -bg           => 'LemonChiffon2',
		     )->grid(-row        => 4,
			     -column     => 2,);

    # REVERSE PRIMER
    $temp2 = 
	$clonePCRF->Entry(-width        => 20,
		     -textvariable => \ $self->{ClonePCRreversePrimerName},
		     -bg           => 'LemonChiffon2',
		     )->grid(-row        => 5,
			     -column     => 2,);
	

    $self->createPurifyGelFrame($clonePCRF);
}

# to be DELETED me thinks.............................

#sub populateSTSData {
#    my ($self, $entry) = @_;

#    $self->{forwardParentName} = 
#	$self->{STSHash}->{$entry}->{forward}->{parent_name};

#    $self->{reverseParentName} = 
#	$self->{STSHash}->{$entry}->{reverse}->{parent_name};

#    $self->{forwardIsSense} = 
#	$self->{STSHash}->{$entry}->{forward}->{is_sense};
#    my $oligo_id = $self->{STSHash}->{$entry}->{forward}->{id_oligo};
#    $self->{forwardOligoName} = $self->{oligoHash}->{$oligo_id}->{name};

#    $oligo_id = $self->{STSHash}->{$entry}->{reverse}->{id_oligo};
#    $self->{reverseOligoName} = $self->{oligoHash}->{$oligo_id}->{name};
#}


################################################################################
# need to store the oligoprimer
################################################################################

sub createWalkFrame {

    my ($self, $frame) = @_;

    $frame->Label(-width  => 25,
		  -text   => "Primer Names or Sequences",
		  -anchor => 'w',
		  )->grid(-row        => 3,
			  -column     => 1,
			  -columnspan => 2,
			  -sticky     => 'w',);

    $frame->Label(-width  => 10,
		  -text   => "outer",
		  )->grid(-row    => 4,
			  -column => 1,);

    $frame->Label(-width  => 10,
		  -text   => "inner",
		  )->grid(-row    => 5,
			  -column => 1,);

    # FORWARD PRIMER

    my $temp1;
    my $temp2;

    $temp1 = $frame->Entry(-width        => 30,
			   -textvariable => 
			   \ $self->{walkForwardPrimerName},
			   )->grid(-row        => 4,
				   -column     => 2,);

    # REVERSE PRIMER

    $temp2 = $frame->Entry(-width        => 30,
			   -textvariable => 
			       \ $self->{walkReversePrimerName},
			   )->grid(-row        => 5,
				   -column     => 2,);
}

################################################################################
#
################################################################################

sub populateWalkData {
    my ($self, $entry) = @_;


    $self->{oligoPrimerParentName}    = 
	$self->{oligoPrimerHash}->{$entry}->{parent_name};

    $self->{oligoPrimerIsSense}       = 
	$self->{oligoPrimerHash}->{$entry}->{is_sense};

    # get stuff from Oligo Hash

    my $id_oligo = $self->{oligoPrimerHash}->{$entry}->{id_oligo};

    $self->{oligoPrimerOligoName}     =
	 $self->{oligoHash}->{$id_oligo}->{name};

    $self->{oligoPrimerOligoSequence} =
	 $self->{oligoHash}->{$id_oligo}->{sequence};

}

################################################################################
#
################################################################################

sub createOligoScreeningFrame {

    my ($self, $frame) = @_;

      # dummy label for spacing

#    $frame->Label(-width  => 17,
#		   -text   => "Est. Product Size",
#		   -anchor => 'w',
#		   )->grid(-row    => 2,
#			   -column => 1,);

#    my $f2 = $frame->Frame();

#    $f2->Entry(-width  => 17,
#	       -textvariable => \ $self->{sizeOfScrnPCR},
#	       )->grid(-row    => 1,
#		       -column => 1,);

#    $f2->Label(-width  => 2,
#	      -text   => "Kb",
#	      -anchor => 'w',
#	      )->grid(-row    => 1,
#		      -column => 2,
#		      -sticky => 'w',);

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


    $frame->Label(-width  => 17,
		-text   => "Primers",
		-anchor => 'w',
		)->grid(-row    => 3,
			-column => 1,);

    $frame->Label(-width  => 14,
		  -text   => "Forward",
		  )->grid(-row    => 4,
			  -column => 1,);

    $frame->Label(-width  => 14,
		  -text   => "Reverse",
		  )->grid(-row    => 5,
			  -column => 1,);



    # FORWARD PRIMER

    my $temp1;
    my $temp2;

    $temp1 = $frame->Entry(-width        => 20,
			   -textvariable => \ $self->{scrnForwardPrimerName},
			   -bg           => 'LemonChiffon2', 
			   )->grid(-row        => 4,
				   -column     => 2,);


    # REVERSE PRIMER - optional

    $temp2 = $frame->Entry(-width        => 20,
			   -textvariable => \ $self->{scrnReversePrimerName},
			   -bg           => 'LemonChiffon2', 
			   )->grid(-row        => 5,
				   -column     => 2,);

    # FRAG SIZE WANTED

    $frame->Label(-width  => 17,
		  -text   => "Screen for size",
		  -anchor => 'w',
		  )->grid(-row    => 6,
			  -column => 1,);

#    $frame->BrowseEntry(-width        => 20,
#			-state        => 'readonly',
#			-textvariable =>
#			    \ $self->{scrnForInsertSize},
#			-choices       => ['0.6 - 1',
#					   '1 - 1.4', 
#					   '1.4 - 2',
#					   '2 - 4',
#					   '4 - 6'],
#			-anchor       => 'w',
#			)->grid(-row        => 6,
#				-column     => 2,);

    my $f = $frame->Frame();
    $f->Label(-width  => 6,
	      -text   => 'From',
	      )->grid(-row    => 1,
		      -column => 1,);
    
    $f->Label(-width  => 6,
	      -text   => 'To',
	      )->grid(-row    => 1,
		      -column => 2);

    my $temp3 = 
	$f->Entry(-width        => 7,
		  -relief       => 'sunken',
		  -bg           => 'lemonchiffon2',
		  -textvariable => \$self->{screenForSize}->[0],
		  )->grid(-row    => 2,
			  -column => 1,
			  -sticky => 'nw');
    my $temp4 =
	$f->Entry(-width        => 7,
		  -relief       => 'sunken',
		  -bg           => 'lemonchiffon2',
		  -textvariable => \$self->{screenForSize}->[1],
		  )->grid(-row    => 2,
			  -column => 2,
			  -sticky => 'nw',
			  -padx   => 6,);

    $f->Label(-width => 3,
	      -text  => 'bp')->grid(-row    => 2,
				    -column => 3,
				    -sticky => 'nw');

    $self->{screenForSize}->[0] = 1400;
    $self->{screenForSize}->[1] = 2000;

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

    # BALLONS

    $self->{balloon}->attach($temp3,
			     -balloonmsg => "The library size to get");
    $self->{balloon}->attach($temp4,
			     -balloonmsg => "The library size to get");

    $self->createApproxGapSizeFrame($frame);
}


################################################################################
# argument 2 to this subroutine is a list of short names of BrowseEntry
# widgets to change. The drop down menu part of each widget is changed.
################################################################################

sub setOligoBrowseWidgets {

    my ($self,   $gadgetNames) = @_;
    my ($widget, $value);

    foreach (@$gadgetNames) {

	if( $_ eq 'ID') {
	    $widget = $self->{oligoIDWidget};
	    $value  = $self->{oligoID};
	}
	elsif( $_ eq 'Name' ) {
	    $widget = $self->{oligoNameWidget};
	    $value  = $self->{oligoName};
	}
	elsif( $_ eq 'Sequence' ){
	    $widget = $self->{oligoSequenceWidget};
	    $value  = $self->{oligoSequence};
	}
	else {
	    LemurUtils->showError($self->{mw},
				  "ERROR! setOligoBrowseGadgets unknown ".
				  "widget: $_");
	    last;
	}

	$widget->delete('0', 'end');
	$widget->insert('end', $value);
    }
}


################################################################################
# store restriction enzyme
#
# see getRestrictionDataRef() - it will return the ref to the data
# structure that the user has selected 
################################################################################

sub createRestrictionFrame {

    my ($self, $frame) = @_;


    $frame->Label(-text   => 'Fragment from',
		  -width  => 14,
		  -anchor => 'w',
		  )->grid(-row    => 1,
			  -column => 1,);

    $self->{nbF2}             = $frame->NoteBook();

    $self->{restrictSubCloneWidget} = 
	$self->{nbF2}->add("puc",
			   -label  => "Sub Clone",
			   -raisecmd => sub {
#			       $self->hidePurifyWidgets();
			       $self->{restrictTabSelected} = 'SubClone';
			   },
			   -anchor => 'nw',);

    $self->{restrictPCRWidget}      = 
	$self->{nbF2}->add("pcr",
			   -label  => "PCR",
			   -raisecmd => sub {
#			       $self->showPurifyWidgets();
			       $self->{restrictTabSelected} = 'PCR';
			   },
			   -anchor => 'nw',);

    $self->{restrictCloneWidget}    =
	$self->{nbF2}->add("clone",
			   -label  => "Clone",
			   -raisecmd => sub {
#			       $self->hidePurifyWidgets();
			       $self->{restrictTabSelected} = 'Clone';
			   },
			   -anchor => 'nw',);

    # CREATE SUB CLONE (pUC) FRAME

    $self->createSubCloneFrame($self->{restrictSubCloneWidget});

    my $subFrame = $self->{restrictSubCloneWidget}->Frame();
    $self->createBasicRestrictionFrame($subFrame,
                                       \$self->{restrictSubClone},
				       1,);
    $subFrame->grid(-row => 20, -column => 1, -columnspan => 3);

    # CREATE CLONE

    $self->createBasicRestrictionFrame($self->{restrictCloneWidget},
                                       \$self->{restrictClone},
				       1,);

    # CREATE PCR

    $self->createBasicRestrictionFrame($self->{restrictPCRWidget},
                                       \$self->{restrictPCR},);

    $self->{restrictPCRWidget}->Label(-width  => 17,
				      -text   => "Est. Product Size",
				      -anchor => 'w',
				      )->grid(-row    => 7,
					      -column => 1,);

    my $f3 = $self->{restrictPCRWidget}->Frame();

    $f3->Entry(-width        => 17,
	       -textvariable => \ $self->{sizeOfrestrictPCR},
	       -bg           => 'LemonChiffon2',
	       )->grid(-row    => 1,
		       -column => 1,);

    $f3->Label(-width  => 2,
	       -text   => "Kb",
	       -anchor => 'w',
	       )->grid(-row    => 1,
		       -column => 2,
		       -sticky => 'w',);

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

    $self->{restrictPCRWidget}->Label(-width  => 17,
				      -text   => "Primer Names",
				      -anchor => 'w',
				      )->grid(-row    => 8,
					      -column => 1,);

    $self->{restrictPCRWidget}->Label(-width  => 14,
				      -text   => "Forward",
				      )->grid(-row    => 9,
					      -column => 1,);

    $self->{restrictPCRWidget}->Label(-width  => 14,
				      -text   => "Reverse",
				      )->grid(-row    => 10,
					      -column => 1,);

    # FORWARD PRIMER

    my $temp1;
    my $temp2;

    $temp1 =
	$self->{restrictPCRWidget}->Entry(-width        => 18,
					  -textvariable => 
					   \ $self->{restrictForwardPrimerName},
					  -bg           => 'LemonChiffon2',
					  )->grid(-row        => 9,
						  -column     => 2,);



    # REVERSE PRIMER

    $temp2 =
	$self->{restrictPCRWidget}->Entry(-width        => 18,
					  -textvariable => 
                                           \ $self->{restrictReversePrimerName},
					  -bg           => 'LemonChiffon2',
					  )->grid(-row        => 10,
						  -column     => 2,);

    # 3 frames for the Notebook have been created, just pack them now

    $self->{nbF2}->grid(-row => 1, -column => 1,);;
}

################################################################################
# for the above subroutine, create 3 main sets of widgets;
#    . Consensus file
#    . Gap co-ordinate
#    . Suggested enzyme
#
# Arguments:
#    1 The frame to create widgets on
#    2 The variable to attach -textvariable stuff to.
#
# It gets called for each tab on the Restriction Notebook.
################################################################################

sub createBasicRestrictionFrame {

    my ($self, $frame, $data, $isPCRFrame) = @_;


    $frame->Label(-width  => 17,
		  -text   => "Consensus file",
		  -anchor => 'w',
		  )->grid(-row    => 2,
			  -column => 1,);

    my $fileWidget3 = 
        $frame->Entry(-width  => 20,
		      -textvariable => \ $$data->{ConsensusFile},
		      -bg           => 'LemonChiffon2',
		      )->grid(-row    => 2,
			      -column => 2,);

    my $check = sub { 
	$self->isGoodConsensusFile($$data->{ConsensusFile});
    };

    $fileWidget3->bind('<Return>',       $check);
    $fileWidget3->bind('<KeyPress-Tab>', $check);

    $$data->{consensusFileWidget} = $fileWidget3;

    my $msg;
    unless( $isPCRFrame ){
	$msg = ". Please include vector sequence.";
    }

    $self->{balloon}->attach($fileWidget3,
			     -balloonmsg => "Consensus file in 'FAST-A' ".
			                    "format".$msg);

    $frame->Label(-width  => 17,
		  -text   => "Gap co-ordinate",
		  -anchor => 'w',
		  )->grid(-row    => 3,
			  -column => 1,);

    my $g4 = $frame->Frame();
    my $gapCoord = 
        $g4->Entry(-width  => 17,
		   -textvariable => \$$data->{GapCoord},
		   -bg           => 'LemonChiffon2',
		   )->grid(-row    => 1,
			   -column => 1,);

    $self->{balloon}->attach($gapCoord,
		      -balloonmsg => "position in consensus file where gap is");

    $g4->Label(-width => 2,
	       -text  => 'bp',
               )->grid(-row    => 1,
		       -column => 2,);

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

    $frame->Label(-width       => 17,
		  -text        => "Suggested enzyme",
		  -anchor      => 'w',
		  )->grid(-row    => 5,
			  -column => 1,);

    my $se = 
	$frame->BrowseEntry(-width    => 18,
			    -variable => \$$data->{EnzymeUsed},
			    -state    => 'readonly',
			    -choices  => [ sort keys %{$self->{enzymeHash}} ],
			    )->grid(-row        => 5,
				    -column     => 2,);

    $self->{balloon}->attach($se,
			     -balloonmsg => "Optional");
}

################################################################################
# If the finisher has requested a Restriction to be done, they have a selection
# of 3 tabs to choose from. This sub returns a reference to the one they
# selected.
################################################################################

sub getRestrictionDataRef {

    my ($self) = @_;
    my $data;

    if( $self->{restrictTabSelected} eq 'SubClone' ) {
	$data = $self->{restrictSubClone};
    }

    elsif( $self->{restrictTabSelected} eq 'PCR' ) {
	$data = $self->{restrictPCR};
    }

    elsif( $self->{restrictTabSelected} eq 'Clone') {
        $data = $self->{restrictClone};
    }

    else {
	LemurUtils->showError($self->{mw},
			      "Unknown tab select for Restriction: ".
			      "'$self->{restrictTabSelected}'");
	return undef;
    }

    return $data;
}

################################################################################
# bound to Keypress-Return on BrowseEntru widget for selecting an Oligo ID.
# Gets all ID_OLIGO that contain what the user has typed in.
################################################################################

sub searchForOligoID {

    my ($self, $idWidget) = @_;

    my $arrayOfArrays;
    my $searchValue = $self->{oligoID};
    my ($dbh)       = $self->{dbi};

    LemurUtils->setWait([$self->{mw}]);

    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;

	$arrayOfArrays = $dbh->fetch_all("
            select ID_OLIGO, OLIGONAME, OLIGO_SEQUENCE
            from   OLIGO
            where  ID_OLIGO like '%$searchValue%'");
    };

    if($@) {
	LemurUtils->showError($self->{mw}, "$@");
    }


    LemurUtils->unSetWait([$self->{mw}]);


    $idWidget->delete('0', 'end');

    foreach my $array ( @$arrayOfArrays ) {
	$idWidget->insert('end', (@$array)[0]);
    }

    # display the drop down window. 
    # Note: BtnDown is not a 'public' method. MAY NOT WORK in future
    # versions but v. nice to have.

    $idWidget->BtnDown if ($idWidget->{"popped"});
    $idWidget->BtnDown;    
}


################################################################################
# bound to Keypress-Return on BrowseEntru widget for selecting an Oligo Name.
# Gets all ID_OLIGO that contain what the user has typed in.
################################################################################

sub searchForPrimerName {

    my ($self, $idWidget, $searchValueRef) = @_;

    my $arrayOfArrays;
    my $searchValue = $$searchValueRef;
    my ($dbh)       = $self->{dbi};


    if( $self->{cloneName} eq '' ){
	LemurUtils->showError($self->{mw},
			      "Please enter the clone name first.");
	return;
    }
    

    LemurUtils->setWait([$self->{mw}]);

    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;

	# restrict to primers available to the clone (clone belongs to 1 or
	# more projects)

	$arrayOfArrays = $dbh->fetch_all("
            select PRIMERNAME
            from   PRIMER, CLONE_PROJECT
            where  CLONE_PROJECT.CLONENAME   = '$self->{cloneName}'
            and    CLONE_PROJECT.PROJECTNAME = PRIMER.PROJECTNAME
            and    PRIMERNAME like '%$searchValue%'");
    };

    if($@) {
	LemurUtils->showError($self->{mw}, "$@");
    }

    LemurUtils->unSetWait([$self->{mw}]);


    $idWidget->delete('0', 'end');

    foreach my $array ( @$arrayOfArrays ) {
	$idWidget->insert('end', $array->[0]);
    }

    # display the drop down window. 
    # Note: BtnDown is not a 'public' method. MAY NOT WORK in future
    # versions but v. nice to have.

    $idWidget->BtnDown if ($idWidget->{"popped"});
    $idWidget->BtnDown;    
}


################################################################################
# bound to Keypress-Return on BrowseEntru widget for selecting an Oligo 
# Sequence.
# Gets all ID_SEQUENCE's that contain what the user has typed in.
################################################################################

sub searchForOligoSequence {

    my ($self, $idWidget) = @_;

    my $arrayOfArrays;
    my $searchValue = $self->{oligoSequence};
    my ($dbh)       = $self->{dbi};

    LemurUtils->setWait([$self->{mw}]);

    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;

	$arrayOfArrays = $dbh->fetch_all("
            select ID_OLIGO, OLIGONAME, OLIGO_SEQUENCE
            from   OLIGO
            where  OLIGO_SEQUENCE like '%$searchValue%'");
    };

    if($@) {
	LemurUtils->showError($self->{mw}, "$@");
	LemurUtils->unSetWait([$self->{mw}]);
	return;
    }

    LemurUtils->unSetWait([$self->{mw}]);

    $idWidget->delete('0', 'end');

    foreach my $array ( @$arrayOfArrays ) {
	$idWidget->insert('end', "@{$array}[2] (@{$array}[1])");
    }

    # display the drop down window. 
    # Note: BtnDown is not a 'public' method. MAY NOT WORK in future
    # versions but v. nice to have.

    $idWidget->BtnDown if ($idWidget->{"popped"});
    $idWidget->BtnDown;    
}

################################################################################
# gets enzymes from Consensus file, populates BrowseEntry widget

# NOW OUT OF DATE!

# REPLACED BY getEnzymes()

################################################################################

sub getSuggestedEnzymes {
    my ($self, $filePath) = @_;
    my $foundStart        = 0;
    my @enzymes;

#    return unless $self->isGoodConsensusFile($filePath);

    open FILEPATH, $filePath;

    while(<FILEPATH>) {

	if( / \.\./ ) {  # this marks the start in Mike Q's REBASE file
	    $foundStart = 1;
	    next;
	}

	if( $foundStart ) {
	    /^(\w+) /;
	    push(@enzymes, $1) if $1;
	}
    }

    if( scalar(@enzymes) == 0 ) {
	LemurUtils->showError($self->{mw}, "Got zero enzymes from $filePath");
    }

    $self->{suggestedEnzymes} = \@enzymes;
}


################################################################################
# check input is good. If so, create Job Request.
#
# RETURNS: 1 if did create record
#          0 if bad things happened
################################################################################

sub addPressed {
    my ($self)    = @_;
    my $jobNumber;
    my ($dbh)     = $self->{dbi};

    LemurUtils->setWait([$self->{mw}]);

    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;

	if( $self->isValidUserInput($dbh) ) {
	    $jobNumber = $self->createRecords($dbh);
	}

	$dbh->commit;
    };

    if( $@ ) {
        my $error = $@;
	$dbh->rollback;  # rollback "just-in-case"
	warn "done rollback\n" if $debug;
        
        Mail::sendMail(-to      => $bug_mail,
                       -subject => "Error entering a SIL request",
                       -message => $error);

	LemurUtils->showError($self->{mw},"$error");
	LemurUtils->unSetWait([$self->{mw}]);
	return 0;
    }

    LemurUtils->unSetWait([$self->{mw}]);

    # show the Job number entered if one created.

    if( $jobNumber ) {
	my $message = "Job submitted. The Job number is;\n\n       $jobNumber";

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

	print "\nJob submitted for clone $self->{cloneName}. ".
	      "The Job number is:  $jobNumber\n";

	return 1;
    }
    else {
	return 0;
    }
}

################################################################################
# returns 1 if user input is valid, 0 otherwise.
# Everytime some bad bit of input is discovered, a message is appended to 
# $mustEnter. It is displayed at the end of the routine if $dataOK is false.
################################################################################

sub isValidUserInput {
    my ($self, $dbh) = @_;
    my $dataOK       = 1;     # boolean. If ever set to 0, some data is invalid.
    my $mustEnter    = "You must enter ";

warn "\n\n***************************\n" if $debug;
warn "*** VALIDATE USER INPUT ***\n" if $debug;

    # SUBMITTER

    if( $self->{submitter} eq '' ) {
	$mustEnter .= "your name (Submitter), ";
	$dataOK     = 0;
    }

    # CLONE

    if( $self->{cloneName} eq '' ) {
	$mustEnter .= "a clone name, ";
	$dataOK     = 0;
    }
    else {
	unless( $self->isValidCloneName($self->{cloneName}, $dbh) ) {
	    $mustEnter .= "a valid clone name, ";
	    $dataOK = 0;
	}
    }

    # SUB CLONE - check plate number, row and col, then isInVector

    my ($rowOK, $colOK) = (1, 1);

    if( $self->needSubcloneInfo() ) {
	
	if( $self->{plateName} eq ''  ) {
	    $mustEnter .= "a plate name, ";
	    $dataOK     = 0;
	    $rowOK      = 0;
	    $colOK      = 0;
	}
        else {
            # See if plate name is in Oracle. Could be old plate in Equus
            # so just ask if it it correct
            my $sth = $self->{sth_is_valid_plate_name};
            $sth->execute($self->{plateName});
            my $count = ($sth->fetchrow_array())[0];

            if( $count == 0 ){
                my $m   = "Warning: Could not find plate ".
                          "'$self->{plateName}' in Platetrack. Is the name".
                          " correct?";
                my $ans = LemurUtils->yesNo($self->{mw}, $m);
                return 0 if $ans eq 'No';
            }
        }

	if( $self->{row} eq '') {
	    $mustEnter .= "a row, ";
	    $dataOK     = 0;
	    $rowOK      = 0;
	}
	else {
	    $self->{row} =~ s/^\s+//;
	    $self->{row} =~ s/\s+$//;

	    unless( $self->{row} =~ /^\w+/ ) {
		$mustEnter .= "a row with letters only, ";
		$dataOK     = 0;
		$rowOK      = 0;
	    }
	}

	if ($self->{col} eq '') {
	    $mustEnter .= "a column, ";
	    $dataOK     = 0;
	    $colOK      = 0;
	}
	else {
	    $self->{col} =~ s/^\s+//;
	    $self->{col} =~ s/\s+$//;

	    unless( $self->{col} =~ /^\d+/ ) {
		$mustEnter .= "a column with digits only, ";
		$dataOK     = 0;
		$colOK      = 0;
	    }
	}

	if( $self->{plateFormat} eq '' ) {
	    $mustEnter .= "the plate format, ";
	    $dataOK     = 0;
	}
	else {
	    if( $rowOK && $colOK ) {
		unless( $self->isValidColRowMap($self->{col},
						$self->{row},
						$self->{plateFormat},
						$dbh         )) {
		    $mustEnter .= "a valid row and/or col for the ".
			          "plate format, ";
		    $dataOK     = 0;
		}
	    }
	}

	if( $self->{isInVector} eq '' ) {
	    $mustEnter .= "the vector the subclone is in, ";
	    $dataOK     = 0;
	}
    }

    # APPROX GAP SIZE

    if( $self->needApproxGapSize() ) {
	if( $self->{GapSize} eq '' ) {
	    $dataOK     = 0;
	    $mustEnter .= 'the approx gap size, ';
	}
	else {
	    $self->{GapSize} =~ s/^\s+//;
	    $self->{GapSize} =~ s/\s+$//;

	    unless( $self->isValidNumber($self->{GapSize}) ) {
		$dataOK     = 0;
		$mustEnter .= 'a natural number for the approx Gap size, ';
	    }
	    else {
		# could carry on and check if number is not in 999.99 format
		# specified in Oracle..... If change Oracle, have to change this
		# code too. Mmmm.	    

                if( $self->{GapSize} >= 1000 ){
                    $dataOK     = 0;
                    $mustEnter .= 'a number in Kb for the approx Gap size, ';
                }
	    }
	}
    }

    # FRAGMENTS, check for a From AND a To value, check they are numbers.

    if( $self->needLibrarySizes() ){
	my $arrayRef = $self->{BandsArray};
	my $from;
	my $to;
	my $fragSizeEntered;

	for my $x (0..$MAIN::NUM_BANDS) {

	    if( ($arrayRef->[$x][0] && ! $arrayRef->[$x][1])  ||
		($arrayRef->[$x][1] && ! $arrayRef->[$x][0])    ) {

		LemurUtils->showError($self->{mw},
				      "You have only half entered a .".
				      "Fragment Size ".($x=1));
		$fragSizeEntered = 1;
		last;
	    }

	    if( $arrayRef->[$x][0] && 
		$arrayRef->[$x][1]       ) {

		$fragSizeEntered = 1;

		$from = $arrayRef->[$x][0];
		$to   = $arrayRef->[$x][1];

		unless( $self->isValidNumber($from)  ) {
		    $dataOK     = 0;
		    $mustEnter .= "a valid number for Fragment ".
			          ($x+1)." From, ";
		}

		unless( $self->isValidNumber($to)  ) {
		    $dataOK     = 0;
		    $mustEnter .= "a valid number for Fragment ".($x+1)." To, ";
		}

		if( $dataOK ) {
		    if( $from >= $to ) {
			$dataOK     = 0;
			$mustEnter .= "a valid size for fragment ".($x+1);
		    }
		}
	    }
	}


	unless( $fragSizeEntered ) {
	    $dataOK     = 0;
	    $mustEnter .= "at least 1 fragment size, ";
	}
    }

    # COMMENT - a "'" char is in the string will mess up Oracle

    if( $self->{comment} =~ /\'/ ) {
	$dataOK     = 0;
	$mustEnter .= "a comment with no \"'\" character(s), ";
    }

    if( length($self->{comment}) > 239 ){
        my $length  = length($self->{comment});
        $dataOK     = 0;
        $mustEnter .= "a comment that has less than 240 letters ".
                      "(you have $length letters), ";
    }

    # NOW call the correct validation subroutine depending on what
    # they want the SubCloners to do.

    $_ = $self->{frameChoice};
    
    SWITCH: {
	/^PCR/  && 
	    do { $self->validatePCR(\$dataOK,
				    \$mustEnter,
				    $dbh);
		 last SWITCH; };

	/^subClone/ &&
	    do { last SWITCH; };

	/^Transposon/ &&
	    do { $self->validateTransposon(\$dataOK,
					   \$mustEnter,
					   $dbh);
		 last SWITCH; };
	
	/^Clone PCR/ &&
	    do { $self->validateClonePCR(\$dataOK,
					 \$mustEnter,
					 $dbh);
		 last SWITCH; };

	/^Genome Walk/ &&
	    do { $self->validateGWalk(\$dataOK,
				      \$mustEnter,
				      $dbh);
		 last SWITCH; };

	/^Oligo Screening/ &&
	    do { $self->validateOligoScreening(\$dataOK,
					       \$mustEnter,
					       $dbh);
		 last SWITCH; };

	/^Restriction/ &&
	    do { $self->validateRestriction(\$dataOK,
					    \$mustEnter,
					    $dbh);
		 last SWITCH; };
    }

    # FINALLY show an error message if there was a problem and return

    unless( $dataOK ) {
	$mustEnter =~ s/, $//; # remove last ', '

	LemurUtils->showError($self->{mw},$mustEnter);
	return 0;
    }
    else {
	return 1;
    }
}

#
#
#

sub needSubcloneInfo {
    my ($self) = @_;

    if(   $self->{frameChoice} eq 'Sub Clone for SIL'

       || (   $self->{frameChoice}           eq 'Transposon'  
	   && $self->{transposonTabSelected} eq 'Subclone')

       || (   $self->{frameChoice}         eq 'Restriction' 
	   && $self->{restrictTabSelected} eq 'SubClone')) {

	return 1;
    }
    else {
	return 0;
    }
}

sub needApproxGapSize {
    my ($self) = @_;

    if( ! (   $self->{frameChoice} eq 'PCR for SIL'

	   || $self->{frameChoice} eq 'Genome Walk'

	   || $self->{frameChoice} eq 'Clone PCR'

	   || (   $self->{frameChoice}           eq 'Transposon'
	       && $self->{transposonTabSelected} eq 'PCR')

           || (   $self->{frameChoice}         eq 'Restriction' 
	       && $self->{restrictTabSelected} eq 'PCR')

           || (   $self->{frameChoice}         eq 'Restriction'
	       && $self->{restrictTabSelected} eq 'Clone'))) {

	return 1;
    }

    return 0;
}

sub needLibrarySizes {
    my ($self) = @_;

    if(   $self->{frameChoice} eq 'Transposon'
       || $self->{frameChoice} eq 'Clone PCR'
       || $self->{frameChoice} eq 'Genome Walk'
       || $self->{frameChoice} eq 'Oligo Screening'){
	return 0; # don't specify library size
    }

    return 1;
}

sub needCloneIntoVector {
    my ($self) = @_;

    if(   $self->{frameChoice} eq 'Transposon'
       || $self->{frameChoice} eq 'Genome Walk'
       || $self->{frameChoice} eq 'Oligo Screening'){
	return 0;
    }

    return 1;
}

################################################################################
# If $filePath is wrong it tells the user, unless it is blank in which case it
# just returns 0.
#
# Tries to get the path from repository. If the project is not on disk it asks
# the user to restore it. If project not in repository it does not attempt to
# check it.
#
# It does not look inside the file to check it really is a consensus file. I
# have been told it can have many different formats. A Nice To Have.
################################################################################

sub isGoodConsensusFile {
    my ($self, $file, $silent) = @_;

    unless( $file ) {
	return 0;
    }

    unless( $self->{cloneName} ){
	LemurUtils->showError($self->{mw},
			      "Please enter a clone name so the consensus ".
			      "file can be validated");
	return 0;
    }

    # get ref to set of widgets (subclone, PCR or clone).
    my $data = $self->getRestrictionDataRef();

    LemurUtils->setWait([$self->{mw}, $data->{consensusFileWidget}]);

    my $repos = new OORepository;

# have to be in the HSG group to create 

#$repos->new_project($repos->return_repos_id("General"), 'wibble2');
#return 1;


    my $path  = $repos->get_online_path_from_project($self->{cloneName});
    my $filePath;

    if( defined $path ){
	$filePath = $path."/".$file;
    }
    else {
	$filePath = '';
    }

warn "project path = $path\n" if $debug;

    if( $repos->is_project_nearlined or $repos->is_project_archived ){
	$self->showInfo("Project $self->{cloneName} is nearlined/archived. ".
			"Please restore");
    }

    $repos->DESTROY();

    LemurUtils->unSetWait([$self->{mw}, $data->{consensusFileWidget}]);

    if( $filePath ){
	unless( -e $filePath ){
	    unless( $silent ){
		LemurUtils->showError($self->{mw},
				      "Consensus file '$filePath' does not ".
				      "exist");
	    }
	    
	    return 0;
	}
    }

    return 1;
}

################################################################################
# Returns true if $cloneName exists in a CLONE record
################################################################################

sub isValidCloneName {
    my ($self, $cloneName, $dbh) = @_;

    if( $cloneName eq '' ) {
	return( 0 );
    }

    my $stmt = "
        select count(*) 
        from   CLONE 
        where  CLONENAME = '$cloneName'";

    return ($dbh->fetch_scalar($stmt) == 1);
}

#

sub isValidColRowMap {
    my ($self, $col, $row, $plateFormat, $dbh) = @_;

    if( $col eq '' || $row eq '') {
	return 0;
    }

    $self->{row} = lc $self->{row};

    my $id_plateFormat = $self->{plateFormats}->{$plateFormat};

    my $stmt = "
        select count(*)
        from   ROWCOL_MAP
	where  FORMAT = $id_plateFormat
        and    MAPROW = '$self->{row}'
        and    MAPCOL = $self->{col}";

    return ($dbh->fetch_scalar($stmt) > 0);
}


################################################################################
#
################################################################################

sub validatePCR {
    my ($self,
	$refToDataOK,
	$refToMustEnter,
	$dbh            ) = @_;

    warn "\n*** VALIDATE PCR ***\n" if $debug;

    # EST. PRODUCT SIZE

    if( $self->{sizeOfPCR} eq '' ) {
	$$refToDataOK     = 0;
	$$refToMustEnter .= 'the estimated product size, ';
    }
    else {
	unless( $self->isValidNumber($self->{sizeOfPCR})  ) {
	    $$refToDataOK     = 0;
	    $$refToMustEnter .= 'a valid number for Est. Prod size, ';
	}
        elsif( $self->{sizeOfPCR} >= 1000 ){
            $$refToDataOK     = 0;
	    $$refToMustEnter .= 'a number in Kb for Est. Prod size, ';
        }
    }

    # PRIMERS

    if( $self->{PCRforwardPrimerName} eq '' ) {
	$$refToDataOK     = 0;
	$$refToMustEnter .= 'a forward primer, ';
    }
#    else {
#	unless( $self->isValidPrimer($self->{PCRforwardPrimerName}, $dbh)  ) {
#	    $$refToDataOK     = 0;
#	    $$refToMustEnter .= 'valid forward primer, ';
#	}
#    }

    if( $self->{PCRreversePrimerName} eq '' ) {
	$$refToDataOK     = 0;
	$$refToMustEnter .= 'a reverse primer, ';

    }
#    else {
#	unless( $self->isValidPrimer($self->{PCRreversePrimerName}, $dbh)  ) {
#	    $$refToDataOK     = 0;
#	    $$refToMustEnter .= 'valid reverse primer, ';
#	}
#    }

}


################################################################################
# only need to check if a PCR needs to be done
################################################################################

sub validateTransposon {
    my ($self,
	$refToDataOK,
	$refToMustEnter,
	$dbh            ) = @_;

warn "\n*** VALIDATE TRANSPOSON ***\n" if $debug;

    unless( $self->{transposonTabSelected} eq 'PCR' ) {
	return;
    }

    # EST. PRODUCT SIZE

    if( $self->{sizeOfTranposonPCR} eq '' ) {
	$$refToDataOK     = 0;
	$$refToMustEnter .= 'the estimated product size, ';
    }
    else {
	unless( $self->isValidNumber($self->{sizeOfTranposonPCR}) ) {
	    $$refToDataOK     = 0;
	    $$refToMustEnter .= 'a valid number for Est. Prod size, ';
	}
    }

    # PRIMERS

    if( $self->{transForwardPrimerName} eq '' ) {
	$$refToDataOK     = 0;
	$$refToMustEnter .= 'a forward primer, ';
    }

    if( $self->{transReversePrimerName} eq '' ) {
	$$refToDataOK     = 0;
	$$refToMustEnter .= 'a reverse primer, ';
    }
}

sub validateClonePCR {
    my ($self,
	$refToDataOK,
	$refToMustEnter,
	$dbh            ) = @_;

    warn "\n*** VALIDATE CLONE PCR ***\n"          if $debug;
    warn "   $self->{sizeOfClonePCR}\n"            if $debug;
    warn "   $self->{ClonePCRforwardPrimerName}\n" if $debug;
    warn "   $self->{ClonePCRreversePrimerName}\n" if $debug;

    # EST. PRODUCT SIZE
    if( $self->{sizeOfClonePCR} eq '' ) {
	$$refToDataOK     = 0;
	$$refToMustEnter .= 'the estimated product size, ';
    }
    else {
	unless( $self->isValidNumber($self->{sizeOfClonePCR})  ) {
	    $$refToDataOK     = 0;
	    $$refToMustEnter .= 'a valid number for Est. Prod size, ';
	}
    }

    # PRIMERS
    if( $self->{ClonePCRforwardPrimerName} eq '' ) {
	$$refToDataOK     = 0;
	$$refToMustEnter .= 'a forward primer, ';
    }

    if( $self->{ClonePCRreversePrimerName} eq '' ) {
	$$refToDataOK     = 0;
	$$refToMustEnter .= 'a reverse primer, ';

    }
}

################################################################################
#
################################################################################

sub validateGWalk {

    my ($self,
	$refToDataOK,
	$refToMustEnter,
	$dbh            ) = @_;

warn "\n*** VALIDATE Genome WALK ***\n" if $debug;

    # PRIMERS

    if( $self->{walkForwardPrimerName} eq '' ) {
	$$refToDataOK     = 0;
	$$refToMustEnter .= 'a forward primer, ';
    }
#    else {
#	unless( $self->isValidPrimer($self->{walkForwardPrimerName}, $dbh)  ) {
#	    $$refToDataOK     = 0;
#	    $$refToMustEnter .= 'valid forward primer, ';
#	}
#    }

    if( $self->{walkReversePrimerName} eq '' ) {
	$$refToDataOK     = 0;
	$$refToMustEnter .= 'a reverse primer, ';
    }
#    else {
#	unless( $self->isValidPrimer($self->{walkReversePrimerName}, $dbh)  ) {
#	    $$refToDataOK     = 0;
#	    $$refToMustEnter .= 'valid reverse primer, ';
#	}
#    }
    
}

################################################################################
#
################################################################################

sub validateOligoScreening {

    my ($self,
	$refToDataOK,
	$refToMustEnter,
	$dbh            ) = @_;
    my $pcrCount          = 0;

warn "\n*** VALIDATE OLIGO SCREAMING ***\n" if $debug;


    # FORWARD PRIMER

    if( $self->{scrnForwardPrimerName} eq '' ) {
        $$refToDataOK     = 0;
        $$refToMustEnter .= 'a forward primer, ';
    }
#    else {
#        unless( $self->isValidPrimer($self->{scrnForwardPrimerName}, $dbh)  ) {
#            $$refToDataOK     = 0;
#            $$refToMustEnter .= 'a valid forward primer, ';
#        }
#    }

    # REVERSE PRIMER - optional

    if( $self->{scrnReversePrimerName} eq '' ) {
	$$refToDataOK     = 0;
	$$refToMustEnter .= 'a reverse primer, ';
    }
#    else {
#        unless( $self->isValidPrimer($self->{scrnReversePrimerName}, $dbh)  ) {
#            $$refToDataOK     = 0;
#            $$refToMustEnter .= 'a valid reverse primer, ';
#        }
#    }

    # SCREEN FOR SIZE

    if( $self->{screenForSize}->[0] eq '' ){
	$$refToDataOK     = 0;
	$$refToMustEnter .= "a number for 'From' screen size, ";	
    }
    else {
	unless( $self->isValidNumber($self->{screenForSize}->[0]) ){
	    $$refToDataOK     = 0;
	    $$refToMustEnter .= "a valid number for 'From' screen size, ";
	}
	elsif( $self->isValidNumber($self->{screenForSize}->[0] =~ /\./) ){
	    $$refToDataOK     = 0;
	    $$refToMustEnter .= "a whole number for 'From' screen size, ";
	}
    }

    if( $self->{screenForSize}->[1] eq '' ){
	$$refToDataOK     = 0;
	$$refToMustEnter .= "a number for 'To' screen size, ";	
    }
    else {
	unless( $self->isValidNumber($self->{screenForSize}->[1]) ){
	    $$refToDataOK     = 0;
	    $$refToMustEnter .= "a valid number for 'To' screen size, ";
	}
	elsif( $self->isValidNumber($self->{screenForSize}->[1] =~ /\./) ){
	    $$refToDataOK     = 0;
	    $$refToMustEnter .= "a whole number for 'To' screen size, ";
	}
    }
}

################################################################################
# The common inputs for a restriction are;
#
#    . Consensus file
#    . Gap co-ord
#    . Approx Gap size
#    . Suggested Enzyme
#
# then branch off if it is a PCR 'cos that needs extra info (Est. Size + 
# Primers)
################################################################################

sub validateRestriction {

    my ($self,
	$refToDataOK,
	$refToMustEnter,
	$dbh            ) = @_;

    my $data = $self->getRestrictionDataRef();

    # CONSENSUS FILE

    if( $data->{ConsensusFile} eq '' ) {
	$$refToDataOK     = 0;
	$$refToMustEnter .= 'a consensus file, ';
    }
    else {
	unless( $self->isGoodConsensusFile($data->{ConsensusFile}, 1) ) {
	    $$refToDataOK     = 0;
	    $$refToMustEnter .= 'a valid consensus file, ';
	}
    }

    # GAP COORD

    if( $data->{GapCoord} eq '' ) {
	$$refToDataOK     = 0;
	$$refToMustEnter .= 'the gap co-ord, ';
    }
    else {
	$data->{GapCoord} =~ s/^\s+//;
	$data->{GapCoord} =~ s/\s+$//;

	unless( $data->{GapCoord} =~ /^\d+$/ ) {
	    $$refToDataOK     = 0;
	    $$refToMustEnter .= 'an natural number for Gap co-ord, ';
	}
    }

    # SUGGESTED ENZYME - optional field

#    if( $data->{EnzymeUsed} eq '' ) {
#	$$refToDataOK     = 0;
#	$$refToMustEnter .= 'the suggested enzyme, ';
#    }

    # CHECK IF PCR

    if ( $self->{restrictTabSelected} eq 'PCR' ) {
	$self->validatePCRRestriction($refToDataOK, $refToMustEnter, $dbh);
    }
}

################################################################################
# A PCR restriction has 3 extras over a 'Sub Clone' or 'Clone' restriction;
#    . Est Product Size
#    . Forward Primer
#    . Reverse Primer.
################################################################################

sub validatePCRRestriction {

    my ($self,
	$refToDataOK,
	$refToMustEnter,
	$dbh            ) = @_;

    # EST PRODUCT SIZE

    if( $self->{sizeOfrestrictPCR} eq '') {
	$$refToDataOK     = 0;
	$$refToMustEnter .= 'Est. product size, ';
    }
    else {
	unless( $self->isValidNumber( $self->{sizeOfrestrictPCR} ) ){
	    $$refToDataOK     = 0;
	    $$refToMustEnter .= 'a number for Est. product size, ';
	}
    }

    # FORWARD PRIMER

    if( $self->{restrictForwardPrimerName} eq '' ) {
	$$refToDataOK     = 0;
	$$refToMustEnter .= 'a forward primer, ';
    }
#    else {
#	unless( $self->isValidPrimer($self->{restrictForwardPrimerName},
#				     $dbh)  ) {
#	    $$refToDataOK     = 0;
#	    $$refToMustEnter .= 'valid forward primer, ';
#	}
#    }

    # REVERSE PRIMER

    if( $self->{restrictReversePrimerName} eq '' ) {
	$$refToDataOK     = 0;
	$$refToMustEnter .= 'a reverse primer, ';
    }
#    else {
#	unless( $self->isValidPrimer($self->{restrictReversePrimerName},
#				     $dbh)  ) {
#	    $$refToDataOK     = 0;
#	    $$refToMustEnter .= 'valid reverse primer, ';
#	}
#    }
}


################################################################################
# returns 1 if is POSIX number, 0 if not.
# valid   examples inlcude: '1', '1.1', '0.' and '1.'
# invalid examples include: ' 1.1.1'  
################################################################################

sub isValidNumber {

    my ($self, $number) = @_;

    $number  =~ s/^\s+//;
    $number  =~ s/\s+$//;

    $!= 0;
    my ($num, $unparsed) = strtod($number); # POSIX sys call, returns num

    if( ($number eq '') || ($unparsed != 0) || $!  ) {
	return 0;
    }

    return 1;
}


################################################################################
# returns "true" if there is more than 1 primer matching the primer name
################################################################################

sub isValidPrimer {

    my ($self, $primerName,  $dbh) = @_;
    my $primer;
    my $project;

    warn "\n*** VALIDATE PRIMER ***\n" if $debug;

    if( $primerName eq '' ) {
	return( 0 );
    }

    my $stmt = "
        select count(*)
        from   PRIMER, CLONE_PROJECT
        where  PRIMER.PRIMERNAME         = '$primerName'
        and    CLONE_PROJECT.CLONENAME   = '$self->{cloneName}'
        and    CLONE_PROJECT.PROJECTNAME = PRIMER.PROJECTNAME";

    return ($dbh->fetch_scalar($stmt) > 0);
}


################################################################################
# User input should have been validated before calling this subroutine.
#
# Created in this order are
#
#    . Sub Clone info - SIL_DNASOUCE
#    . Request info   - SIL_REQUEST
#    . Fragment Sizes - SIL_INSERTSIZE
#
# Switch statement at end calls various subs to create other records (SIL_PCR,
# SIL_RESTRICTION).

# RETURNS: the job number

################################################################################

sub createRecords {

    my ($self, $dbh) = @_;
    my ($id_vectorsite, $id_map, $plateName);
warn "\n*** CREATE RECORDS ***\n" if $debug;

    # INFO FOR SIL_DNASOURCE

    if( $self->needSubcloneInfo ){

warn "needed subclone\n" if $debug;

	$id_vectorsite = $self->{vectorsWithEnzymes}->{$self->{isInVector}};
	$id_map        = $dbh->fetch_scalar("
            select ID_MAP
            from   ROWCOL_MAP
            where  MAPROW = '$self->{row}'
            and    MAPCOL = $self->{col}");

	$plateName        = "'$self->{plateName}'";
    }
    else {
	$id_map           = "''";
	$plateName        = "''";
	$id_vectorsite    = "''";
    }

    # CREATE SIL_DNASOURCE

    my $user = $dbh->fetch_scalar("select user from dual");
    warn "User == $user\n\n" if $debug;

    my $id_source  = $dbh->fetch_scalar("
        select SEQ_SILDNASOURCE.nextval
        from   dual");

warn "
        insert into SIL_DNASOURCE
               (ID_SOURCE,
                CLONENAME,
                ID_MAP,
                PLATENAME,
                ID_VECTORSITE)
        values ($id_source,
                '$self->{cloneName}',
                $id_map,
                $plateName,
                $id_vectorsite)
\n" if $debug;

    $dbh->do("
        insert into SIL_DNASOURCE
               (ID_SOURCE,
                CLONENAME,
                ID_MAP,
                PLATENAME,
                ID_VECTORSITE)
        values ($id_source,
                '$self->{cloneName}',
                $id_map,
                $plateName,
                $id_vectorsite)");

    # INFO FOR SIL_REQUEST

    my $SILtype          = $self->{frameChoice};
    my $id_SIL_type_dict = $dbh->fetch_scalar("
        select ID_DICT
        from   SILTYPEDICT
        where  DESCRIPTION = '$SILtype'");

    unless( $id_SIL_type_dict ) {
	LemurUtils->showError($self->{mw},
			      "No entry in SILTYPEDICT for '$SILtype'. ".
			      "Please tell bug!");
    }

#    my $date =  (localtime)[3]."/".
#	       ((localtime)[4] + 1)."/".
#	       ((localtime)[5] + 1900);

    my $id_role = $self->{finisherHash}->{$self->{submitter}};

    # CREATE SIL_REQUEST
    # There are some optional fields, build up SQL string with possible fields.
    # Can't have blank lines in SQL, hence bad layout....

    my $cloneIntoVector_field = '';
    my $cloneIntoVector_data  = '';

    if( $self->needCloneIntoVector && $self->{cloneIntoVector} ne '' ) {
	$cloneIntoVector_field = 'PREFERRED_VECTOR,';
	$cloneIntoVector_data  = 
	    "$self->{vectorsWithEnzymes}->{$self->{cloneIntoVector}},";
    }

    my $gapSize = '';

    if( $self->needApproxGapSize() ) {
	$gapSize = $self->{GapSize};
    }

    warn "self->{GapSize} = ", $self->{GapSize}, "\n" if $debug;
    warn "gapSize         = $gapSize\n"               if $debug;

    my $id_request = $dbh->fetch_scalar("
        select SEQ_SILREQUEST.nextval
        from   dual");

#    Mail::sendMail( -to      => 'pjm',
#                    -subject => "Lemur: Got Job Num $id_request",
#                    -message => "\nAttempting to add request $id_request\n".
#                                "Clone name: $self->{cloneName}");

warn "
        insert into SIL_REQUEST
               (ID_REQUEST,
                REQUEST_DATE,
                REQUESTED_BY,
                ID_SOURCE,
                SIL_TYPE,
                GAP_SIZE_KB, $cloneIntoVector_field
                REMARK)
        values ($id_request,
                SYSDATE,
                $id_role,
                $id_source,
                $id_SIL_type_dict, 
                '$gapSize', $cloneIntoVector_data
                '$self->{comment}')
" if $debug;

    $dbh->do("
        insert into SIL_REQUEST
               (ID_REQUEST,
                REQUEST_DATE,
                REQUESTED_BY,
                ID_SOURCE,
                SIL_TYPE,
                GAP_SIZE_KB, $cloneIntoVector_field
                REMARK)
        values ($id_request,
                SYSDATE,
                $id_role,
                $id_source,
                $id_SIL_type_dict, 
                '$gapSize', $cloneIntoVector_data
                '$self->{comment}')");

    warn "\n" if $debug;
    warn "SIL_REQUEST.ID_REQUEST = $id_request\n" if $debug;
    warn "\n" if $debug;

    # CREATE SIL_INSERTSIZE (loop for each fragment) if needed.

    if( $self->needLibrarySizes() ){

	my $arrayRef = $self->{BandsArray};
	my $from;
	my $to;

	for my $x (0..$MAIN::NUM_BANDS) {

	    $from = $arrayRef->[$x][0];
	    $to   = $arrayRef->[$x][1];

	    if( $from ne '' && $to ne '' ) {

		$dbh->do("
                insert into SIL_INSERTSIZE
                values ($id_request,
                        $from,
                        $to)");
	    }
	}
    }

    # CREATE SILREQUEST_STATUS of 'Request made'

    my $operator = $self->{email_id_of}->{$self->{submitter}};

    $dbh->do("
        insert into SILREQUEST_STATUS
        values ($id_request,
                1,
                SYSDATE,
                1,
                $self->{session_id},
                'EnterJob.pm',
                '$operator')");

    # NOW call the correct sub depending on what
    # the finisher wants the SubCloners to do.

    $_ = $self->{frameChoice};
    
    SWITCH: {
	/^PCR/            && do { $self->createPCRrecord($id_request,
							 $dbh);
				  last SWITCH; };

	/^subClone/       && do { last SWITCH; };

	/^Transposon/     && do { $self->createTransposonRecord($id_request,
								$dbh);
				  last SWITCH; };

	/^Clone PCR/     && do { $self->createClonePCRRecord($id_request,
							     $dbh);
				 last SWITCH; };
	
	/^Genome Walk/    && do { $self->createGWalkRecord($id_request,
							   $dbh);
				  last SWITCH; };

	/^Oligo Screening/ && do {$self->createOligoScreeningRecord($id_request,
								    $dbh);
				  last SWITCH; };

	/^Restriction/    && do { $self->createRestrictionRecord($id_request,
								 $dbh);
				  last SWITCH; };
    }

    # return the job number

    return $id_request;
}


sub createPCRrecord {
    my ($self, $id_request, $dbh) = @_;
    my $kinaseBool     = 0;
    my $purfifyGelBool = 0;

    $kinaseBool     = 1 if($self->{kinase}    eq 'Yes');
    $purfifyGelBool = 1 if($self->{purifyGel} eq 'Yes');

    $dbh->do("
        insert into SIL_PCR
        values ($id_request,
                '$self->{PCRforwardPrimerName}',
                '$self->{PCRreversePrimerName}',
                $self->{sizeOfPCR},
                $purfifyGelBool,
                $kinaseBool)");
}

sub createTransposonRecord {
    my ($self, $id_request, $dbh) = @_;

    unless( $self->{transposonTabSelected} eq 'PCR' ) {
	return;
    }

    $dbh->do("
        insert into SIL_PCR
        values ($id_request,
                '$self->{transForwardPrimerName}',
                '$self->{transReversePrimerName}',
                $self->{sizeOfTranposonPCR},
                0,
                0)");
}

sub createClonePCRRecord {
    my ($self, $id_request, $dbh) = @_;
    my $kinaseBool     = 0;
    my $purfifyGelBool = 0;

    $purfifyGelBool = 1 if($self->{purifyGel} eq 'Yes');

    $dbh->do("
        insert into SIL_PCR
        values ($id_request,
                '$self->{ClonePCRforwardPrimerName}',
                '$self->{ClonePCRreversePrimerName}',
                $self->{sizeOfClonePCR},
                $purfifyGelBool,
                $kinaseBool)");
}

sub createGWalkRecord {

    my ($self, $id_request, $dbh) = @_;

    $dbh->do("
        insert into SIL_PCR
        values ($id_request,
                '$self->{walkForwardPrimerName}',
                '$self->{walkReversePrimerName}',
                0,
                0,
                0)");
}

sub createOligoScreeningRecord {

    my ($self, $id_request, $dbh) = @_;

    $dbh->do("
        insert into SIL_PCR
        values ($id_request,
                '$self->{scrnForwardPrimerName}',
                '$self->{scrnReversePrimerName}',
                0,
                0,
                0)");

    $dbh->do("
        insert into SIL_INSERTSIZE
        values ($id_request,
                $self->{screenForSize}->[0],
                $self->{screenForSize}->[1])");
}

sub createRestrictionRecord {

    my ($self, $id_request, $dbh) = @_;

    my $data = $self->getRestrictionDataRef();

warn "\n*** CREATE RESTRICTION ***\n" if $debug;

    $dbh->do("
        insert into SIL_RESTRICTION
               (ID_REQUEST,
                CONSENSUS_FILE,
                GAP_COORDINATE,
                ENZYMENAME)
        values ($id_request,
                '$data->{ConsensusFile}',
                $data->{GapCoord},
                '$data->{EnzymeUsed}')");

    if( $self->{restrictTabSelected} eq 'PCR' ) {
	$dbh->do("
            insert into SIL_PCR
            values ($id_request,
                    '$self->{restrictForwardPrimerName}',
                    '$self->{restrictReversePrimerName}',
                    $self->{sizeOfrestrictPCR},
                    0,
                    0)");
    }
}


################################################################################
# after add is pressed, this gets called
################################################################################

sub clearWidgets {
    my ($self) = @_;
    
    ($self->{cloneName},
     $self->{plateName},
     $self->{row},
     $self->{col},
     $self->{GapSize})     = @{ [] };

    my $arrayRef = $self->{BandsArray};

    for my $x (0..$MAIN::NUM_BANDS) {
	$arrayRef->[$x][0] = '';
	$arrayRef->[$x][1] = '';
    }

    $self->{cloneIntoVector} = '';
    $self->{comment}         = '';

    $self->{sizeOfPCR}            = '';

    $self->{PCRforwardPrimerName} = '';
    $self->{PCRreversePrimerName} = '';

    $self->{transForwardPrimerName}    = '';
    $self->{transReversePrimerName}    = '';
    $self->{sizeOfTranposonPCR}        = '';
    $self->{walkForwardPrimerName}     = '';
    $self->{walkReversePrimerName}     = '';
    $self->{scrnForwardPrimerName}     = '';
    $self->{scrnReversePrimerName}     = '';
    $self->{sizeOfScrnPCR}             = '';
    $self->{restrictForwardPrimerName} = '';
    $self->{restrictReversePrimerName} = '';
    $self->{sizeOfrestrictPCR}         = '';

    $self->{sizeOfClonePCR}            = '';
    $self->{ClonePCRforwardPrimerName} = '';
    $self->{ClonePCRreversePrimerName} = '';

    my $ref               = $self->getRestrictionDataRef();
    $ref->{ConsensusFile} = '';
    $ref->{GapCoord}      = '';
    $ref->{EnzymeUsed}    = '';
}

sub expire {
    my ($self, $message) = @_;

    Mail::sendMail( -to      => 'bug',
                    -subject => "Lemur: Error requesting job",
                    -message => $message);
    die "$message\n";
}

#

sub DESTROY {
    my ($self) = @_;
    $self->{dbi}->disconnect if $self->{dbi};
    $self->{dbi} = undef;
}

#######
# EOF
#######
1;


#
# $Log: LemurRequestJob.pm,v $
# Revision 1.34  2005/11/14  16:30:51  mdf
# *** empty log message ***
#
# Revision 1.33  2005/11/14  16:26:49  mdf
# added team numbers
#
# Revision 1.32  2004/05/07  14:00:08  mdf
# Modified the clone list sql to order it by clonename
#
# Revision 1.31  2003/05/27  14:03:05  mdf
# *** empty log message ***
#
# Revision 1.30  2003/05/27  13:52:42  mdf
# *** empty log message ***
#
# Revision 1.29  2003/05/27  13:47:09  mdf
# Fixed window resize problem
#
# Revision 1.28  2001/04/04  15:12:31  pjm
# bug email was going to pjm and not bug, this has been rectified
#
# Revision 1.27  2000/07/27  13:54:35  pjm
# looks up plate name. If not in oracle asks user if correct name - could be
# in Equus. Maybe write code to look up there in the future....?
#
# Revision 1.26  2000/05/10  15:59:03  pjm
# Makes sure user has not written War & Peace in the comments field.
#
# Revision 1.25  2000/04/04  16:23:42  pjm
# commented out auto email to pjm when seq_SILREQUEST.nextval is executed.
#
# Revision 1.24  2000/03/08  09:43:29  pjm
# Oracle wont take gap size or size of PCR > 999.99. Code now checks not bigger
# than 9999.99 in both cases
#
# Revision 1.23  2000/03/07  15:03:54  pjm
# getFinishers() also gets subcloners now....
#
# Revision 1.22  2000/03/07  13:57:16  pjm
# emails pjm when the do elect SEQ_SILREQUEST.nextval - temp code only!
#
# Revision 1.21  2000/03/06  15:28:05  pjm
# added SYSDATE instead of date worked out from localtime - done when coder
# was new, honest :)
#
# Revision 1.20  2000/03/06  14:58:08  pjm
# have added a mail to bug if things go wrong after pressing the add button!
#
# Revision 1.19  1999/11/25  14:31:33  pjm
# changed variable name ($list -> vec_list)
# made Clone into Vector BrowseEntry readonly so can't type into it
#
# Revision 1.18  1999/11/25 11:42:25  pjm
# changed $debug to 0.
# Dialog box for showing job number used to have error for its title - now
# says "Your Job Number"
#
# Revision 1.17  1999/11/25 10:04:31  pjm
# added some debug output.
#
# Revision 1.16  1999/08/10 15:58:21  pjm
# took off \n in subject line. Dohh.
#
# Revision 1.15  1999/08/05 17:03:16  pjm
# added Clone PCR option, hence lots of additional code.
#
# Revision 1.14  1999/07/28 16:24:24  pjm
# taken out auto email everytime someone requested job. Calls LemurUtils stuff
# instead of it's own functions.
#
# Revision 1.13  1999/07/26 11:23:37  pjm
# Pressing Reports button now l
