################################################################## 
## Class Name: OutputController                                 ##
##                                                              ##
## Description: This abstract class represents a concrete output##
##              controller and should be implemented by any     ##
##              output controller class.                        ##
##                                                              ##
## Arguments: None.                                             ##
##                                                              ##
##################################################################
package APE::OutputControllerFactory::ConcreteOutputController::OutputController;

$APE::OutputControllerFactory::ConcreteOutputController::OutputController::VERSION = '0.1';

use strict;
use warnings;
use Carp;

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

{
    my %_attributes = (
		       options    => [],
		       advertised => {}
		       );

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

    
    #################################################################
    ## Constructor method for this object. Returns a new
    ## OutputController 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::OutputControllerFactory::ConcreteOutputController::OutputController'."
	    if $proto eq 
            'APE::OutputControllerFactory::ConcreteOutputController::OutputController';
	
	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) = @_;

	## Set attributes to passed values if present.
	foreach my $attName (keys(%args)) {
	    if(exists($_attributes{$attName})) {
		$object{ $self }->{$attName} = delete $args{$attName};
	    }
	}

	return %args;
    }


    #################################################################
    ## Method to push a new option to the OutputController and to
    ## advertise its existence to the user. Requires a hash - key = the
    ## name of the option value = the code reference to call when the
    ## option is called.
    #################################################################
    sub pushOption {
	my ($self,%options) = @_;
	croak "Error: no new option specified" 
            unless keys %options;
	foreach my $key (keys(%options)) {
	    croak "Error: option value should be a code ".
                "reference to advertise"
		unless ref $options{$key} eq 'CODE';
	    push(@{$object{ $self }->{options}},$key);
	    $object{ $self }->{advertised}{$key} = 
                $options{$key};
	}
    }


    #################################################################
    ## Method to produce the default output behaviour for an
    ## OutputController object. This method is always called but can be
    ## overridden by classes using this class as the base class to
    ## perform other outputting tasks.
    #################################################################
    sub createOutput {
	my ($self,$advertised,$results) = @_;
	croak "Error: advertised option '$advertised' does ".
            "not exist." 
	    unless exists $self->getAdvertised->{$advertised};
	eval { my $anonSub = $self->getAdvertised->{$advertised};
	       $anonSub->($self,$results); };
	croak $@ if $@;
    }
}

1;
