package APE::InputController::COORD2PLATE_InputController;

use base 'APE::InputController';

use strict;
use warnings;
use Carp;

use APE::InputController::Requirement;
use APE::InputController::RequirementContainer;
#use APE::InputController::EPSA_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();
	$self->SUPER::createRequirements();
	my $inputRequirementContainer = 
	    new APE::InputController::RequirementContainer
	    (outDescription=>"Well co-ordinate");

	$inputRequirementContainer->pushRequirement
	    ( new APE::InputController::Requirement
	      (arrayingEntityIndex=> -1,
	       atomicProcessIndex => -1,
	       type               => 'Input',
	       description        => 'Enter well coord [rowcol]: ',
	       checkingCode       => qr/^[a-h][1-12]/ ) );	
	
	$self->unshiftRequirementContainer
	    ($inputRequirementContainer);

	## The getData method requires an EPSA_InputController method.
	#$object{ $self }->{epsaInputController} =
	#    new APE::InputController::EPSA_InputController
	#    (atomicProcessContainer=>$self->getAtomicProcessContainer(),
	#     sqlEngineObj          =>$self->getSqlEngineObj());
    }


    #################################################################
    ## Overridden method from base class to process a requirement 
    ## object. In the coord stored in the Input Requirement object
    ## is stored in this object and used when each of the Requirement
    ## Container objects are arrayed. 
    #################################################################
    sub process {
	my ($self,$requirementObj) = @_;
	## Set the requested coord if this is the input Requirement
	## object.
	if($requirementObj->getType eq 'Input') {
	    $object{ $self }->{coord} = $requirementObj->getData;
	    return;
	}

	## Call supers process method that will call this objects
	## getData method if the Requirement object is not type Input.
	eval  { $self->SUPER::process($requirementObj); };
	if($@){ croak $@; }
    }


    #################################################################
    ## Method to array the data stored in the Requirement objects in
    ## the passed RequirementContainer object. This method over-rides
    ## the base class method of the same name so that the ArrayPattern
    ## objects can be modified to only store the contents of the
    ## selected coordinate.
    #################################################################
    sub arrayContainerData {
	my ($self,$requirementContainer) = @_;
	croak "ERROR: coord has not been set - the Input Requirement " . 
	    "has not been received by the process method."
	    unless $object{ $self }->{coord};
	warn "\n*** Using coord: ".$object{ $self }->{coord}." ***\n";
 	eval  { $self->_alterArrayPatterns($object{ $self }->{coord},$requirementContainer); };
	if($@){ croak $@; }
	$self->SUPER::arrayContainerData($requirementContainer);
    }

    
    #################################################################
    ## Method to alter the array patterns in each of the AtomicProcess
    ## objects pointed to by each of the Requirement objects held in
    ## the completedRequirementsList so that they match the selected
    ## well of the source plate.
    #################################################################
    sub _alterArrayPatterns {
	my ($self,$coord,$requirementContainer) = @_;
	return if $requirementContainer->isInput;
	#warn "Altering ArrayPatterns.\n";
	#my $inputRequirement = $self->popCompletedRequirement();
	#my $coord            = $inputRequirement->getData();
	foreach my $requirementObj (@{$requirementContainer->getRequirementList}) {
	    next if $requirementObj->isInput;
	    #self->getCompletedRequirementList()}) { 
	    my $arrayingEntityIndex    = $requirementObj->getArrayingEntityIndex();
	    my $atomicProcessIndex     = $requirementObj->getAtomicProcessIndex();
	    my $atomicProcessContainer = $self->getAtomicProcessContainer();
	    my $arrayingEntity         = $atomicProcessContainer->getArrayingEntityList()->[$arrayingEntityIndex];
	    my $atomicProcess          = $arrayingEntity->getAtomicProcessList()->[$atomicProcessIndex];
	    ## Fetch then delete the hash of ArrayPattern objects from the
	    ## AtomicProcess object.
	    my $arrayPatternHash  = $atomicProcess->deleteArrayPatternHash();
	    ## Adjust the ArrayPattern object to show the new inMapId data.
	    foreach my $mapId (keys(%{$arrayPatternHash})) {
		foreach my $arrayPattern (@{$arrayPatternHash->{$mapId}}) {
		    warn "Before AP($coord): ".$arrayPattern->getInRow . $arrayPattern->getInColumn.
		    " -> " . $arrayPattern->getOutRow . $arrayPattern->getOutColumn."\n";
		    eval  { $arrayPattern->_setInCoord($coord); };
		    if($@){ croak $@;                           }
		    warn "After AP($coord): ".$arrayPattern->getInRow . $arrayPattern->getInColumn.
		    " -> ".$arrayPattern->getOutRow . $arrayPattern->getOutColumn."\n";
		    $atomicProcess->addArrayPattern($arrayPattern);
		}
	    }
	}
    }


    #################################################################
    ## Overridden method from base class to get data associated with 
    ## less well known entity types. This method creates a new       
    ## EPSA_InputController and uses its getData method as it knows 
    ## how to distinquish between an EP sense and EP antisense entity
    ## and thus get the correct information from the database.
    #################################################################
    #sub getData {
    #	my ($self,$requirementObj) = @_;
    #	my $completedRequirementObj = 
    #	    eval  { $object{ $self }->{epsaInputController}->getData($requirementObj); };
    #	if($@){ croak $@; }
    #	return $completedRequirementObj;
    #}


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

1;
