package Weather::OpenWeatherMap::Result::Forecast;
$Weather::OpenWeatherMap::Result::Forecast::VERSION = '0.003001';
use strictures 2;
use Carp;

use Types::Standard      -all;
use List::Objects::Types -all;

use Weather::OpenWeatherMap::Result::Forecast::Day;
use Weather::OpenWeatherMap::Result::Forecast::Hour;

=pod

=for Pod::Coverage lazy_for

=cut

sub lazy_for {
  my $type = shift;
  (
    lazy => 1, is => 'ro', isa => $type,
    ( $type->has_coercion ? (coerce => 1) : () ),
    @_
  )
}

use Moo; 
extends 'Weather::OpenWeatherMap::Result';

has hourly => ( lazy_for Bool,
  builder => sub { shift->request->hourly ? 1 : 0 },
);

has id => ( lazy_for Int,
  builder => sub { shift->data->{city}->{id} },
);

has name => ( lazy_for Str,
  builder => sub { shift->data->{city}->{name} },
);

has country => ( lazy_for Str,
  builder => sub { shift->data->{city}->{country} },
);

has latitude => ( lazy_for StrictNum,
  builder => sub { shift->data->{city}->{coord}->{lat} },
);

has longitude => ( lazy_for StrictNum,
  builder => sub { shift->data->{city}->{coord}->{lon} },
);

has count => ( lazy_for Int,
  builder => sub { shift->data->{cnt} // 0 },
);

has _forecast_list => ( lazy_for ArrayObj,
  builder => sub { 
    my ($self) = @_;
    my @list = @{ $self->data->{list} || [] };
    warn "No items in forecast list (name: @{[$self->name]})"
      unless @list;
    # FIXME test that bad items in @list warn and add nothing
    $self->request->hourly ?
      [ map {;
        ref $_ eq 'HASH' ?
          Weather::OpenWeatherMap::Result::Forecast::Hour->new(%$_)
          : (carp "Expected a HASH but got $_" and ())
      } @list ]
    : [ map {;
      ref $_ eq 'HASH' ?
        Weather::OpenWeatherMap::Result::Forecast::Day->new(%$_)
        : (carp "expected a HASH but got $_" and ())
      } @list ]
  },
);

sub as_array {
  my ($self) = @_;
  $self->_forecast_list->copy
}

=for Pod::Coverage as_list

=cut

{ no warnings 'once'; *as_list = *list }
sub list {
  my ($self) = @_;
  $self->_forecast_list->all
}

sub iter {
  my ($self) = @_;
  $self->_forecast_list->natatime(1)
}


1;

=pod

=head1 NAME

Weather::OpenWeatherMap::Result::Forecast - Weather forecast result

=head1 SYNOPSIS

  # Normally retrieved via Weather::OpenWeatherMap

=head1 DESCRIPTION

This is a subclass of L<Weather::OpenWeatherMap::Result> containing the
result of a completed L<Weather::OpenWeatherMap::Request::Forecast>.

These are normally emitted by a L<Weather::OpenWeatherMap> instance.

=head2 ATTRIBUTES

=head3 hourly

Boolean true if this is an hourly weather report.

=head3 count

The number of forecast days returned by the L<OpenWeatherMap
API|http://www.openweathermap.org/api>.

See L</list> and L</iter>.

=head3 country

The country string.

=head3 id

The L<OpenWeatherMap|http://www.openweathermap.org/> city code.

=head3 latitude

The station's latitude.

=head3 longitude

The station's longitude.

=head3 name

The city name.

=head2 METHODS

=head3 as_array

The full forecast list, as a L<List::Objects::WithUtils::Array>.

See L</list>.

=head3 list

The full forecast list; each item in the list is either a
L<Weather::OpenWeatherMap::Result::Forecast::Day> (by default) or a
L<Weather::OpenWeatherMap::Result::Forecast::Hour> (if L</hourly> is true)
instance:

  for my $day ($result->list) {
    my $date = $day->dt->mdy;
    my $cloudiness = $day->cloud_coverage;
    # ...
  }

See the documentation for
L<Weather::OpenWeatherMap::Result::Forecast::Day> &
L<Weather::OpenWeatherMap::Result::Forecast::Hour>.

=head3 iter

Returns an iterator that, when called, returns the next
L<Weather::OpenWeatherMap::Result::Forecast::Day> or
L<Weather::OpenWeatherMap::Result::Forecast::Hour> instance (or undef when the
list is empty):

  my $iter = $result->iter;
  while (my $day = $iter->()) {
    my $wind = $day->wind_speed_mph;
    # ...
  }

See also: L</list>

=head1 SEE ALSO

L<Weather::OpenWeatherMap::Result>

L<Weather::OpenWeatherMap::Result::Forecast::Block>

L<Weather::OpenWeatherMap::Result::Forecast::Day>

L<Weather::OpenWeatherMap::Result::Forecast::Hour>

L<Weather::OpenWeatherMap::Result::Current>

=head1 AUTHOR

Jon Portnoy <avenj@cobaltirc.org>

=cut
