The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
package Games::Perlwar::Array;

our $VERSION = '0.03';

use strict;
use warnings;
use Carp;
use utf8;

use Class::Std;
use Games::Perlwar::Cell;

my %cells_of          ;
my %size_of           : ATTR( :name<size> :default<100> );

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

sub START {
    my( $self, $id ) = @_;

    my @cells;

    push @cells, Games::Perlwar::Cell->new for 1..$size_of{ $id };

    $cells_of{ $id } = \@cells;
}

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

sub load_from_xml {
    my( $self, $xml ) = @_;
    my $id = ident $self;

    for my $cell ( $xml->findnodes( '//agent' ) ) {
        my $position = $cell->findvalue( '@position' );
		my $owner = $cell->findvalue( '@owner' );
		my $facade = 
            $cell->findvalue( '@facade' );
		my $code = $cell->findvalue( "text()" );
        utf8::decode( $code );

        $self->set_cell( $position => {
                owner => $owner,
                code => $code,
                facade => $facade,
        } );
    }
}

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

sub set_cell {
    my( $self, $position, $ref_args ) = @_;
    my $id = ident $self;

    $self->get_cell( $position )->set( $ref_args );
}

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

sub clear {
    my $self = shift;

    $_->clear for @{$cells_of{ ident $self }};
}
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

sub run_cell {
    my( $self, $cell_id, $vars_ref ) = @_;
    my %vars;
    %vars = %$vars_ref if $vars_ref;

    my $cell = $self->get_cell( $cell_id );

    return $cell->run({
        %vars,
        '@_' => [ $self->get_cells_code( $cell_id ) ],
        '@o' => [ $self->get_facades( $cell_id ) ],
        });
   
    
}

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

sub get_cell {
    my( $self, $position ) = @_;
    my $id = ident $self;

    $position %= $size_of{ $id };

    return $cells_of{ $id }[ $position ];
}

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

sub get_cells_code {
    my( $self, $base ) = @_;
    my $id = ident $self;

    my $last_index = $size_of{ $id } - 1;
    return map { $_->get_code  } 
               @{$cells_of{ $id }}[ $base..$last_index, 0..($base-1) ];

}
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

sub get_facades {
    my( $self, $base ) = @_;
    my $id = ident $self;

    my $last_index = $size_of{ $id } - 1;
    return map { $_->get_facade } 
               @{$cells_of{ $id }}[ $base..$last_index, 0..($base-1) ];
}

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

sub census {
    my ( $self ) = @_;
    my $id = ident $self;

    my %census;
    my @cells = @{ $cells_of{ $id } };

    for my $cell ( @cells ) {
        my $owner = $cell->get_owner;
        $census{ $owner }++ if $owner;
    }

    return %census;
}

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

sub empty_cells {
    my $self = shift;
    my $id = ident $self;
    
    return grep { $cells_of{$id}[$_]->is_empty } 0..$size_of{ $id }-1;
}

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

sub cells_belonging_to {
    my( $self, $player ) = @_;
    my $id = ident $self;

    return grep { $_->get_owner eq $player } @{ $cells_of{$id} };
}
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

sub cell { $_[0]->get_cell( $_[1] ); }

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

sub reset_operational {
    my( $self ) = @_;
    my $id = ident $self;

    $_->set_operational( 1 ) for @{ $cells_of{ $id } };
}

sub save_as_xml {
    my( $self, $writer ) = @_;
    my $id = ident $self;
        
	$writer->startTag( 'theArray', size => $size_of{ $id } );
    for my $id ( 0..@{$cells_of{ $id}} ) {
        my $cell = $self->cell( $id );
        next if $cell->is_empty;

        my $owner = $cell->get_owner;
        my $facade = $cell->get_facade;

        $facade = undef if $facade eq $owner;

        $writer->dataElement( 'agent', $cell->get_code,
                                        position => $id, 
                                        owner => $owner,
                                        ( facade => $facade ) x !!$facade,
                            );
    }
    $writer->endTag;
}   

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

1;