#!/usr/local/bin/perl5.6.1 -w
# $Id: BC2DBaseLook.pm,v 1.1 2003/10/21 15:42:03 jx1 Exp $

package BC2DBaseLook;

use strict;
use warnings;
use Carp qw(croak cluck carp);
use Class::Struct;
use sigtrap qw(die untrapped normal-signals
               stack-trace any error-signals);
use Tk;

use BC2DBaseData;
use LabelerV;
use BoxScanrV;
use Dna2AbTubeV;

my $setup = { title_f       => "*-times-bold-r-normal--*-180-*-*-p-*-*-*",
	      entry_f       => "-adobe-helvetica-medium-r-normal--17-120-100-100-p-88-iso8859-1",
	      button_f      => "-adobe-helvetica-bold-r-normal--17-120-100-100-p-92-iso8859-1",
	      menu_f        => "-adobe-helvetica-bold-r-normal--17-120-100-100-p-92-iso8859-1",
	      label_f       => "-adobe-helvetica-bold-r-normal--14-100-100-100-p-82-iso8859-1",
	      active_entry  => "pale green",
	      disabled_entry=> "grey85",
	      other_entry   => "white",
	      frame_bordrw  => '5',
	  };


unless (caller)
{
    use BC2DBaseLook;
    my $front = BC2DBaseLook::new();
    $front = $front -> init();

    $front->UserBox() -> focusForce();
    #$front->updateWarning( "A bad one!" );
    MainLoop;
  
}


struct BC2DBaseLook =>
{
    MainWin   => '$', # ref to $mainwin,
    Menu      => '$', # ref to array of menus ,
    MsgBox    => '$', # ref to MessageBox,
    UserBox   => '$', # ref to user entry box,
    Operation => '$', # ref to sub window of the chosen operation,
    DataSource=> '$', # ref to data hash/object
};

sub init #new
{
#     my $invocant = shift;
#     my $class = ref($invocant) || $invocant;

    my $self = shift;

    
    ## set up to do ....
    $self->DataSource( BC2DBaseData->new()->init($self) );

    #my $mainwin = createMainWin( $self );  
    $self->MainWin( createMainWin( $self ) );
    $self->Menu( createMenu( $self ) );
    $self->MsgBox( createMessageBox( $self ) );
    $self->UserBox( createUserBox( $self ) );

    $self -> updateMessage( "Please enter user id.");
    $self->UserBox()->focus();

    
    return $self;
}


sub createMainWin
{
    my $family = shift;
    my $mainwin = MainWindow->new();
     
    $mainwin -> configure(cursor  => 'hand2');
    $mainwin -> wm('minsize', 480, 410); 
    $mainwin -> wm('maxsize', 1080, 910);
    
    # bind destroy window event
    #$mainwin -> onDestroy( [\&toExit, $family] );
    return $mainwin ;
}


sub createMenu
{
    my $self = shift;
    my $mw = $self->MainWin();
    #my $menuText = @_;

    my $f = $mw -> Frame( -relief	   => 'ridge', 
			  -borderwidth     => 2 )
	                -> pack( -side     => 'top',
				 -anchor   => 'n',
				 -expand   => 1,
				 -fill     => 'x' );

    # Create the menubutton, 
    my $filem = $f -> Menubutton ( -font      => $setup->{menu_f},
				   -text      => "File",
				   -tearoff   => 0,
				   -menuitems => [  "-",
						   [ "command" => "Exit",
						     -command  => [\&toExit, $self] 
						   ]
						 ]
				 ) -> pack ( -side => 'left' );
    
    my $operationm = $f -> Menubutton ( -font      => $setup->{menu_f},
					-text      => "Operation",
					-state     => 'disabled',
					-tearoff   => 0,
					-menuitems => [ "-",
							[ "command" => "Create rack label",
							  -command  => [\&startMkLable, $self]
							],

							[ "command" => "DNA tube -> storage", 
							  -command  => [\&startStoreDNA, $self] 
							],

							[ "command" => "Record box", 
							  -command  => [\&startRecordBox, $self] 
							]
						      ]	
				      ) -> pack ( -side => 'left' );

    return [$filem, $operationm];
    #return $operationm; 

}


sub createMessageBox
{
    my $self = shift;
    my $mainwin = $self->MainWin();
    
    ############ make frame to hold message box
    my $msgFrame = $mainwin -> Frame ( -borderwidth => '8' );
    $msgFrame -> pack ( -side   => 'top',
			-anchor   => 'n',
			-expand   => 1,
			-fill   => 'x');
    
    # create message box
    my $msgbox = $msgFrame -> ScrlListbox( -font        => $setup->{entry_f},
					   -bg          => 'white',
					   -scrollbars  => 'se',
					   -height      => 8,
					   -width       => 60,
					   -takefocus   => 0
					 ) -> pack( -side => 'top', 
						    -anchor => 's',
						    -fill => 'x');   

    return $msgbox;
	
}


sub createUserBox
{
    my $self = shift;

    my $parentw = $self->MainWin();

    my $userid='';
#    $self->{DataSource}->{UsrId} = $userid;

    my $user_frame = $parentw -> Frame( -borderwidth => $setup->{frame_bordrw},
					-label => "User ID  ",
					-labelFont => $setup->{button_f},
					-labelPack => [ -side => 'left'] );

    $user_frame -> pack ( -side   => 'top',
		          -expand => 1, 
		          -fill   => 'x');

    my $userEntry = $user_frame->Entry ( -width        => 15,
					 -font         => $setup->{entry_f}
				       )->pack(-side => 'left');
					 #-textvariable => \$self->DataSource()->UserId()
					 #-textvariable => \$userid 

    $userEntry -> bind ("<Return>" => [\&usr_finishEntry, $self] );

    # when $userEntry get focus
    #$userEntry -> bind ( "<Enter>" => \&usr_gotFocus ); # through mouse cursor
    $userEntry -> bind ( "<FocusIn>" => \&usr_gotFocus ); # through kb action

    # configure entry for starting look
    $userEntry -> grabRelease();
    $userEntry -> configure ( -background => $setup->{other_entry},
			      -state      => 'normal' );
  
    my $logout_button = $user_frame->Button( -font             => $setup->{button_f},
					     -fg               => 'purple',
					     -activebackground => 'black',
					     -activeforeground => 'white',   
					     -text             => "Logout",
					     -command          => [\&logout, $self]
					   ) -> pack(-side => 'right');

    my $clear_button = $user_frame->Button( -font             => $setup->{button_f},
					     -fg               => 'purple',
					     -activebackground => 'black',
					     -activeforeground => 'white',   
					     -text             => "Clear Message",
					     -command          => [\&clearMsgBox, $self]
					   ) -> pack(-side => 'right');

    return $userEntry;  #, \$userid];
}


sub enableOpMenu
{
    my $family = shift;
    
    $family->Menu()->[1]->configure( -state => 'normal' );    
}


sub disableOpMenu
{
    my $family = shift;
    
    $family->Menu()->[1]->configure( -state => 'disabled' );        
}


sub updateMessage
{
    my $self = shift;
    my @update_text = @_;
    my $msgbox = $self -> MsgBox();

    my @time = localtime();
    for( my $i=0; $i<3; $i++ ) #each (@time[0..2])
    {
	if( $time[$i] < 10 )
	{
	    $time[$i] = "0".$time[$i];
	}
    }
    $time[4] = $time[4] + 1;
    $time[5] = 1900 + $time[5];
    my $time_str = "$time[3]/$time[4]/$time[5] $time[2]:$time[1]:$time[0]  ";
    #print "Present: $time_str\n";

    for( my $i=0; $i<scalar( @update_text ); $i++ )
    {
	$update_text[$i] = $time_str.$update_text[$i];
    }

    #push @update_text, " "; #empty line for each message

    $msgbox -> insert( 'end', @update_text );
    $msgbox -> see( 'end' );
    $msgbox -> update( 'idletasks' );
}


sub updateWarning
{
    my $self = shift;
    my @wmsg = @_;
#    print "Number of elements in message: ", scalar(@wmsg), "\n";
    my $msgbox = $self -> MsgBox();

    for( my $i = 0; $i < scalar(@wmsg); $i++ )
    {
	$wmsg[$i] = "[Warning:] ".$wmsg[$i];
#	print "line $i: $wmsg[$i]\n";
    }
    #$wmsg = "[Warning:] ".$wmsg;

#    $msgbox -> insert( 'end',  $wmsg );
#    $msgbox -> see( 'end' );
#    $msgbox -> update( 'idletasks' );
    $self->updateMessage( "", @wmsg );
}



sub handleOpQuit
{
    my $self = shift;
    
    if( defined $self->Operation() )
    {
	$self->Operation( undef() );
    }

    print "Operation quit event.\n" if 
    return;
}


sub DESTROY
{
    my $self = shift;

    print "BC2DBaseLook finishing process ...\n";
    $self->DataSource( undef() );
    $self->Operation( undef() );
}


####    callbacks    ####

# logout button
sub logout
{
    my $family = shift;
    my $userEntry = $family->UserBox();

    $family->disableOpMenu();

    # the order of the next two statement seems important
    $userEntry -> configure( -background => $setup->{other_entry}, 
			     -state      => 'normal' );
    $userEntry -> delete (0, 'end');
    
    $family->DataSource()->resetUser();
    
    if( defined $family->Operation() )
    {
	$family->quitOperation();
    }
    return;
}

sub clearMsgBox
{
    my $family = shift;
    $family->MsgBox() -> delete( 0, 'end' );

    return;
}

# usr entry, been focused upon --
sub usr_gotFocus
{
    my $userEntry = shift;
    $userEntry -> configure( -background => $setup->{active_entry},
			     -state      => 'normal' );
#    $userEntry -> grab();
    
    return;
}


#usr entry, finish entering user info --
sub usr_finishEntry
{ 
    my $userEntry = shift;
    my $self = shift;

    $userEntry = $self->UserBox();
    
    # check any text at user entry box
    my $user = $userEntry -> get();
    if( !length( $user ) )
    {
	$user = $userEntry -> focusForce();
	return;
    }

    my $data = $self->DataSource();
    my $valid_user = $data->verifyUserId( $user ); # get() );
    #print "validation returns: ", $valid_user, "\n";
    if( $valid_user )
    {
	print "$valid_user is a valid user.\n";
	$userEntry -> delete( 0, 'end' );
	$userEntry -> insert( 0, $valid_user );
	$userEntry -> configure( -background   => $setup->{disabled_entry},	 
				 -state        => 'disabled' );
	
	# just to make $userEntry loose focus ...    
	$userEntry -> parent() -> focus();  
    
	#$self->Menu()->[1]->configure( -state => 'normal' );
	$self->enableOpMenu();
	$self->updateMessage( "Please choose an option from OPERATION menu." );

    }
    else
    {
	
    }

    return;
} 


# menu callbacks
sub startMkLable
{
    my $family = shift;
    my $mw = $family->MainWin();

    # quit previous operation if necessary
    $family->quitOperation();

    my $operation = LabelerV->new()->init( $mw, $family );
    $operation->OpFrame()-> pack( -side     => 'bottom',
				  -anchor   => 's',
				  -expand   => 1,
				  -fill     => 'x' ); 

    # start new op
    $family->Operation( $operation );
    $family->updateMessage ( "Create barcode labels for ABgene box." );
   
    return;
}


sub startStoreDNA
{
    my $family = shift;
    my $mw = $family->MainWin();

    # quit previous operation if necessary
    $family->quitOperation();

    # start new op
    my $operation;
    eval
    {
	$operation = Dna2AbTubeV->new()->init( $mw, $family );
    };
    if( $@ )
    {
	$family->updateWarning( $@ );
	return;
    }

    $operation->OpFrame()-> pack( -side     => 'bottom',
				  -anchor   => 's',
				  -expand   => 1,
				  -fill     => 'x' ); 
 
    $family->Operation( $operation );
    $family->updateMessage ( "Transfer DNA to storage tubes." );

    return;
}

sub startRecordBox
{
    my $family = shift;
    my $mw = $family->MainWin();

    # quit previous operation if necessary
    $family->quitOperation();

    # start new op
    my $operation;
    eval
    {
	$operation = BoxScanrV->new()->init( $mw, $family );
    };
    if( $@ )
    {
	$family->updateWarning( $@ );
	return;
    }

    $operation->OpFrame()-> pack( -side     => 'bottom',
				  -anchor   => 's',
				  -expand   => 1,
				  -fill     => 'x' ); 
 
    $family->Operation( $operation );
    $family->updateMessage ( "Scan and record Box." );

    return;
}


sub quitOperation
{
    my $family = shift;
    my $operation = $family->Operation();

    if( defined $operation )
    {
	print "previous operation exist, quit it now.\n";
	$family->Operation( )->end();
	$family->Operation( undef() );
    }
}


sub toExit
{
    my $self = shift;
    
    $self->DataSource( undef() ); #->DESTROY();
    $self->Operation( undef() );
    exit(0);
}


# top level destruction
sub onWindowKill
{
    my $family = shift;
    $family->toExit();
    print "Window destruction handled.\n";
}


######################################################################
#END
#{
#    print "End of BC2DBaseLook.pm\n";
#}
1;  # keep perl happy 
