package APE::InputController::COL2PLATE_InputController;

use base 'APE::InputController::STUDY_InputController';

use strict;
use warnings;
use Carp;

use APE::InputController::Requirement;
use APE::InputController::RequirementContainer;
#use APE::InputController::EPSA_InputController;
#use APE::InputController::PCSTUDY_InputController;

use constant TRUE  => 1;
use constant FALSE => 0;

{
    my %_attributes = ( );

    my %object;

    ## Autoloader wannabe. Inserts the sub calls that I want to be
    ## accessible into the symbol table.
    foreach my $attName (keys(%_attributes)) {
	no strict 'refs';
	*{__PACKAGE__ . "::get\u$attName"} = sub { $object{ $_[0] }->{$attName} }
    }


    #################################################################
    ## 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};
	    }
	} 

  	## Set the description as this is a specialised InputController.
	$args{description} = "An InputController that adds a Requirement object to " . 
	    "the requirementList. The new Requirement object is type 'Input' and " . 
	    "requires the user to enter a plate well coord.";

	return $self->SUPER::_init(%args);
    }


    #################################################################
    ## Overridden method from base class to create the Requirement
    ## objects. Calls the base class method of the same name to build
    ## the basic number of Requirement objects. It then adds its own
    ## Requirement object (type='Input') that requests the user to
    ## enter a plate coord.
    #################################################################
    sub createRequirements {
	my $self = shift;
	return if $self->hasRequirements();
	my $atomicProcessContainer = $self->getAtomicProcessContainer();
	## Make sure the ArrayingEntity objects held in the container
	## are aware that there may be missing arraying data from the
	## ArrayPattern objects.
	$atomicProcessContainer->setAllowMissingArrayData(TRUE);
	my $arrayingEntityList = $atomicProcessContainer->getArrayingEntityList();
	my %lookupPlate  =();
	my $indexPlate   =-1;
	my @storePlate   =();
	my $description;
	## Create Requirements for each inConcreteEntity as the in is
	## split into 2 X 12 columns.
	for(my $aei=0; $aei < @{$arrayingEntityList}; $aei++) {
	    my $atomicProcessList = $arrayingEntityList->[$aei]->getAtomicProcessList();
	    for(my $api=0; $api < @{$atomicProcessList}; $api++) {
		my $description = $atomicProcessList->[$api]->getInDescription();
		my $inConcreteEntity  = $atomicProcessList->[$api]->getInConcreteEntity();
		my $outConcreteEntity = $atomicProcessList->[$api]->getOutConcreteEntity();
		## Sense and Antisense plate Requirement objects are
		## created here and pushed to the queue.
		if(!exists($lookupPlate{$inConcreteEntity})) {
		    $lookupPlate{$inConcreteEntity} = ++$indexPlate;
		    my $localDescription = $description . " - (".$atomicProcessList->[$api]->getInPrefix()."): ";
		    $storePlate[$lookupPlate{$inConcreteEntity}] 
			= new APE::InputController::Requirement
			(arrayingEntityIndex=>[$aei],
			 atomicProcessIndex =>[$api],
			 type               =>$atomicProcessList->[$api]->getInPrefix(),
			 description        =>$localDescription);
		}else{
		    ## Push the ArrayingEntity index to the Requirement object.
		    my $res = $storePlate[$lookupPlate{$inConcreteEntity}]->pushIndexes($aei,$api);
		}
	    }
	}
	
	my $requirementContainer = 
	    new APE::InputController::RequirementContainer();

	## Push the plate and column Requirement objects onto the
	## queue.
	for(my $i=0; $i < scalar(@storePlate); $i++) {
	    $requirementContainer->pushRequirement($storePlate[$i]);
	}
	
	$self->pushRequirementContainer($requirementContainer);

	## Push a Study Requirement object if this is a PCR output.
	## Not tidy but it will do for phase 1.
	if($atomicProcessContainer->getParentProcessId() =~ /[5739|6236|6543]$/) {
	    my $requirementContainer = 
		new APE::InputController::RequirementContainer(outDescription=>'Study Name');
	    #$object{ $self }->{pcStudyInputController} =
	    #new APE::InputController::PCSTUDY_InputController
	    #(atomicProcessContainer=>$self->getAtomicProcessContainer(),
	    # sqlEngineObj          =>$self->getSqlEngineObj());
	    ## Add the Requirement to the RequirementContainer attribute list.
	    $requirementContainer->pushRequirement($self->_getStudyRequirement);
	    ## Add the RequirementContainer to the attribute list.
	    $self->unshiftRequirementContainer($requirementContainer);
	    ## Add an EPSA input controller to deal with EP type entities.
	    #$object{ $self }->{pcStudyInputController}->_addEPSAInputController;
	}
    }


    #################################################################
    ## Overriden method from InputController base class. This is here
    ## to deal just with the PC study name. If the process is any of
    ## those in the pattern then the PCSTUDY_InputController is used to
    ## process the requirement.
    #################################################################
    sub process {
	my ($self,$requirementObj) = @_;
	if($self->getAtomicProcessContainer->getParentProcessId() =~ /[5739|6236]$/) {
	    warn "****** Found Requirement that requires PCSTUDY treatment: ".
	    $requirementObj->getType. "\n";
	    eval  { $requirementObj = $self->SUPER::_setData($requirementObj); };
	    #eval  { $requirementObj = $object{ $self }->{pcStudyInputController}->_setData($requirementObj); };
	    if($@){ croak $@; }
	}else{
	    ## Call supers process method that will call this objects
	    ## getData method if the Requirement object is not type Input.

	    ## Get the data associated with this Requirement object and
	    ## set it.
	    eval  { $self->getData($requirementObj); }; #$self->SUPER::process($requirementObj); };
	    if($@){ croak $@;                               }
	}
    }


    #################################################################
    ## Method to destroy this object.
    #################################################################
    sub DESTROY {
	my $self = shift;
	delete $object{$self};
	$self->SUPER::DESTROY;
    }
}

1;
