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

package Dna2AbTubeDataMgr;

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

use sql_engine;
use BarcodeRevised_V2_0;
use Checkbarcode;

use User;
use Medusa;

my $ABgenehost = "$ENV{'ABGENE_HOST'}";
my $ABtube_prefix = 'AB';
my $db = '2dbarcode';
my $sqllib = "Dna2AbTube.sql_lib";

####    simple tester for object    ####
unless( caller )
{
    use Dna2AbTubeDataMgr;
    
    my $dmgr = Dna2AbTubeDataMgr->new()->init();

    for( my $i=0; $i<3; $i++)
    {
	$dmgr->addDataLine($i*1000);
	my $tbid = $dmgr->readAbTube();
	$dmgr->readAbTube();
    }
#    print "The tube id: $tbid\n";

    print "Content in DataList: \n";
    foreach (@{$dmgr->DataList()})
    {
	print "Element count in this list: ", scalar @{$_};
	print "\nline -- ";

	foreach my $e (@{$_})
	{
	    print "$e ";
	}
	#print "\n";
    }

}


###################################
#                                 #
#        Object definition        #
#                                 #
###################################

struct Dna2AbTubeDataMgr =>
{
    BcReader => '$',
    DataList => '$',
    Scanned  => '$',
    CurrDnaT => '$',
    QueryHandlr => '$',
    VLeader => '$',
    UserInfo => '$',
};


####    public methods    #### 
sub init 
{
    my $self = shift; 
    my $bchost;

    if( @_ )
    {
	$bchost = shift;  # scalar - string
    }
    else
    {
	$bchost = $ABgenehost;
    }

    #print "ABgene host is: $bchost\n";
    eval
    {
	$self -> BcReader( Medusa->new( host => $bchost ) );
    };
    if( $@ )
    {
	croak "2D tube scanner may be busy: $@\n";
    }

    my $vleader = $self->VLeader();
    if( defined $vleader )
    {
	$self -> UserInfo( $vleader->DataSource()->User() ); 
    }   
#    if( $^W )
#    {
#	my $user = $self -> UserInfo();
#	
#	if( defined $user )
#	{
#	    print "User information: \n";
#	    print "UserId: ", $user->PersonId(), "\n";
#	    print "Team:   ", $user->Team(), "\n";
#	    print "RoleId: ", $user->RoleId(), "\n";
#	}
#    }

    # database connection
    my $qhdlr = statements->new("$db");
#    $qhdlr->default_sql_lib_path('./');
#    print $sqllib::all', "\n";
    $qhdlr->load_sql_lib([$sqllib."::all"]);
    $qhdlr->{debug} = 1 if( $^W );
    $self->QueryHandlr( $qhdlr );

    $self -> DataList( [] );
#    print "DataList ref: ", $self->DataList(), "\n";

    $self -> Scanned( {} );
    return $self;
}


my $checkSessionDnaTube = sub
{
    my $family = shift;
    my $tid = shift; # this should be all numerical

    my @data = values %{$family->Scanned()};

    my $i = 0;
    foreach (@data)
    {
	$i ++ if( $_->[0] == $tid );
    }

    return $i;
};


sub verifyDnaTube
{
    my $self = shift;
    my $tubeid = shift;
    my $dbqueryh = $self->QueryHandlr();
    my $vleader = $self->VLeader();

    # format check
    my $result = Verifynumber( $tubeid ); 

    if( $result->{Process} eq 'Good' )
    {
	$tubeid = $result->{Whole};
	if( $tubeid !~ /^DT/ )
	{
	    croak "$tubeid is not a DNA tube id.\n";
	}

	# database verification
	my $res_query = ($dbqueryh->get( $sqllib.'::exist_dna_tube',
					 [$result->{Number}] )
			 );
	# in query result, 
	# 1st col - DNA tube id
	# 2nd col - team the DNA belongs to
	# 3rd col - storage tube id (AB...) if exist

	my $n_res = scalar(@{$res_query});
	
	if( $n_res == 0 )
	{
	    # problem with finding DNA tube id in database
	    print "$tubeid is not recorded in database.\n";
	    croak "$tubeid is not recorded in database - CONTACT BUG!!!\n";
	}

	# when $n_res >= 1 only
	#$self->CurrDnaT( [$res_query->[0]->[0], $res_query->[0]->[1]] );    
	# change ownership from DNA tube's team to trasfer operator's team
	$self->CurrDnaT( [$res_query->[0]->[0], $self->UserInfo()->Team()] );
	$self->addDataLine( $tubeid );

	# check storage tubes already exist in database
	my $storeT = $dbqueryh->get( $sqllib.'::exist_STRtube4DNAtube',
				     [$result->{Number}] );
		     
	my $n_st = scalar( @{$storeT} );
	print "Number of tubes for storage: $n_st\n";
	if( $n_st )
	{
	    # storage tubes already exist, give warning message
	    $vleader->updateWarning( "$n_st ABtubes already exist for $tubeid in database." );
	}

	# check data in this session, not yet has db update
	my $tcnt = 0;
	$tcnt = $self->$checkSessionDnaTube( $result->{Number} );
	
	if( $tcnt > 0 )
	{
	    $vleader->updateWarning( "$tcnt ABtubes already scanned for $tubeid in this session." );
	}
	
    } # end - if( $result->{Process} eq 'Good' )
    else
    {
	croak "Incorrect format - $tubeid\n";
    }

    return $result->{Whole};
}


sub addDataLine
{
    my $self = shift; 

    push @{$self->DataList()}, [@_];
    print "-- Lines of data in data source: ", scalar @{$self->DataList()}, " --\n";

	foreach my $line ( @{$self->DataList()} )
	{
	    foreach (@{$line})
	    {
		print $_, "\t";
	    }
	    print "\n";
	}

    return;
}


sub removeDataLine
{
    my $self = shift; 
    
    pop @{$self->DataList()};
    
    # need to undef CurrDnaT ??
    return;
}


sub removeDataItem
{
    my $self = shift; 
    my $item = shift;
    
    my $dataline = $self->getLastDataLine();
    my $item_1 = pop @{$dataline};
    delete $self->Scanned()->{$item_1};

    # for debug only
    if( $item ne $item_1 ) #&& $^W )
    {
	print "-- removing data item from data source --\n";
	print "input item:       $item\n";
	print "data source item: $item_1\n";
    }

    return ;
}


sub getLastDataLine
{
    my $self = shift;
    my $ilast = (scalar @{$self->DataList()}) - 1;

    return $self->DataList()->[$ilast];
}

sub readAbTube
{
    my $self = shift;

    my $tube_id = $self->BcReader()->read();
#    print $tube_id, "\n";
    if( $tube_id !~ $ABtube_prefix )
    {
	#if( $^W )
	{
	    print "No tube in Meduas.\n";
	}
	croak "No tube to read.\n";
    }
    
    my $scanned = $self->Scanned();
    if( exists( $scanned->{$tube_id} ) )
    {
	# repeated scan of the same tube
	# a failing point
	croak "Tube already scanned. Please insert a new tube.\n";
    }
    # else, check in db if tube already used
    # if not mark tube as scanned
    else
    {
	# database check
	my $res_query = $self->QueryHandlr()->get( $sqllib.'::is_ABtube_used', [$tube_id] );
	print "there are ", scalar @{$res_query}, " results from query.\n";
	if( scalar @{$res_query} ) # tube already been used
	{
	    croak "Tube is already in use. Please choose another.\n";
	}

	$scanned->{$tube_id} = $self->CurrDnaT();
	print $scanned->{$tube_id}->[0], " belongs to team ", $scanned->{$tube_id}->[1], "\n";
    }

    # ??record data, move to View??
    my $data = $self->DataList();
#    print "Is this an array; ", @{$data}, "\n";
    my $cur_i = scalar (@{$data}) - 1;
    print "current index of array: $cur_i\n"; 

    push @{$data->[$cur_i]}, $tube_id;

    print "content in the cur indexed array: \n";
    foreach (@{$data->[$cur_i]})
    { 
	print "$_\n";
    }

    return $tube_id;
}


sub recordData
{
    my $self = shift;
    my $data = $self->Scanned();
    my $dbqh = $self->QueryHandlr();
    my $user = $self->UserInfo();

    print "Is this a problem: ", scalar( %{$data} ), "\n";
    if ( scalar( keys %{$data} ) == 0 )
    {
	print "Nothing to update.\n";
	$self->VLeader()->updateWarning( "Nothing to update." );

	return;
    }
#    else
#    {
#	print "Recording data in database happens here!\n";
#    }

    my ($ab_tube, $dnat_info );
    while( ($ab_tube, $dnat_info) = each %{$data} )
    {
	print "$ab_tube is from DT$dnat_info->[0], team$dnat_info->[1]\n"; # if( $^W );
	# $dnat_info->[0] -- source tube db id
	# $dnat_info->[1] -- team ordered the source

	eval
	{
	    my $res_query = $dbqh->do( $sqllib.'::create_new_physical_entity', 
					[ $ab_tube, $dnat_info->[1] ] );

	    $dbqh->do( $sqllib.'::record_new_entity_status',
			[ $user->RoleId() ] );

	    $dbqh->do( $sqllib.'::record_new_entity_contents' );

	    $dbqh->do( $sqllib.'::record_new_entity_info',
			[ $dnat_info->[0] ] );
	};
	if( $@ )
	{
	    # rollback, warn, and continue.	    
	    $dbqh->{DBH}->rollback();
	    warn "$@. CONTACT BUG!!!\n";
	}
	else
	{
	    $dbqh->{DBH}->commit();
	    delete( $data->{$ab_tube} ); # remove if db update successfull
	}
    } #end while

    # any unsuccessfull update?
    if( scalar %{$data} )
    {
	print "Not all scanned data have been recorded in database -\n";
	while( ($ab_tube, $dnat_info) = each %{$data} )
	{
	    # the following info should go into a logfile
	    print "$ab_tube is from DT$dnat_info->[0], team$dnat_info->[1]\n"; # if( $^W );
	}
	croak "Not all scanned data have been recorded in database, CONTACT BUG!!!\n";
    }
    else
    {
	# data for display should be cleared ??
	#$self->resetData();

	#above line commented out 
	#since user prefer data remain in view after update successful
    }
}


sub resetData
{
    my $self = shift;

    $self -> DataList( [] );
    $self -> Scanned( {} );
    $self -> CurrDnaT( undef );

    return $self;
}


sub DESTROY
{
    my $self = shift;
    
    my $reader = $self->BcReader();
    if( defined $reader )
    {
	$reader->delete();
	#$self->BcReader(undef());
    }
    
    my $qryh = $self->QueryHandlr();
    if( defined $qryh )
    {
	$qryh->{DBH}->rollback();
	$qryh -> end();
    }
    
    return;
}

1;  # just to keep perl happy
