###########################################
package CachedQuote;
# Cache stock closing prices
# Mike Schilli, 2007 (m@perlmeister.com)
###########################################
use strict;
use warnings;
use Cache::Historical;
use Log::Log4perl qw(:easy);
use Finance::QuoteHist::Yahoo;

###########################################
sub new {
###########################################
  my($class, %options) = @_;

  my $self = {
    file => "/tmp/cached-quote.dat",
    %options,
  };

  $self->{cache} = Cache::Historical->new(
        sqlite_file => $self->{file});

  bless $self, $class;
}

###########################################
sub quote {
###########################################
  my($self, $date, $key) = @_;

  my $quote = $self->{cache}->get(
          $date, $key);

  return $quote if defined $quote;
  $self->quote_refresh( $date, $key );

  return $self->{cache}->get_interpolated(
            $date, $key);
}

###########################################
sub quote_refresh {
###########################################
  my($self, $date, $symbol) = @_;

  my($from, $to) = 
    $self->{cache}->time_range($symbol);

  my $upd = $self->{cache}->
             since_last_update($symbol);

    # Date available, no refresh
  if(defined $to and defined $from and
     $date <= $to and $date >= $from) {
      DEBUG "Date within, no refresh";
      return 1;
  }

  if(defined $date and defined $to and
     defined $upd and $date > $to and
     $upd->delta_days < 1) {
      DEBUG "Date ($date) above cached",
       " range ($from-$to), but cache ",
       "is up-to-date.";
      return 1;
  }

  my $start = $date->clone->subtract(
                            years => 1 );
  if(defined $start and defined $from and
     $start > $from and $to > $start) {
        # no need to refresh old data
      $start = $to;
  }

  $self->quotes_fetch(
    $start,
    DateTime->today(),
    $symbol);
}

###########################################
sub quotes_fetch {
###########################################
  my($self, $start, $end, $symbol) = @_;

  DEBUG "Refreshing $symbol ",
        "($start - $end)";

  my $q = Finance::QuoteHist::Yahoo->new(
    symbols    => [$symbol],
    start_date => date_format($start),
    end_date   => date_format($end),
  );

  foreach my $row ($q->quotes()) {
    my($symbol, $date, $open, $high, $low, 
       $close, $volume) = @$row;

    $self->{cache}->set( dt_parse($date), 
                  $symbol, $close ); 
  }
}

###########################################
sub date_format {
###########################################
  my($dt) = @_;
  return $dt->strftime("%m/%d/%Y");
}

###########################################
sub dt_parse {
###########################################
  my($string) = @_;
  my $fmt = 
      DateTime::Format::Strptime->new(
        pattern => "%Y/%m/%d");
  $fmt->parse_datetime($string);
}

1;
