#!/usr/bin/env perl
use strict;
use warnings;
use Test::More tests => 96;

use_ok('BankAccount');
can_ok('BankAccount', 'new');

my $acct = BankAccount->new('Paul Lalli', 123456, 50);
isa_ok($acct, 'BankAccount');

can_ok($acct, qw/get_name get_account_num get_balance deposit withdraw/);
is($acct->get_name(), 'Paul Lalli', 'get_name');
cmp_ok($acct->get_account_num(), '==', 123456, 'get_account_num');
cmp_ok($acct->get_balance(), '==', 50, 'get_balance');

$acct->deposit(30);
cmp_ok($acct->get_balance(), '==', 80, 'deposit increased balance');

$acct->withdraw(20);
cmp_ok($acct->get_balance(), '==', 60, 'withdraw reduced balance');

my $a2 = BankAccount->new('Test', 1, 0);
is($acct->get_name(), 'Paul Lalli', 'Acct 1 name unaffected by Acct 2 creation');
cmp_ok($acct->get_account_num(), '==', 123456, 'Acct 1 account_num unaffected by Acct 2 creation');
cmp_ok($acct->get_balance(), '==', 60, 'Acct 1 balance unaffected by Acct 2 creation');
is($a2->get_name(), 'Test', 'Acct 2 get_name');
cmp_ok($a2->get_account_num(), '==', 1, 'Acct 2 get_account_num');
cmp_ok($a2->get_balance(), '==', 0, 'Acct 2 get_balance');

SKIP: {
   skip 'CheckingAccount not yet written', 27 unless -e 'CheckingAccount.pm';
   use_ok('CheckingAccount');
   can_ok('CheckingAccount', 'new');
   ok(defined &CheckingAccount::new, 'CheckingAccount writes its own new()');

   my $ca = CheckingAccount->new('CGuy', 8754, 100, 2);
   my $ca2 = CheckingAccount->new('CGuy2', 56, 1000, 10);

   isa_ok($ca, 'CheckingAccount');
   isa_ok($ca2, 'CheckingAccount');
   isa_ok($ca, 'BankAccount');
   isa_ok($ca2, 'BankAccount');

   can_ok($ca, qw/get_name get_account_num get_balance deposit withdraw/);
   ok(!defined &CheckingAccount::get_name, "CheckingAccount doesn't define get_name");
   ok(!defined &CheckingAccount::get_account_num, "CheckingAccount doesn't define get_account_num");
   ok(!defined &CheckingAccount::get_balance, "CheckingAccount doesn't define get_balance");
   ok(!defined &CheckingAccount::deposit, "CheckingAccount doesn't define deposit");
   ok(!defined &CheckingAccount::withdraw, "CheckingAccount doesn't define withdraw");


   cmp_ok($ca->{checks}, '==', 2, "Proper number of checks set");
   cmp_ok($ca2->{checks}, '==', 10, "CA2 proper checks set");

   can_ok($ca, 'order_checks', 'write_check');
   $ca->write_check(25);
   cmp_ok($ca->get_balance(), '==', 75, 'write_check decreased balance by $25');
   cmp_ok($ca->{checks}, '==', 1, "write_check decremented checks number to 1.");

   $ca->write_check(15);
   cmp_ok($ca->get_balance(), '==', 60, 'write_check decreased balance by $15');
   cmp_ok($ca->{checks}, '==', 0, "write_check decremented checks number to 0.");

   my $w;
   $SIG{__WARN__} = sub { $w = join('', @_) };
   $ca->write_check(20);
   like($w, qr/^Cannot write a check, no checks available(?: at \S+ line \d+\.?\s*)?$/,
        'Appropriate warning for write_check without any checks');
   undef $SIG{__WARN__};
   cmp_ok($ca->get_balance(), '==', 60, 'write_check without checks left balance alone');
   cmp_ok($ca->{checks}, '==', 0, 'write_check without checks left checks alone');

   cmp_ok($ca2->get_balance(), '==', 1000, "Ops on CA didn't affect CA2 balance");
   cmp_ok($ca2->{checks}, '==', 10, "Ops on CA didn't affect CA2 checks");

   
   $ca->order_checks(20);
   $ca2->order_checks(5);
   cmp_ok($ca->{checks}, '==', 20, 'CA ordered 20 more checks');
   cmp_ok($ca2->{checks}, '==', 15, 'CA2 ordered 5 more checks');
}


SKIP: {
   skip 'InterestAccount not yet written', 18 unless -e 'InterestAccount.pm';
   use_ok('InterestAccount');
   can_ok('InterestAccount', 'new');
   ok(defined &InterestAccount::new, 'InterestAccount writes its own new()');
      
   
   my $ia = InterestAccount->new('CGuy', 8754, 100, 0.05);
   my $ia2 = InterestAccount->new('CGuy2', 56, 1000, 0.12);

   isa_ok($ia, 'InterestAccount');
   isa_ok($ia2, 'InterestAccount');
   isa_ok($ia, 'BankAccount');
   isa_ok($ia2, 'BankAccount');

   can_ok($ia, qw/get_name get_account_num get_balance deposit withdraw/);
   ok(!defined &InterestAccount::get_name, "InterestAccount doesn't define get_name");
   ok(!defined &InterestAccount::get_account_num, "InterestAccount doesn't define get_account_num");
   ok(!defined &InterestAccount::get_balance, "InterestAccount doesn't define get_balance");
   ok(!defined &InterestAccount::deposit, "InterestAccount doesn't define deposit");
   ok(!defined &InterestAccount::withdraw, "InterestAccount doesn't define withdraw");

   cmp_ok($ia->{rate}, '==', 0.05, 'IA rate starts at 0.05');
   cmp_ok($ia2->{rate}, '==', 0.12, 'IA2 rate starts at 0.12');

   can_ok($ia, 'accrue');
   $ia->accrue();
   cmp_ok($ia->get_balance(), '==', 105, '100 balance accrued 5% interest = 105');
   $ia2->withdraw(500);
   $ia2->accrue();
   cmp_ok($ia2->get_balance(), '==', 560, '500 balance accrued 12% interest = 560');

}

SKIP: {
   skip 'InterestCheckingAccount not yet written', 36 unless -e 'InterestCheckingAccount.pm';
   use_ok('InterestCheckingAccount');
   can_ok('InterestCheckingAccount', 'new');
   ok(defined &InterestCheckingAccount::new, 'InterestCheckingAccount writes its own new()');
 
   
   my $ica = InterestCheckingAccount->new('ICGuy', 8754, 100, 0.05, 2);
   my $ica2 = InterestCheckingAccount->new('ICGuy2', 56, 1000, 0.12, 10);

   isa_ok($ica, 'InterestCheckingAccount');
   isa_ok($ica2, 'InterestCheckingAccount');
   isa_ok($ica, 'CheckingAccount');
   isa_ok($ica2, 'CheckingAccount');
   isa_ok($ica, 'InterestAccount');
   isa_ok($ica2, 'InterestAccount');
   isa_ok($ica, 'BankAccount');
   isa_ok($ica2, 'BankAccount');


   can_ok($ica, qw/get_name get_account_num get_balance deposit withdraw/);
   ok(!defined &InterestCheckingAccount::get_name, "InterestCheckingAccount doesn't define get_name");
   ok(!defined &InterestCheckingAccount::get_account_num, "InterestCheckingAccount doesn't define get_account_num");
   ok(!defined &InterestCheckingAccount::get_balance, "InterestCheckingAccount doesn't define get_balance");
   ok(!defined &InterestCheckingAccount::deposit, "InterestCheckingAccount doesn't define deposit");
   ok(!defined &InterestCheckingAccount::withdraw, "InterestCheckingAccount doesn't define withdraw");

   cmp_ok($ica->{rate}, '==', 0.05, 'IA rate starts at 0.05');
   cmp_ok($ica2->{rate}, '==', 0.12, 'IA2 rate starts at 0.12');

   can_ok($ica, 'accrue');
   $ica->accrue();
   cmp_ok($ica->get_balance(), '==', 105, '100 balance accrued 5% interest = 105');
   $ica2->withdraw(500);
   $ica2->accrue();
   cmp_ok($ica2->get_balance(), '==', 560, '500 balance accrued 12% interest = 560');





   cmp_ok($ica->{checks}, '==', 2, "Proper number of checks set");
   cmp_ok($ica2->{checks}, '==', 10, "CA2 proper checks set");

   #Set balances to what the below tests expect them to be
   $ica->{balance} = 100;
   $ica2->{balance} = 1000;
   can_ok($ica, 'order_checks', 'write_check');
   $ica->write_check(25);
   cmp_ok($ica->get_balance(), '==', 75, 'write_check decreased balance by $25');
   cmp_ok($ica->{checks}, '==', 1, "write_check decremented checks number to 1.");

   $ica->write_check(15);
   cmp_ok($ica->get_balance(), '==', 60, 'write_check decreased balance by $15');
   cmp_ok($ica->{checks}, '==', 0, "write_check decremented checks number to 0.");

   my $w;
   $SIG{__WARN__} = sub { $w = join('', @_) };
   $ica->write_check(20);
   like($w, qr/^Cannot write a check, no checks available(?: at \S+ line \d+\.?\s*)?$/,
        'Appropriate warning for write_check without any checks');
   undef $SIG{__WARN__};
   cmp_ok($ica->get_balance(), '==', 60, 'write_check without checks left balance alone');
   cmp_ok($ica->{checks}, '==', 0, 'write_check without checks left checks alone');

   cmp_ok($ica2->get_balance(), '==', 1000, "Ops on ICA didn't affect ICA2 balance");
   cmp_ok($ica2->{checks}, '==', 10, "Ops on ICA didn't affect ICA2 checks");

  
   $ica->order_checks(20);
   $ica2->order_checks(5);
   cmp_ok($ica->{checks}, '==', 20, 'ICA ordered 20 more checks');
   cmp_ok($ica2->{checks}, '==', 15, 'ICA2 ordered 5 more checks');
}
