The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
package WWW::Google::Contacts::Roles::List;
{
    $WWW::Google::Contacts::Roles::List::VERSION = '0.38';
}

use Moose::Role;
use MooseX::Types::Moose qw( ArrayRef Int );
use Carp qw( croak );
use URI::Escape;
use Perl6::Junction qw( any );
use WWW::Google::Contacts::Data;

requires 'baseurl', 'element_class';

has elements => (
    isa        => ArrayRef,
    is         => 'rw',
    lazy_build => 1,
);

has server => (
    is       => 'ro',
    required => 1,
);

has pointer => (
    isa      => Int,
    is       => 'rw',
    default  => 0,
    init_arg => undef,
);

sub search {
    my ( $self, $search ) = @_;

    my $class = $self->element_class;

# TODO - make something clever to match XML keys without having to bless all the objects for comparison
# this could be a start;
#
#my $element = $class->new( server => $self->server );
#my $search_params = [];
#foreach my $key ( keys %{ $search } ) {
#    my $xml_key = $element->get_xml_key( $key );
#    if ( $xml_key ) {
#        push @{ $search_params },
#            {
#                xml_key => $xml_key,
#                value   => $search->{ $key },
#            };
#    }
#    else {
#        croak "Can't find XML key for [$key]";
#    }
#}

    # This doesn't scale well.... SLOW
    my $to_ret = [];
  ELEM:
    foreach my $elem ( @{ $self->elements } ) {
        my $obj = $class->new( server => $self->server );
        $obj->set_from_server($elem);
        foreach my $key ( keys %{$search} ) {
            next ELEM unless ( defined $obj->$key );
            if ( ref( $obj->$key ) and ref( $obj->$key ) eq 'ARRAY' ) {
                my $search_field = $obj->$key->[0]->search_field;
                next ELEM unless ( defined $search_field );
                my @values = map { $_->$search_field } @{ $obj->$key };
                my $search_key = $search->{$key};

                # protocol might not match, that doesn't matter
                if ( $search_key =~ s{^http.?:}{} ) {
                    $_ =~ s{^http.?:}{} foreach (@values);
                }
                next ELEM unless ( any(@values) eq $search_key );
            }
            else {
                my $search_key = $search->{$key};
                my $obj_key    = $obj->$key;

                # protocol might not match, that doesn't matter
                if ( $search_key =~ s{^http.?:}{} ) {
                    $obj_key =~ s{^http.?:}{};
                }
                next ELEM unless ( $obj_key eq $search_key );
            }
        }
        push @{$to_ret}, $obj;
    }
    return wantarray ? @{$to_ret} : $to_ret;
}

sub next {
    my $self = shift;
    return undef unless ( $self->elements->[ $self->pointer ] );
    my $next = $self->elements->[ $self->pointer ];
    $self->pointer( $self->pointer + 1 );
    my $class = $self->element_class;
    return $class->new( server => $self->server )->set_from_server($next);
}

sub _build_elements {
    my $self = shift;

    my $args = {};
    $args->{'alt'} = 'atom';    # must be atom
    $args->{'max-results'} ||= 9999;
    my $group = delete $args->{group} || 'full';
    my $url = sprintf( '%s/%s?v=3.0', $self->baseurl, uri_escape($group) );
    foreach my $key ( keys %$args ) {
        $url .= '&' . uri_escape($key) . '=' . uri_escape( $args->{$key} );
    }
    my $res     = $self->server->get($url);
    my $content = $res->content;
    my $data    = WWW::Google::Contacts::Data->decode_xml($content);
    my $array   = $data->{entry} || [];

    if ( ref($array) eq 'HASH' ) {
        $array = [$array];
    }

# ..lots of overhead to bless them all now.
#my $class = $self->element_class;
#$array = [ map { $class->new( server => $self->server )->set_from_server( $_ ) } @{ $array } ];
    return $array;
}

1;