#!/usr/bin/perl -w
#
# Stock Quote Module
#
# Currently actually a Yahoo Stock Quote Module; if I feel the urge I
# may build a module tree instead. Based on previous Stock Exchange
# efforts.
#
# Waider 07/06/2003
package Stock;

use strict;

use LWP::UserAgent;
use HTML::TokeParser;
use Date::Parse;

my $CGISITE = 'http://finance.yahoo.com';
my $CGIROOT = $CGISITE . '/q?s=';
my $ua;

# XXX this only covers the ones I'm interested in
my %currencies = (
   'L' => 'GBP',
   'OL' => 'NOK',
  );

sub new {
  my $self = shift;

  my %options = @_;

  my $ua = new LWP::UserAgent;
  $ua->agent( "GeekToy/0.1 " . $ua->agent );
  $ua->env_proxy();

  my $obj = bless {}, $self;

  $obj->{'ua'} = $ua;

  $obj;
}

sub quote {
  my $self = shift;
  my ( $ticker, $exchange ) = ( $self->{'ticker'}, $self->{'exchange'});
  my ( $date, $value, $currency );
  $ticker ||= shift;
  $exchange ||= shift;
  $exchange ||= "";

  die "No ticker specified" unless $ticker;

  if ( defined( $exchange ) and defined( $currencies{$exchange})) {
    $currency = $currencies{$exchange};
  } else {
    $currency = "USD";
  }

  $exchange = ".$exchange" if $exchange;

  my $url = $CGIROOT . $ticker . $exchange;
  $ENV{DEBUG} and print STDERR "fetching $url...\n";
 grabpage:
  my $req = new HTTP::Request
    GET => $url;

  my $res = $self->{ua}->request( $req );

  if ( $res->is_success ) {
    my $content = $res->content;

    if ( $content =~
         /is no longer valid. It has changed to <a href="([^"]+)"/ ) {
        my $newurl = $CGISITE . $1 . "&s=";
        die "loop! " if $newurl eq $url;
        $url = $newurl;
        goto grabpage;
    }

    if ( $content =~
         /Invalid Ticker Symbol/ ) {
        die "$ticker is not a valid symbol for $exchange\n";
    }

    my $p = new HTML::TokeParser( \$content );
    my $foundit = 0;
    while ( my $token = $p->get_tag ) {
      #   last if $p->get_trimmed_text eq "$ticker$exchange";
      # 2003 09 05
        if ( $p->get_trimmed_text eq "Last Trade:" ) {
            $foundit = 1;
            last;
        }
    }

    die "Failed to locate sentinel" unless $foundit;

    # value
    $p->get_tag( "b" );
    $value = $p->get_trimmed_text( "/b" );
    print STDERR "price: $currency $value\n" if $ENV{DEBUG};

    $p->get_tag( "tr" );
    $p->get_tag( "th", "td" ); # Trade Time:
    if (( my $caption = $p->get_trimmed_text ) ne "Trade Time:" ) {
        if ( $ENV{DEBUG} and open( DUMP, ">$ticker.$exchange.html" )) {
            print DUMP $content;
        }
        die "Page format ($url) changed, found $caption\nStopped";
    }

    # date
    $p->get_tag( "td" );
    $date = $p->get_trimmed_text;

    # unix-time the date
    my $udate = str2time( $date );
    $udate ||= time;
    # if it's just a day spec then tweak it
    if ( $date =~ /jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec/i ) {
      $udate += 60 * 60 * 24;
    }
    $date = $udate;
  } else {
    # HTML retrieve failed
    return;
  }

  return { 'date' => $date, 'value' => $value, 'currency' => $currency };
}

1;

