use strict;
use warnings;

use lib qw(../../..);

=encoding utf8

=head1 NAME

    Algorithm::Evolutionary::Individual::String - A character string to be evolved. Useful mainly in word games

=head1 SYNOPSIS

    use Algorithm::Evolutionary::Individual::String;

    my $indi = new Algorithm::Evolutionary::Individual::String ['a'..'z'], 10;
                                   # Build random bitstring with length 10

    my $indi3 = new Algorithm::Evolutionary::Individual::String;
    $indi3->set( { length => 20, 
		   chars => ['A'..'Z'] } );   #Sets values, but does not build the string
    $indi3->randomize(); #Creates a random bitstring with length as above
    print $indi3->Atom( 7 );       #Returns the value of the 7th character
    $indi3->Atom( 3, 'Q' );       #Sets the value

    $indi3->addAtom( 'K' ); #Adds a new character to the bitstring at the end

    my $indi4 = Algorithm::Evolutionary::Individual::String->fromString( 'esto es un string');   #Creates an individual from that string

    my $indi5 = $indi4->clone(); #Creates a copy of the individual

    my @array = qw( a x q W z ñ); #Tie a String individual
    tie my @vector, 'Algorithm::Evolutionary::Individual::String', @array;
    print tied( @vector )->asXML();
    
    print $indi3->as_string(); #Prints the individual

=head1 Base Class

L<Algorithm::Evolutionary::Individual::Base>

=head1 DESCRIPTION

String Individual for a evolutionary algorithm. Contains methods to handle strings 
easily. It is also TIEd so that strings can be handled as arrays.

=head1 METHODS

=cut

package Algorithm::Evolutionary::Individual::String;

use Carp;

our $VERSION =   '3.6';

use base 'Algorithm::Evolutionary::Individual::Base';

use constant MY_OPERATORS => qw(Algorithm::Evolutionary::Op::Crossover 
				Algorithm::Evolutionary::Op::QuadXOver
				Algorithm::Evolutionary::Op::StringRand
				Algorithm::Evolutionary::Op::Permutation	
				Algorithm::Evolutionary::Op::IncMutation
				Algorithm::Evolutionary::Op::ChangeLengthMutation );

=head2 new

Creates a new random string, with fixed initial length, and uniform
distribution of characters along the character class that is
defined. However, this character class is just used to generate new
individuals and in mutation operators, and the validity is not
enforced unless the client class does it

=cut

sub new {
  my $class = shift; 
  my $self = Algorithm::Evolutionary::Individual::Base::new( $class );
  $self->{'_chars'} = shift || ['a'..'z'];
  $self->{'_length'} = shift || 10;
  $self->randomize();
  return $self;
}

sub TIEARRAY {
  my $class = shift; 
  my $self = { _str => join("",@_),
               _length => scalar( @_ ),
               _fitness => undef };
  bless $self, $class;
  return $self;
}

=head2 randomize

Assigns random values to the elements

=cut

sub randomize {
  my $self = shift; 
  $self->{'_str'} = ''; # Reset string
  for ( my $i = 0; $i <  $self->{'_length'}; $i ++ ) {
	$self->{'_str'} .= $self->{'_chars'}[ rand( @{$self->{'_chars'}} ) ];
  }
}

=head2 addAtom

Adds an atom at the end

=cut

sub addAtom{
  my $self = shift;
  my $atom = shift;
  $self->{_str}.= $atom;
}

=head2 fromString

Similar to a copy ctor; creates a bitstring individual from a string. Will be deprecated soon

=cut

sub fromString  {
  my $class = shift; 
  my $str = shift;
  my $self = Algorithm::Evolutionary::Individual::Base::new( $class );
  $self->{_str} =  $str;
  my %chars;
  map ( $chars{$_} = 1, split(//,$str) );
  my @chars = keys %chars; 
  $self->{_length} = length( $str  );
  $self->{'_chars'} = \@chars;
  return $self;
}

=head2 from_string

Similar to a copy ctor; creates a bitstring individual from a string. 

=cut

sub from_string  {
  my $class = shift; 
  my $chars = shift;
  my $str = shift;
  my $self = Algorithm::Evolutionary::Individual::Base::new( $class );
  $self->{'_chars'} = $chars;
  $self->{'_str'} =  $str;
  $self->{'_length'} = length( $str  );
  return $self;
}

=head2 clone

Similar to a copy ctor: creates a new individual from another one

=cut

sub clone {
  my $indi = shift || croak "Indi to clone missing ";
  my $self = { '_fitness' => undef };
  bless $self, ref $indi;
  for ( qw( _chars _str _length)  ) {
	$self->{ $_ } = $indi->{$_};
  }
  return $self;
}


=head2 asString

Prints it

=cut

sub asString {
  my $self = shift;
  my $str = $self->{_str} . " -> ";
  if ( defined $self->{_fitness} ) {
	$str .=$self->{_fitness};
  }
  return $str;
}

=head2 Atom

Sets or gets the value of the n-th character in the string. Counting
starts at 0, as usual in Perl arrays.

=cut

sub Atom {
  my $self = shift;
  my $index = shift;
  if ( @_ ) {
    substr( $self->{_str}, $index, 1 ) = substr(shift,0,1);
  } else {
    substr( $self->{_str}, $index, 1 );
  }
}

=head2 TIE methods

String implements FETCH, STORE, PUSH and the rest, so an String
can be tied to an array and used as such.

=cut

sub FETCH {
  my $self = shift;
  return $self->Atom( @_ );
}

sub STORE {
  my $self = shift;
  $self->Atom( @_ );
}

sub PUSH {
  my $self = shift;
  $self->{_str}.= join("", @_ );
}

sub UNSHIFT {
  my $self = shift;
  $self->{_str} = join("", @_ ).$self->{_str} ;
}

sub POP {
  my $self = shift;
  my $pop = substr( $self->{_str}, length( $self->{_str} )-1, 1 );
  substr( $self->{_str}, length( $self->{_str} ) -1, 1 ) = ''; 
  return $pop;
}

sub SHIFT {
  my $self = shift;
  my $shift = substr( $self->{_str}, 0, 1 );
  substr( $self->{_str}, 0, 1 ) = ''; 
  return $shift;
}

sub SPLICE {
  my $self = shift;
  my $offset = shift;
  my $length = shift || length( $self->{'_str'} - $offset );
  my $sub_string =  substr( $self->{_str}, $offset, $length );
#  if ( @_ ) {
    substr( $self->{_str}, $offset, $length ) = join("", @_ );
#  } 
  return split(//,$sub_string);
}

sub FETCHSIZE {
  my $self = shift;
  return length( $self->{_str} );
}

=head2 size()

Returns length of the string that stores the info; overloads abstract base method. 

=cut 

sub size {
  my $self = shift;
  return length($self->{_str}); #Solves ambiguity
}

=head2 as_string() 
    
    Returns the string used as internal representation

=cut

sub as_string {
    my $self = shift;
    return $self->{_str};
}


=head2 asXML()

Prints it as XML. See L<Algorithm::Evolutionary::XML> for more info on this

=cut

sub asXML {
  my $self = shift;
  my $str = $self->SUPER::asXML();
  my $str2 = "> " .join( "", map( "<atom>$_</atom> ", split( "", $self->{_str} )));
  $str =~ s/\/>/$str2/e ;
  return $str."\n</indi>";
}


=head2 Chrom

Sets or gets the variable that holds the chromosome. Not very nice, and
I would never ever do this in C++

=cut

sub Chrom {
  my $self = shift;
  if ( defined $_[0] ) {
    $self->{_str} = shift;
  }
  return $self->{_str}
}

=head1 Known subclasses

=over 4

=item * 

L<Algorithm::Evolutionary::Individual::BitString|Algorithm::Evolutionary::Individual::BitString>

=back

=head2 Copyright
  
  This file is released under the GPL. See the LICENSE file included in this distribution,
  or go to http://www.fsf.org/licenses/gpl.txt

=cut
