package APE::BarcodeFactory::ConcreteBarcode::Barcode;

use strict;
use warnings;
use Class::Throwable;
use SqlEngine2;
use Carp;

use constant TRUE  => 1;
use constant FALSE => 0;
use constant LOGIN => 'gt_process';

$SqlEngine2::verbosity = 0; 

{
    my %_attributes = ( 
			barcodeType     => undef,
    			flushController => undef,
    			sqlEngineObj    => undef,
    			processId       => undef,
			entityId        => undef,
			reservedData    => []
    		      );
    
    my %object;
    
    foreach my $attName (keys(%_attributes)) {
    	no strict 'refs';
    	*{__PACKAGE__ . "::get\u$attName"} = sub { $object{ $_[0] }->{$attName} }
    }
    
    
    #################################################################
    ## Constructor method for this object. Returns a new
    ## BarcodeFactory object.
    #################################################################
    sub new {
    	my ($proto,%args) = @_;
    	
	## This is an abstract class, instances of it can not be created.
	confess "Error: can not create an instance of the abstract class ".
	    "'APE::BarcodeFactory::ConcreteBarcode::Barcode'."
	    if $proto eq 'APE::BarcodeFactory::ConcreteBarcode::Barcode';

    	my $class = ref($proto) || $proto;
    	my $self  = bless {}, $class;
    	
    	%args = $self->_init(%args);
    	
    	my @leftover = keys %args;
    	
    	confess "Error: the following arguments are unknown - @leftover\n" if @leftover;
    	
    	return $self;
    }
    
    
    #################################################################
    ## Initialise the objects private attributes. The argument is
    ## deleted as it is found, initialised and set.
    #################################################################
    sub _init {
    	my ($self,%args) = @_;
    	foreach my $attName (keys(%args)) {
    	    if(exists($_attributes{$attName})) {
    		$object{ $self }->{$attName} = delete $args{$attName};
    	    }
    	}
    	
    	## This class requires the processId attribute to be set.
    	croak "ERROR: argument processId has not been set."
    	    unless $object{ $self }->{processId};
    	
	## This class requires the barcodeType attribute to be set.
    	croak "ERROR: argument processId has not been set."
    	    unless $object{ $self }->{barcodeType};

	## This class requires the entityId attribute to be set.
    	croak "ERROR: argument entityId has not been set."
    	    unless $object{ $self }->{entityId};	

    	return %args;
    }

    #################################################################
    ## Method to find a Process objects root process id and description
    ## as well as its tract process id and description. Returns a hash
    ## containing two keys value pairs: 
    ## 
    ## root  => id_process  - the process id of the root process.  
    ## tract => description - the description of the tract this
    ##                        process is under.
    ##
    ###################################################################
    sub findRootTract {
	my $self = shift;

	## Return the cached root tract data if it exists.
	return $object{ $self }->{rootTract} if $object{ $self }->{rootTract};

	my $processId = $self->getProcessId;
	my $sqlEngine = new SqlEngine2;

	## Execute the lookup.
	my $rootTractData = 
	    eval { $sqlEngine->getAll
		       ('APE/BarcodeFactory/ConcreteBarcode/Barcode::FindRootTract',
			[$processId],
			SqlEngine2::getDbh(LOGIN)); };
	throw Class::Throwable::Simple($@) if $@;

	## The root or/and tract data was not returned - we need both.
	throw Class::Throwable::Simple("ERROR: root or tract for process '$processId' has not been found")
	    unless scalar(@{$rootTractData}) == 2;

	## Set the private object attribute.
	$object{ $self }->{rootTract} = { root => $rootTractData->[0], tract => $rootTractData->[1] };

	return $object{ $self }->{rootTract};
    }
    


    #################################################################
    ## Abstract class that should be implemented by the subclass.  This
    ## method should return the actual description object - what its
    ## all about!
    #################################################################
    sub createBarcode { die "ERROR: abstract method that should be implemented by the sub class."; }
}

1;
