package ToyArrayFold;
use Carp;

# A _toy_ helper class to fold an array into what seems to be an
# array of arrays (of arrays, etc), based on a list of the sizes 
# of each dimension.
# Eg, 
#   @array = (1..6);
#   $folded = ToyArrayFold->new_array(\@array, [ 2, 3 ]);
#   dump $folded->[0];    # [ 1 , 2 , 3 ]
#   dump $folded->[1];    # [ 4 , 5 , 6 ]
#   dump $folded->[1][0]; # 4
#   dump $folded->[1][1]; # 5
#   $folded->[1][1] = 50;
#   dump $folded->[1][1]; # 50
#
# [I also have a real version of this class... somewhere...]

sub new_array {
    my $class = shift;
    my @a;
    tie @a, $class, @_;
    return \@a;
}

sub TIEARRAY {
    my($class,$array,$shape,$coors_opt) = @_;
    bless { ARRAY => $array,
            SHAPE => $shape,
            COORS => ($coors_opt || [])
            }, $class;
}
sub FETCH {
    my($self,$index) = @_;
    my $shape = $self->{SHAPE};
    my @coors = @{$self->{COORS}};
    $index += $shape->[@coors] if $index < 0;
    croak "invalid index" if($index < 0 || $index >= $shape->[@coors]);
    push(@coors,$index);
    if(@coors < @$shape) {
        my @a;
        tie @a, ref($self), $self->{ARRAY}, $shape, \@coors;
        return \@a;
    }
    return $self->{ARRAY}->[ $self->_calculate_index(@coors) ];
}
sub STORE {
    my($self,$index,$value) = @_;
    my $shape = $self->{SHAPE};
    my @coors = @{$self->{COORS}};
    $index += $shape->[@coors] if $index < 0;
    croak "invalid index" if($index < 0 || $index >= $shape->[@coors]);
    push(@coors,$index);
    if(@coors < @$shape) {
        die "Multipoint STORE not implemented by this toy.";
    }
    $self->{ARRAY}->[ $self->_calculate_index(@coors) ] = $value;
}
sub FETCHSIZE {
    my($self)= @_;
    my $shape = $self->{SHAPE};
    my @coors = @{$self->{COORS}};
    return $shape->[scalar(@coors)];
}
sub _calculate_index {
    my($self,@coors)= @_;
    my $shape = $self->{SHAPE};
    my @offsets;
    my $step = 1;
    for(my $i=$#$shape; $i>=0; $i--) {
        $offsets[$i] = $step;
        $step *= $shape->[$i];
    }
    my $index = 0;
    for(my $i = 0; $i < @coors; $i++) {
        $index += $offsets[$i] * $coors[$i];
    }
    return $index;
}

1;