The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
package Template::Flute::Iterator::Cache;

use Moo;
use Types::Standard qw/ArrayRef InstanceOf Int/;

use base 'Template::Flute::Iterator';

=head1 NAME

Template::Flute::Iterator::Cache - Iterator caching class

=head1 DESCRIPTION

This iterator is used for caching another iterator which is used multiple
times in a list. We can safely use reset method on the caching iterator,
but not always on the original iterator.

=head1 ATTRIBUTES

=head2 iterator

Original iterator (required).

=head2 index

Current position.

=head2 data

Cached data.

=head2 filled

Whether cache is filled or not.

=cut

has iterator => (
    isa => InstanceOf ['Template::Flute::Iterator'],
    required => 1,
    is => 'ro',
);

has index => (
    isa => Int,
    default => 0,
    is => 'rwp',
);

has data => (
    isa => ArrayRef,
    is => 'rwp',
    default => sub {[]},
);

has filled => (
    is => 'rwp',
    default => 0,
);

=head1 METHODS

=head2 count

Returns count of (original) iterator.

=cut

sub count {
    return $_[0]->iterator->count;
}

=head2 next

Returns next record, either from original iterator or our cache.

=cut

sub next {
    my ($self, $index, $record);

    $self = shift;
    $index = $self->index;

    if ($self->filled) {
        # grab record from cache
        if ($index < $self->count) {
            $self->_set_index($index + 1);
            return $self->data->[$index];
        }
        return undef;
    }

    # grab record from original iterator and store it
    if ($record = $self->iterator->next) {
        push @{$self->data}, $record;
        $self->_set_index($index + 1);
        return $record;
    }

    $self->_set_filled(1);
    return undef;
}

=head2 reset

Resets the iterator.

=cut

sub reset {
    my $self = shift;

    $self->_set_index(0);
}

=head1 AUTHOR

Stefan Hornburg (Racke), <racke@linuxia.de>

=head1 LICENSE AND COPYRIGHT

Copyright 2014-2016 Stefan Hornburg (Racke) <racke@linuxia.de>.

This program is free software; you can redistribute it and/or modify it
under the terms of either: the GNU General Public License as published
by the Free Software Foundation; or the Artistic License.

See http://dev.perl.org/licenses/ for more information.

=cut

1;