#
# Copyright (c) 2014-2015 Christian Jaeger, copying@christianjaeger.ch
#
# This is free software, offered under either the same terms as perl 5
# or the terms of the Artistic License version 2 or the terms of the
# MIT License (Expat version). See the file COPYING.md that came
# bundled with this file.
#

=head1 NAME

FP::OrderedCollection

=head1 SYNOPSIS

=head1 DESCRIPTION


=head1 NOTE

This is alpha software! Read the package README.

=cut


package FP::OrderedCollection;

use strict; use warnings; use warnings FATAL => 'uninitialized';

use Chj::TEST;
use FP::Predicates;
use FP::Stream qw(subarray_to_stream subarray_to_stream_reverse  stream_to_array);
use FP::Lazy;
use FP::List;

use FP::Struct
  [[\&is_array, "array"],
   [\&is_hash, "hash"]];


# Unsafe: assumes that the given array is never mutated after
# constructing the OrderedCollection
sub unsafe_new_from_array {
    my $cl=shift;
    @_==1 or die "wrong number of arguments";
    my ($a)=@_;
    my %h;
    for my $i (0..$#$a) {
        $h{$$a[$i]}= $i;
    }
    $cl->new ($a,\%h)
}

sub new_from_array {
    my $cl=shift;
    @_==1 or die "wrong number of arguments";
    my ($a)=@_;
    $cl->unsafe_new_from_array ([@$a])
}

sub new_from_values {
    my $cl=shift;
    $cl->unsafe_new_from_array([@_])
}

sub contains {
    my $s=shift;
    @_==1 or die "wrong number of arguments";
    exists $$s{hash}{$_[0]}
}

sub maybe_position {
    my $s=shift;
    @_==1 or die "wrong number of arguments";
    $$s{hash}{$_[0]}
}

sub perhaps_following {
    my $s=shift;
    my $i= $s->maybe_position(@_) // return;
    subarray_to_stream($$s{array}, $i+1)
}

sub perhaps_previous {
    my $s=shift;
    my $i= $s->maybe_position(@_) // return;
    subarray_to_stream_reverse($$s{array}, $i-1)
}

sub maybe_next {
    my $s=shift;
    my ($l)= $s->perhaps_following (@_) or return undef;
    $l= force ($l);
    is_null $l ? undef : car $l
}

sub maybe_prev {
    my $s=shift;
    my ($l)= $s->perhaps_previous (@_) or return undef;
    $l= force ($l);
    is_null $l ? undef : car $l
}


TEST {
    our $c= FP::OrderedCollection->new_from_values(qw(a b c f));
    $c->contains ("a")
} 1;

TEST {
    our $c->contains ("q")
} '';

TEST {
    our $c->maybe_position ("1")
} undef;

TEST {
    our $c->maybe_position ("f")
} 3;

TEST { [ our $c->perhaps_following ("xx")] }
  [];
TEST { stream_to_array( our $c->perhaps_following ("c")) }
  [ 'f' ];
TEST { stream_to_array( our $c->perhaps_following ("b")) }
  [ 'c', 'f' ];
TEST { stream_to_array( our $c->perhaps_previous ("c")) }
  [ 'b', 'a' ];

TEST { our $c->maybe_prev("c") }
  'b';
TEST { our $c->maybe_prev("a") }
  undef;
TEST { our $c->maybe_prev("xx") }
  undef;
TEST { our $c->maybe_next("a") }
  'b';
TEST { our $c->maybe_next("f") }
  undef;


_END_
