package APE::InputControllerFactory::ConcreteInputController::PC_InputController;

use base
  'APE::InputControllerFactory::ConcreteInputController::STUDY_InputController';

$APE::InputControllerFactory::ConcreteInputController::PC_InputController::VERSION = '1.1';

use strict;
use warnings;
use Carp;

use APE::InputControllerFactory::ConcreteInputController::Requirement;
use APE::InputControllerFactory::ConcreteInputController::RequirementContainer;

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

{
    my %_attributes = (
        ## ** Add your object attributes here **
        ## They will automatically be given a get method.
        ## e.g. attribute 'personForename' can be accessed
        ## using getPersonForname(). There are no automatic
        ## set routines, they must be declared or the attribute
        ## value must be parsed in the constructor
        ## i.e new InputController(personForename=>'Simon');
    );

    my %object;

    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 overrides the createRequirement "
          . "method to group Requirement objects based on their inConcreteEntity id number."
          unless $args{description};

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

    #################################################################
    ## Overridden method from InputController base class.
    #################################################################
    sub createRequirements {
        my $self = shift;
        return if $self->hasRequirements();
        my $atomicProcessContainer = $self->getAtomicProcessContainer;
        my $arrayingEntityList     =
          $atomicProcessContainer->getArrayingEntityList();
        my %lookupPlate = ();
        my $indexPlate  = -1;
        my @storePlate  = ();
        ## Create new Requirement objects. AtomicProcess objects with
        ## matching inConcreteEntity id numbers are grouped so that
        ## only one Requirement object is used for all inputs.
        for ( my $aei = 0 ; $aei < @{$arrayingEntityList} ; $aei++ ) {
            my $atomicProcessList =
              $arrayingEntityList->[$aei]->getAtomicProcessList();
            for ( my $api = 0 ; $api < @{$atomicProcessList} ; $api++ ) {
                my $atomicProcess = $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::InputControllerFactory::ConcreteInputController::Requirement
                      (
                        atomicProcess => $atomicProcess,

                        #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 $linkCount =
                      $storePlate[ $lookupPlate{$inConcreteEntity} ]
                      ->attach($atomicProcess);
                }
            }
        }

        ## Create the study RequirementContainer and call super
        ## classes method to create a new study requirement object.
        my $studyRequirementContainer = new
          APE::InputControllerFactory::ConcreteInputController::RequirementContainer
          ( outDescription => 'Study Name' );
        $studyRequirementContainer->pushRequirement(
            $self->_getStudyRequirement );

        ## Create the RequirementContainer to hold the actual Requirements.
        my $requirementContainer = new
          APE::InputControllerFactory::ConcreteInputController::RequirementContainer(
          );
        ## Push the plate and column Requirement objects to the
        ## container.
        for ( my $i = 0 ; $i < scalar(@storePlate) ; $i++ ) {
            $requirementContainer->pushRequirement( $storePlate[$i] );
        }

        $self->pushRequirementContainer($studyRequirementContainer);
        $self->pushRequirementContainer($requirementContainer);
    }

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

1;
