package APE::InputControllerFactory::Plugin::UniqueRequirementCreator;

use base qw(APE::InputControllerFactory::Plugin::RequirementCreator);

$APE::InputControllerFactory::Plugin::UniqueRequirementCreator::VERSION = '0.1';

use strict;
use warnings;

=head1 NAME

APE::InputControllerFactory::Plugin::UniqueRequirementCreator - XXX fill in.


=head1 SYNOPSIS

use APE::InputControllerFactory::Plugin::UniqueRequirementCreator

my $object = APE::InputControllerFactory::Plugin::UniqueRequirementCreator->new
  (
   XXX fill in options
   );


=head1 DESCRIPTION

XXX fill in description.


=head1 CONSTANTS

=over 5

=item TRUE

This is a boolean true constant.

=cut

use constant TRUE  => 1;

=item FALSE

This is a boolean false constant.

=cut

use constant FALSE => 0;

=back

=head1 CONSTRUCTOR

=over 5

=item $object = APE::InputControllerFactory::Plugin::UniqueRequirementCreator->new(option => value,...?);

The constructor for this class calls the populateWells method (see
populateWells() method) to create as many Entity::Well objects as the
format of the plate. Override the populateWells method to use derived
instances of Entity::Well objects or to alter the number of
Entity::Well objects created.

The following arguments may be passed to the constructor so are
options for all derived classes of type Entity.

=over 5

=item controller

Required. An APE::Controller object of type
APE::InputControllerFactory::ConcreteInputController::InputController.

=back

=cut

my %_attributes = ();

=head2 INSTANTIATION PROCESS

The new method for this object calls the _init() method on $self. If
$self is a derived class then it's _init() method will be called
giving it the chance to remove any arguments it requires from the
%args hash. If there is no _init() method in the derived class then
the _init() method in this class is called.

Derived classes implementing a _init() method should return the %args
hash to the base class:

package Derived::Class;

sub _init {
   my ($self,%args) = @_;
   my $argument = delete $args{classArgument};
   return $self->SUPER::_init(%args);
}

=cut

sub new {
    my ($proto,%args) = @_;
    my $self = $proto->SUPER::new(%args);
    my $controller = $self->getController();
    ## Check type of InputController.
    die "Error: argument 'controller' should be an ".
      "APE::InputControllerFactory::ConcreteInputController::InputController class"
      unless UNIVERSAL::isa
      ($controller,"APE::InputControllerFactory::ConcreteInputController::InputController");
    return $self;
}

=head1 METHODS

=over 10

=item $plugin->_init(%args);

Private method. This method is called by the new method during object
instantiation (see the INSTANTIATION process). The method removes any
of the arguments required by the object from the %args hash and
returns it.

See the INSTANTIATION section for information on how to use this
method in a derived class.

=cut

sub _init {
    my ($self,%args) = @_;
    foreach my $arg (keys(%args)) {
        $self->{"_".$arg} = delete $args{$arg}
          if exists $_attributes{$arg};
    }

    ## Check for required attributes.
    foreach my $requiredArg (qw//) {
        die "Error: argument '$requiredArg' is required"
          unless $self->{"_".$requiredArg};
    }

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

=item $plugin->getInputController()

Returns the InputController object being worked on by this option.

=cut

foreach my $attName (keys(%_attributes)) {
    no strict 'refs';
    *{__PACKAGE__ . "::get\u$attName"} = sub { $_[0]->{"_".$attName} }
}

=item $plugin->run()

Implemented method from APE::ControllerPlugin class. Creates
Requirement objects to represent each of the unique in entities of the
arraying process represented by this objects controller attribute
object (an
APE::InputControllerFactory::ConcreteInputController::InputController
object).

=cut

sub run {
    my $plugin = shift;
    ## Self becomes this options InputController object.
    my $self = $plugin->getController();
    return if $self->hasRequirements();
    my $atomicProcessContainer = $self->getAtomicProcessContainer;
    my $arrayingEntityList = $atomicProcessContainer->getArrayingEntityList();
    my %lookupPlate  =();
    my $indexPlate   =-1;
    my @storePlate   =();
    my $description;
    my $count = 1;
    ## Create Requirements for each inConcreteEntity.
    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();
            ## Create a new Requirement per in concrete entity id.
            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);
                $count++;
            }else{
                ## Push the ArrayingEntity index to the Requirement object.
#my $res = $storePlate[$lookupPlate{$inConcreteEntity}]->pushIndexes($aei,$api);
                my $linkCount = $storePlate[$lookupPlate{$inConcreteEntity}]->attach($atomicProcess);
                print "Link count: $linkCount\n";
            }
        }
    }

    my $requirementContainer =
      new APE::InputControllerFactory::ConcreteInputController::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);
}

1;

=back

=head1 ALSO SEE

APE::InputControllerFactory::ConcreteInputController::InputController

=head1 AUTHOR

Simon Holroyd <holroyd@sanger.ac.uk>

=cut

