package Finance::Bank::AllianceAndLeicester;
use strict;
use Carp;
our $VERSION = '1.00';

use WWW::Mechanize;
use HTML::TokeParser;

sub check_balance {
    my ($class, %opts) = @_;
    my @accounts;
    croak 'Must provide a Customer ID'	       unless exists $opts{customerid};
    croak 'Must provide Memorable information' unless exists $opts{memorable};
    croak 'Must provide a Unique Phrase'       unless exists $opts{phrase};
    croak 'Must provide a PIN Code'            unless exists $opts{pin};
    croak 'Customer ID should be 12 digits'    unless $opts{customerid} =~ /^\d{12}$/;
    croak 'PIN Code should be 5 digits'        unless $opts{pin} =~ /^\d{5}$/;

    my $self = bless { %opts }, $class;
    
    # Submit Customer ID
    my $agent = WWW::Mechanize->new();
    $agent->get("https://www.mybank.alliance-leicester.co.uk/login/checkLogin.asp?txtCustomerID=$opts{customerid}");

    # Submit the memorable information
    $agent->get("https://www.mybank.alliance-leicester.co.uk/login/checkPM5.asp?txtMemDetail=$opts{memorable}");

    # Check we have got the correct Unique Phrase
    my $content = $agent->content;
    my $stream = HTML::TokeParser->new(\$content) or die "$!";
    for (my $a=0; $a<5; $a++) {
        $stream->get_tag("span");
    }
    my $phrase = $stream->get_trimmed_text('/span');
   
    croak "Unique Phrase Mismatch." unless(lc($phrase) eq lc($opts{phrase}));
    
    # Submit the PIN Number
    $agent->get("https://www.mybank.alliance-leicester.co.uk/login/checkPM4point1.asp?txtCustomerPIN=$opts{pin}");

    # Check for login errors
    $content = $agent->content;
    $stream = HTML::TokeParser->new(\$content) or die "$!";
    while(my $token = $stream->get_tag('div')) {
        if($token->[1]{'id'} eq 'error') {
	    my $error = $stream->get_trimmed_text('/div');
            croak "Error During Login: $error\n";
            last;
        }
    }

    # save this data to parse later
    $content = $agent->{content};

    # We have the data we need, so lets logout
    $agent->get("https://www.mybank.alliance-leicester.co.uk/login/calls/logout.asp");

    # Begin parsing the HTML
    $stream = HTML::TokeParser->new(\$content) or die "$!";
    $stream->get_tag("tr");

    while (my $token = $stream->get_tag('tr')) {

        my($accountbalance, $accountname, 
            $accountoverdraft, $accountnumber, $accountavailable);

	# Get the Account Name and number
	$token = $stream->get_tag('td');
	$accountname = $stream->get_trimmed_text('/td');
	$accountname =~ s/\s(\d+)$//;
	$accountnumber = $1;

	# Get the balance
	$stream->get_tag('td');
	$accountbalance = $stream->get_trimmed_text('/td');

        # Get overdraft
	$stream->get_tag('td');
	$accountoverdraft = $stream->get_trimmed_text('/td');

	# Get Available Balance
	$stream->get_tag('td');
        $accountavailable = $stream->get_trimmed_text('/td');

	# Strip pounds signs from balances
	$accountbalance   =~ s/^\x{00A3}//;
	$accountoverdraft =~ s/^\x{00A3}//;
        $accountavailable =~ s/^\x{00A3}//;

	# Strip Comma ',' from balances
	$accountbalance   =~ s/\,//g;
        $accountoverdraft =~ s/\,//g;
        $accountavailable =~ s/\,//g;
                   
        # Add to list of accounts to return
        push @accounts, {
            balance           => $accountbalance,
            name              => $accountname,
            overdraft         => $accountoverdraft,
	    account           => $accountnumber,
            available_balance => $accountavailable
        };
    }

    # Return the list of accounts
    return @accounts;
}

1;
__END__
# Documentation is below here

=head1 NAME

Finance::Bank::AllianceAndLeicester - Check your Alliance & Leicester bank accounts from Perl

=head1 SYNOPSIS

  use Finance::Bank::AllianceAndLeicester;
  my @accounts = Finance::Bank::AllianceAndLeicester->check_balance(
      customerid  => '012345678912',
      pin         => '12345',
      memorable   => 'mybirthplace',
      phrase      => 'my unique phrase'
  );

  foreach (@accounts) {
      printf "%12s(%20s):  GBP %8.2f (Overdraft: GBP %8.2f Available: GBP %8.2f)\n",
        $_->{account}, $_->{name}, $_->{balance}, $_->{overdraft}, $_->{available_balance} ;
  }

=head1 DESCRIPTION

This module provides a rudimentary interface to the Alliance & Leicester
online banking system at C<https://www.mybank.alliance-leicester.co.uk/>. 

=head1 DEPENDENCIES

You will need either C<Crypt::SSLeay> or C<IO::Socket::SSL> installed 
for HTTPS support to work with LWP.  This module also depends on 
C<WWW::Mechanize> and C<HTML::TokeParser> for screen-scraping.

=head1 CLASS METHODS

=over

=item B<check_balance>

    check_balance ( customerid => $c, 
                    pin        => $p, 
                    memorable  => $m, 
                    phrase     => $s 
    )

Return an array of account hashes, one for each of your bank accounts.

=item customerid

The Customer ID is 12 Digit number supplied with your account

=item pin

Your 5 Digit PIN Number

=item memorable

This is your memorable information. Such as your birth place. 
This is asked for when you first login to your bank account.

=item phrase

Your unique phrase. This is used to make sure we are connecting to
the Alliance & Leicester website and that the connection has not been hijacked.

This is created when you fisrt sign up your account, and can be changed on the 
Alliance & Leicester internet banking website.

=back

=head1 ACCOUNT HASH KEYS 

    $ac->account
    $ac->name
    $ac->balance
    $ac->overdraft
    $ac->available_balance
 
Return the account number, account name (eg. 'PlusSaver'), account
balance, account overdraft limit and available balance as a signed floating point value.

=head1 WARNING

This warning is from Simon Cozens' C<Finance::Bank::LloydsTSB>, and seems
just as apt here.

This is code for B<online banking>, and that means B<your money>, and
that means B<BE CAREFUL>. You are encouraged, nay, expected, to audit
the source of this module yourself to reassure yourself that I am not
doing anything untoward with your banking data. This software is useful
to me, but is provided under B<NO GUARANTEE>, explicit or implied.

=head1 THANKS

Simon Cozens for C<Finance::Bank::LloydsTSB> and Chris Ball for Finance::Bank::HSBC, 
upon which most of this code is based. 
Andy Lester (and Skud, by continuation) for WWW::Mechanize, Gisle Aas for HTML::TokeParser.

=head1 CHANGELOG

=over

=item Version 1.01 - 04/10/2006 - Ian Bissett <ian@tekuiti.co.uk>

* Strip commas from balances.

=back

=head1 AUTHOR

Ian Bissett C<ian.bissett@tekuiti.co.uk>

=cut

