#!/usr/bin/perl -w
#
#    Copyright (C) 2003, Rob Clark <finiteautomaton@users.sourceforge.net>
#
#    This program is free software; you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation; either version 2 of the License, or
#    (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with this program; if not, write to the Free Software
#    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#    02111-1307, USA
#
#
# This code derived from Padzensky's work on package Finance::YahooQuote,
# but extends its capabilites to encompas a greater number of data sources.
#
# 

require 5.005;

use strict;

package Finance::Quote::BMONesbittBurns;

use vars qw($VERSION $BMO_URL); 

use LWP::UserAgent;
use HTTP::Request::Common;
use HTML::TableExtract;

$VERSION = '0.9';

# URLs of where to obtain information
my $BMO_URL = 'http://bmonesbittburns.com/QuickQuote/QuickQuote.asp?Symbol=';

sub methods { return (bmonesbittburns => \&bmonesbittburns) } 
sub labels  { return (bmonesbittburns => [qw/name last p_change bid offer open high low volume currency method exchange date time/]) };
			
# ==============================================================================
sub bmonesbittburns {
    my $quoter = shift;
    my @symbols = @_;
    return unless @symbols;

    my($url, $reply, $te);
    my(%info);
    
    my $ua = $quoter->user_agent; 	# user_agent
    $url = $BMO_URL;    		    # base url 
    
    foreach my $symbol (@symbols) {
        $reply = $ua->request(GET $url.join('',$symbol)); 
        
        if ($reply->is_success) { 
        
            #print STDERR $reply->content,"\n";
            
            $te = new HTML::TableExtract( depth => 1);

            # parse table
            $te->parse($reply->content); 
            
            # check for a page without tables.
            # This gets returned when a bad symbol name is given.
            unless ( $te->tables )  {
                $info {$symbol,"succes"} = 0;
                $info {$symbol,"errormsg"} = "Fund name $symbol not found, bad symbol name";
                next;
            } 
            
            # extract table contents
            my($ignored, $stock_info, $data) = $te->table_states;
            my(@rows) = $data->rows;

            unless ($stock_info && $rows[0][1] !~ /Error/) {
                $info {$symbol,"success"} = 0;
                $info {$symbol,"errormsg"} = "Parse error";
                next;
            }

            my(@info_row) = $stock_info->rows;
            if ( $info_row[0][2] !~ /\w/ ) {
                # No text name associated with the stock, use the symbol name
                $info {$symbol, "name"} = $symbol;
            }
            else {
                $info {$symbol, "name"} = $info_row[0][2];
            }
            # Strip leading and trailing spaces
            $info {$symbol, "name"} =~ s/^\s*//;
            $info {$symbol, "name"} =~ s/\s*$//;

            $info {$symbol, "success"} = 1;
            $info {$symbol, "exchange"} = "BMO Nesbitt Burns";
            $info {$symbol, "method"} = "bmonesbittburns";
            
            ($info {$symbol, "last"} = $rows[1][2]) =~ s/\s*//g; # Remove spaces
            ($info {$symbol, "bid"} = $rows[4][2]) =~ s/\s*//g; 
            ($info {$symbol, "offer"} = $rows[4][5]) =~ s/\s*//g;
            ($info {$symbol, "high"} = $rows[7][2]) =~ s/\s*//g; 
            ($info {$symbol, "low"} = $rows[6][5]) =~ s/\s*//g;
            ($info {$symbol, "open"} = $rows[6][2]) =~ s/\s*//g;
            ($info {$symbol, "p_change"} = $rows[2][5]) =~ s/\s*//g;
            ($info {$symbol, "volume"} = $rows[6][5]) =~ s/\s*//g;

            # We'll use today's date as default, in case we only have
	    # a time.
            my($month, $day, $year) = (localtime())[4,3,5];
	    $month++;
	    $year += 1900;

            my($dt) = $rows[3][2];
            if ($dt =~ /:/) {
                ($info {$symbol, "time"} = "$dt:00") =~ s/\s*//g; 
                $info {$symbol, "date"} = "$month/$day/$year";
            }
            else {
                ($day, $month) = ($dt =~ /([0-9]+)\/([0-9]+)/);
                ($info {$symbol, "date"} = "$month/$day/$year") =~ s/\s*//g;
                $info {$symbol, "time"} = "00:00:00";
            }

            # If this was a US exchange, currency in US$
            if ($symbol =~ /,X$/) {
                $info {$symbol, "currency"} = "USD";
            }
            else {
                $info {$symbol, "currency"} = "CAD";
            }
            $info {$symbol, "success"} = 1; 

            # Walk through our fields and remove high-ascii
	    # characters which may have snuck in.
	    
	    foreach (@{labels()}) {
                $info{$symbol,$_} =~ tr/\200-\377//d;
	    }

        } else {
            $info {$symbol, "success"} = 0;
            $info {$symbol, "errormsg"} = "Error retreiving $symbol ";
        }
    }

    return %info if wantarray;
    return \%info;
} 

1; 

=head1 NAME

Finance::Quote::BMONesbittBurns Obtain quotes from the BMO NesbittBurns site

=head1 SYNOPSIS

    use Finance::Quote;

    $q = Finance::Quote->new;

    %info = Finance::Quote->fetch("bmonesbittburns","NT,X");

=head1 DESCRIPTION

This module fetches information from the "BMO NesbittBurns Quitre Qote" site.
Most Canadiam and US stocks as well as Canadian Mutual Funds are available.

The symbolm representing a stock or mutual fund is composed of the stock
symbol, a comma, and then the index or type. The following indexes and types
are supported:

  T    Toronto Stock Exchange
  MF   Canadian Mutaul Fund
  V    Canadian venture Exchange
  I    Index
  X    U.S Stocks (most exchanges)

This module is loaded by default on a Finance::Quote object. It's 
also possible to load it explicity by placing "BMONesbittBurns" in the argument
list to Finance::Quote->new().

Information obtained by this module may be covered by BMO Nesbitt Burns 
terms and conditions. See http://bmonesbittburns.com/ for details.

=head1 LABELS RETURNED

The following labels may be returned by Finance::Quote::BMONesbittBurns :
name, last, date, p_change, bid, offer, open, high, low,  
volume, currency, method, exchange, time, date.

=head1 SEE ALSO

BMO Nesbitt-Burns  http://bmonesbittburns.com/QuickQuote/QuickQuote.asp
=cut

