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

use strict;
use warnings;

use base 'Mojo::Base';

__PACKAGE__->attr('elements');

sub new {
    my $self = shift->SUPER::new(@_);

    $self->rewind;

    return $self;
}

sub rewind { shift->{index} = 0 }

sub reverse {
    my $self = shift;

    $self->{elements} = [reverse @{$self->{elements}}];

    return $self;
}

sub size { scalar @{shift->{elements} || []} }

sub first { shift->{elements}->[0] }
sub last  { shift->{elements}->[-1] }

sub current {
    my $self = shift;

    my $index = $self->{index};
    $index-- if $index;

    return $self->{elements}->[$index];
}

sub take_next {
    my $self = shift;

    return unless $self->has_next;

    return $self->{elements}->[$self->{index}];
}

sub take_prev {
    my $self = shift;

    return if $self->{index} < 2;

    return $self->{elements}->[$self->{index} - 2];
}

sub has_next {
    my $self = shift;

    return $self->{index} < $self->size ? 1 : 0;
}

sub has_prev {
    my $self = shift;

    return $self->{index} > 0 ? 1 : 0;
}

sub next {
    my $self   = shift;
    my $length = shift;

    if (!$length) {
        return unless $self->has_next;

        return $self->{elements}->[$self->{index}++];
    }

    my @elements;
    while (my $element = $self->next) {
        push @elements, $element;

        last if --$length <= 0;
    }

    return $self->new(elements => [@elements]);
}

sub prev {
    my $self   = shift;
    my $length = shift;

    if (!$length) {
        return unless $self->has_prev;

        return $self->{elements}->[--$self->{index}];
    }

    return $self->new(elements => []) if $self->{index} == 0;

    $self->{index}--;

    my @elements;
    while (my $element = $self->prev) {
        push @elements, $element;

        last if --$length <= 0;
    }

    return $self->new(elements => [@elements]);
}

1;