package de.tu_dresden.diplom.richter_mirko_mat2628335.witness.account;

import org.apache.log4j.Logger;
import junit.framework.TestCase;
import de.tu_dresden.diplom.richter_mirko_mat2628335.common.account.Amount;
import de.tu_dresden.diplom.richter_mirko_mat2628335.common.account.Currency;
import de.tu_dresden.diplom.richter_mirko_mat2628335.common.account.IFCurrency;

/**
 * 
 */
public class UTAccount extends TestCase{

   private static final Logger logger = Logger.getLogger(UTAccount.class);

   protected void setUp() throws Exception {
   }

   protected void tearDown() throws Exception {
   }

   public void testSetGetIdentification(){
      Account acc = new Account(null);
      String ident = "ident#1";
      acc.setIdentification(ident);
      assertEquals(ident, acc.getIdentification());
   }

   public void testSetGetAmount(){
      Amount amount = new Amount(100, IFCurrency.CURRENCY_COUNTER_INST);
      Account acc = new Account(null);
      assertTrue(acc.setAmount(amount));
      assertEquals(amount, acc.getAmount());
      Amount negAmount = new Amount(-5, IFCurrency.CURRENCY_COUNTER_INST);
      assertFalse(acc.setAmount(negAmount));
      assertEquals(amount, acc.getAmount());
   }

   public void testAddVirtualDebit(){
      Account acc = new Account(null);
      Amount amount = new Amount(100, IFCurrency.CURRENCY_COUNTER_INST);
      acc.setAmount(amount);
      VirtualDebit vd1 = new VirtualDebit(20, IFCurrency.CURRENCY_COUNTER_INST);
      assertTrue(acc.addVirtualDebit(vd1));
      assertFalse(acc.addVirtualDebit(vd1));
      assertEquals(80, acc.getAmountWithoutVirtualDebits().getAmount(), 0);
      vd1 = new VirtualDebit(85, IFCurrency.CURRENCY_COUNTER_INST);
      assertFalse(acc.addVirtualDebit(vd1));
      assertEquals(80, acc.getAmountWithoutVirtualDebits().getAmount(), 0);
      Amount credit = new Amount(10, IFCurrency.CURRENCY_COUNTER_INST);
      assertTrue(acc.setCredit(credit));
      assertTrue(acc.addVirtualDebit(vd1));
      assertEquals(-5, acc.getAmountWithoutVirtualDebits().getAmount(), 0);
      credit = new Amount(2, IFCurrency.CURRENCY_COUNTER_INST);
      assertFalse(acc.setCredit(credit));
      assertFalse(acc.setCredit(null));
      credit = new Amount(6, IFCurrency.CURRENCY_COUNTER_INST);
      assertTrue(acc.setCredit(credit));
   }

   public void testRemoveVirtualDebit(){
      Account acc = new Account(null);
      Amount amount = new Amount(100, IFCurrency.CURRENCY_COUNTER_INST);
      acc.setAmount(amount);
      VirtualDebit vd1 = new VirtualDebit(20, IFCurrency.CURRENCY_COUNTER_INST);
      assertTrue(acc.addVirtualDebit(vd1));
      assertEquals(acc.getVirtualDebitSum().getAmount(), 20, 0);
      assertEquals(amount.getAmount(), 100, 0);
      acc.removeVirtualDebit(vd1);
      assertEquals(acc.getVirtualDebitSum().getAmount(), 0, 0);
      assertEquals(amount.getAmount(), 100, 0);

      assertTrue(acc.addVirtualDebit(vd1));
      VirtualDebit vd2 = new VirtualDebit(20, IFCurrency.CURRENCY_COUNTER_INST);
      assertTrue(acc.addVirtualDebit(vd2));
      assertEquals(acc.getVirtualDebitSum().getAmount(), 40, 0);
      assertEquals(amount.getAmount(), 100, 0);
      acc.removeVirtualDebit(vd2);
      assertEquals(acc.getVirtualDebitSum().getAmount(), 20, 0);
      assertEquals(amount.getAmount(), 100, 0);

      VirtualDebit vd3 = new VirtualDebit(70, IFCurrency.CURRENCY_COUNTER_INST);
      assertTrue(acc.addVirtualDebit(vd3));
      assertFalse(acc.addVirtualDebit(vd2));
      acc.removeVirtualDebit(vd1);
      assertTrue(acc.addVirtualDebit(vd2));
      assertEquals(acc.getVirtualDebitSum().getAmount(), 90, 0);
   }

   public void testPerformVirtualDebit(){
      Account acc = new Account(new Amount(100, IFCurrency.CURRENCY_COUNTER_INST));

      acc.setCredit(new Amount(40, IFCurrency.CURRENCY_COUNTER_INST));
      acc.performVirtualDebit(new VirtualDebit(20, Currency.CURRENCY_COUNTER_INST));
      assertEquals(acc.getVirtualDebitSum().getAmount(), 0, 0);
      assertEquals(acc.getAmount().getAmount(), 100, 0);

      VirtualDebit vd1 = new VirtualDebit(20, IFCurrency.CURRENCY_COUNTER_INST);
      assertTrue(acc.addVirtualDebit(vd1));
      assertEquals(acc.getVirtualDebitSum().getAmount(), 20, 0);
      assertEquals(acc.getAmount().getAmount(), 100, 0);
      acc.performVirtualDebit(vd1);
      assertEquals(acc.getVirtualDebitSum().getAmount(), 0, 0);
      assertEquals(acc.getAmount().getAmount(), 80, 0);

      vd1 = new VirtualDebit(100, IFCurrency.CURRENCY_COUNTER_INST);
      assertTrue(acc.addVirtualDebit(vd1));
      assertEquals(acc.getVirtualDebitSum().getAmount(), 100, 0);
      assertEquals(acc.getAmount().getAmount(), 80, 0);
      acc.performVirtualDebit(vd1);
      assertEquals(acc.getVirtualDebitSum().getAmount(), 0, 0);
      assertEquals(acc.getAmount().getAmount(), -20, 0);
   }

   public void testAddVirtualCredit(){
      Account acc = new Account(new Amount(100, IFCurrency.CURRENCY_COUNTER_INST));
      VirtualCredit vc = new VirtualCredit(30, IFCurrency.CURRENCY_COUNTER_INST);
      acc.addVirtualCredit(vc);
      assertEquals(acc.getVirtualDebitSum().getAmount(), 0, 0);
      assertEquals(acc.getVirtualCreditSum().getAmount(), 30, 0);
      assertEquals(acc.getAmount().getAmount(), 100, 0);
      acc.performVirtualCredit(new VirtualCredit(30, IFCurrency.CURRENCY_COUNTER_INST));
      assertEquals(acc.getVirtualDebitSum().getAmount(), 0, 0);
      assertEquals(acc.getVirtualCreditSum().getAmount(), 30, 0);
      assertEquals(acc.getAmount().getAmount(), 100, 0);
      acc.performVirtualCredit(vc);
      assertEquals(acc.getVirtualCreditSum().getAmount(), 0, 0);
      assertEquals(acc.getAmount().getAmount(), 130, 0);

      // negative credit not allowed
      vc = new VirtualCredit(-30, IFCurrency.CURRENCY_COUNTER_INST);
      acc.addVirtualCredit(vc);
      assertEquals(acc.getVirtualCreditSum().getAmount(), 0, 0);
      assertEquals(acc.getAmount().getAmount(), 130, 0);

      VirtualCredit vc1 = new VirtualCredit(30, IFCurrency.CURRENCY_COUNTER_INST);
      acc.addVirtualCredit(vc1);
      VirtualCredit vc2 = new VirtualCredit(70, IFCurrency.CURRENCY_COUNTER_INST);
      acc.addVirtualCredit(vc2);
      VirtualCredit vc3 = new VirtualCredit(40, IFCurrency.CURRENCY_COUNTER_INST);
      acc.addVirtualCredit(vc3);
      assertEquals(acc.getVirtualCreditSum().getAmount(), 140, 0);
      assertEquals(acc.getAmount().getAmount(), 130, 0);
      acc.performVirtualCredit(vc1);
      acc.performVirtualCredit(vc2);
      acc.performVirtualCredit(vc3);
      assertEquals(acc.getVirtualCreditSum().getAmount(), 0, 0);
      assertEquals(acc.getAmount().getAmount(), 270, 0);
   }

   public void testRemoveVirtualCredit(){
      Account acc = new Account(new Amount(100, IFCurrency.CURRENCY_COUNTER_INST));
      VirtualCredit vc = new VirtualCredit(30, IFCurrency.CURRENCY_COUNTER_INST);
      acc.addVirtualCredit(vc);
      assertEquals(acc.getVirtualCreditSum().getAmount(), 30, 0);
      acc.removeVirtualCredit(vc);
      assertEquals(acc.getVirtualCreditSum().getAmount(), 0, 0);

      // two credits that are same object are not allowed
      acc.addVirtualCredit(vc);
      acc.addVirtualCredit(vc);
      assertEquals(acc.getVirtualCreditSum().getAmount(), 30, 0);
      VirtualCredit vc1 = new VirtualCredit(20, IFCurrency.CURRENCY_COUNTER_INST);
      acc.addVirtualCredit(vc1);
      VirtualCredit vc2 = new VirtualCredit(30, IFCurrency.CURRENCY_COUNTER_INST);
      acc.addVirtualCredit(vc2);
      VirtualCredit vc3 = new VirtualCredit(10, IFCurrency.CURRENCY_COUNTER_INST);
      acc.addVirtualCredit(vc3);
      assertEquals(acc.getVirtualCreditSum().getAmount(), 90, 0);
      acc.removeVirtualCredit(vc2);
      acc.removeVirtualCredit(vc1);
      assertEquals(acc.getVirtualCreditSum().getAmount(), 40, 0);
   }

   public void testPerformVirtualCredit(){
      Account acc = new Account(new Amount(100, IFCurrency.CURRENCY_COUNTER_INST));
      VirtualCredit vc = new VirtualCredit(30, IFCurrency.CURRENCY_COUNTER_INST);
      acc.addVirtualCredit(vc);
      assertEquals(acc.getVirtualCreditSum().getAmount(), 30, 0);
      assertEquals(acc.getAmount().getAmount(), 100, 0);
      VirtualCredit vc1 = new VirtualCredit(20, IFCurrency.CURRENCY_COUNTER_INST);
      acc.addVirtualCredit(vc1);
      assertEquals(acc.getVirtualCreditSum().getAmount(), 50, 0);
      assertEquals(acc.getAmount().getAmount(), 100, 0);
      acc.performVirtualCredit(vc1);
      assertEquals(acc.getVirtualCreditSum().getAmount(), 30, 0);
      assertEquals(acc.getAmount().getAmount(), 120, 0);
      acc.performVirtualCredit(vc1);
      assertEquals(acc.getVirtualCreditSum().getAmount(), 30, 0);
      assertEquals(acc.getAmount().getAmount(), 120, 0);
      acc.removeVirtualCredit(vc);
      acc.performVirtualCredit(vc);
      assertEquals(acc.getVirtualCreditSum().getAmount(), 0, 0);
      assertEquals(acc.getAmount().getAmount(), 120, 0);
   }



   public void testSetCredit(){
      Account acc = new Account(null);
      Amount amount = new Amount(100, IFCurrency.CURRENCY_COUNTER_INST);
      acc.setAmount(amount);
      Amount credit = new Amount(10, IFCurrency.CURRENCY_COUNTER_INST);
      assertTrue(acc.setCredit(credit));
      amount = new Amount(-15, IFCurrency.CURRENCY_COUNTER_INST);
      assertFalse(acc.setAmount(amount));
      VirtualDebit debit = new VirtualDebit(108, IFCurrency.CURRENCY_COUNTER_INST);
      assertTrue(acc.addVirtualDebit(debit));
      acc.performVirtualDebit(debit);
      credit = new Amount(5, IFCurrency.CURRENCY_COUNTER_INST);
      assertFalse(acc.setCredit(credit));
   }
}
