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

import org.apache.log4j.Logger;
import junit.framework.TestCase;
import de.tu_dresden.diplom.richter_mirko_mat2628335.common.context.comm.IFContextCreationResponse;
import de.tu_dresden.diplom.richter_mirko_mat2628335.common.context.IFCoordinationContext;
import de.tu_dresden.diplom.richter_mirko_mat2628335.common.context.CountingContext;
import de.tu_dresden.diplom.richter_mirko_mat2628335.common.handler.data.HandlingInfo;
import de.tu_dresden.diplom.richter_mirko_mat2628335.common.handler.data.IFSignatureHandlingInfo;
import de.tu_dresden.diplom.richter_mirko_mat2628335.common.account.AccountIdentification;
import de.tu_dresden.diplom.richter_mirko_mat2628335.common.account.Amount;
import de.tu_dresden.diplom.richter_mirko_mat2628335.common.digestAgreement.DigestAgreementRequest;
import de.tu_dresden.diplom.richter_mirko_mat2628335.common.digestAgreement.IFDigestAgreementResponse;
import de.tu_dresden.diplom.richter_mirko_mat2628335.witness.DTWitness;
import de.tu_dresden.diplom.richter_mirko_mat2628335.common.digestAgreement.IFDigestAgreementRequest;
import de.tu_dresden.diplom.richter_mirko_mat2628335.common.digestAgreement.DigestAgreementRequest;
import de.tu_dresden.diplom.richter_mirko_mat2628335.common.digestAgreement.IFDigestAgreementResponse;
import de.tu_dresden.diplom.richter_mirko_mat2628335.witness.account.AccountPool;
import de.tu_dresden.diplom.richter_mirko_mat2628335.witness.account.IFAccount;
import de.tu_dresden.diplom.richter_mirko_mat2628335.common.account.Amount;
import de.tu_dresden.diplom.richter_mirko_mat2628335.common.account.IFCurrency;
import de.tu_dresden.diplom.richter_mirko_mat2628335.common.account.IFCurrency;

/**
 * 
 */
public class UTDigesterProcess extends TestCase {

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

   ContextCreationProcess createContextProcess4ClientLongLife = null;

   protected void setUp() throws Exception {
      {
         createContextProcess4ClientLongLife = DTProcess.getSucceedingContextCreationProcess4Client(1000 * 60 * 20, 30 * 1000, 30 * 1000);
      }
   }

   public void testDigester() {
      //assertFalse(true);
   }

   public void testContextLifeTime() {
      AccountPool.resetAccounts();
      ContextCreationProcess ctxCreateProc1 = null;
      {
         ctxCreateProc1 = DTProcess.getSucceedingContextCreationProcess4Client(1000, 30 * 1000, 30 * 1000);
         ctxCreateProc1.perform();
         IFContextCreationResponse ctxCreateResp = ctxCreateProc1.getContextCreationResponse();
         assertTrue(ctxCreateResp.isSuccess());
         assertNotNull(ctxCreateResp);
         IFCoordinationContext coordCtx = ctxCreateProc1.getHeaderResponse();
         assertNotNull(coordCtx);
      }
      {
         DigesterProcess digProc = DTProcess.getSucceedingDigesterProcess(ctxCreateProc1);
         final DigesterProcess digProc2 = DTProcess.getSucceedingDigesterProcess(ctxCreateProc1);
         new Thread(new Runnable() {
            public void run() {
               digProc2.perform();
               IFDigestAgreementResponse resp = digProc2.getDigestAgreementResponse();
               assertTrue(resp.isSuccess());
            }
         }).start();
         digProc.perform();
         IFDigestAgreementResponse resp = digProc.getDigestAgreementResponse();
         assertTrue(resp.isSuccess());
      }
      long expirationTime = ctxCreateProc1.getHeaderResponse().getExpiresLong();
      try {
         while (expirationTime > System.currentTimeMillis()) {
            Thread.sleep(10); // waiting to overrun lifetime of the context
         }
      } catch (InterruptedException e) {
         e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
      }
      {
         DigesterProcess digProc = DTProcess.getSucceedingDigesterProcess(ctxCreateProc1);
         final DigesterProcess digProc2 = DTProcess.getSucceedingDigesterProcess(ctxCreateProc1);
         new Thread(new Runnable() {
            public void run() {
               digProc2.perform();
               IFDigestAgreementResponse resp = digProc2.getDigestAgreementResponse();
               assertFalse(resp.isSuccess());
            }
         }).start();
         digProc.perform();
         IFDigestAgreementResponse resp = digProc.getDigestAgreementResponse();
         assertFalse(resp.isSuccess());
      }
      //assertFalse(true);
   }

   public void testCreditDebitCreationAndExecution() {
      AccountPool.resetAccounts();
      float sourceAmount = AccountPool.getAccount(DTWitness.getClient1(), new AccountIdentification("one")).getAmount().getAmount();
      float targetAmount = AccountPool.getAccount(DTWitness.getTicketBooking(), new AccountIdentification("default")).getAmount().getAmount();
      createContextProcess4ClientLongLife.perform();
      IFContextCreationResponse ctxCreateResp = createContextProcess4ClientLongLife.getContextCreationResponse();
      assertTrue(ctxCreateResp.isSuccess());
      assertNotNull(ctxCreateResp);
      IFCoordinationContext coordCtx = createContextProcess4ClientLongLife.getHeaderResponse();
      assertNotNull(coordCtx);

      IFDigestAgreementResponse refResp = null;
      {
         DigestAgreementRequest digAgreeReq = DTWitness.getDigestAgreementRequest(createContextProcess4ClientLongLife.getHeaderResponse());
         digAgreeReq.setAmount(new Amount(20, IFCurrency.CURRENCY_COUNTER_INST));
         HandlingInfo handlingInfo = new HandlingInfo();
         CountingContext countingContext = new CountingContext();
         countingContext.setCoordinationContext(createContextProcess4ClientLongLife.getHeaderResponse());
         handlingInfo.setCountingContext(countingContext);
         handlingInfo.getSignatureHandlingInfoBody().setActingEntity(createContextProcess4ClientLongLife.getRequestHandlingInfo().getSignatureHandlingInfoBody().getActingEntity());
         handlingInfo.getSignatureHandlingInfoBody().setResultCode(IFSignatureHandlingInfo.SUCCESS);
         DigesterProcess digProc = new DigesterProcess(handlingInfo, digAgreeReq);

         digAgreeReq = DTWitness.getDigestAgreementRequest(createContextProcess4ClientLongLife.getHeaderResponse());
         digAgreeReq.setAmount(new Amount(20, IFCurrency.CURRENCY_COUNTER_INST));
         handlingInfo = new HandlingInfo();
         countingContext = new CountingContext();
         countingContext.setCoordinationContext(createContextProcess4ClientLongLife.getHeaderResponse());
         handlingInfo.setCountingContext(countingContext);
         handlingInfo.getSignatureHandlingInfoBody().setActingEntity(DTWitness.getTicketBooking());
         handlingInfo.getSignatureHandlingInfoBody().setResultCode(IFSignatureHandlingInfo.SUCCESS);
         final DigesterProcess digProc2 = new DigesterProcess(handlingInfo, digAgreeReq);
         new Thread(new Runnable() {
            public void run() {
               digProc2.perform();
               IFDigestAgreementResponse resp = digProc2.getDigestAgreementResponse();
               assertTrue(resp.isSuccess());
            }
         }).start();
         digProc.perform();
         refResp = digProc.getDigestAgreementResponse();
         assertTrue(refResp.isSuccess());
      }
      IFAccount clientAccount = AccountPool.getAccount(DTWitness.getClient1(), new AccountIdentification("one"));
      IFAccount bookingAccount = AccountPool.getAccount(DTWitness.getTicketBooking(), new AccountIdentification("default"));
      try {
         // neded because otherwise the digProc2-Process may be still active when
         // virtualDebitSum and virtualCreditSum are requested
         Thread.sleep(200);
      } catch (InterruptedException e) {
         e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
      }
      assertTrue(clientAccount.getVirtualDebitSum().getAmount() == 20);
      assertTrue(bookingAccount.getVirtualCreditSum().getAmount() == 20);
      {
         DigestAgreementRequest digAgreeReq = DTWitness.getDigestAgreementRequest(createContextProcess4ClientLongLife.getHeaderResponse());
         digAgreeReq.setAmount(null);
         digAgreeReq.setPhase(IFDigestAgreementRequest.PHASE_RESPONSE);
         //digAgreeReq.setAgreementReference(refResp.getAgreementReference());
         digAgreeReq.setDigest("abcd");
         digAgreeReq.setNonce(refResp.getAgreementReference());
         HandlingInfo handlingInfo = new HandlingInfo();
         CountingContext countingContext = new CountingContext();
         countingContext.setCoordinationContext(createContextProcess4ClientLongLife.getHeaderResponse());
         handlingInfo.setCountingContext(countingContext);
         handlingInfo.getSignatureHandlingInfoBody().setActingEntity(createContextProcess4ClientLongLife.getRequestHandlingInfo().getSignatureHandlingInfoBody().getActingEntity());
         handlingInfo.getSignatureHandlingInfoBody().setResultCode(IFSignatureHandlingInfo.SUCCESS);
         DigesterProcess digProc = new DigesterProcess(handlingInfo, digAgreeReq);

         digAgreeReq = DTWitness.getDigestAgreementRequest(createContextProcess4ClientLongLife.getHeaderResponse());
         digAgreeReq.setAmount(null);
         digAgreeReq.setPhase(IFDigestAgreementRequest.PHASE_RESPONSE);
         //digAgreeReq.setAgreementReference(refResp.getAgreementReference());
         digAgreeReq.setDigest("abcd");
         digAgreeReq.setNonce(refResp.getAgreementReference());
         handlingInfo = new HandlingInfo();
         countingContext = new CountingContext();
         countingContext.setCoordinationContext(createContextProcess4ClientLongLife.getHeaderResponse());
         handlingInfo.setCountingContext(countingContext);
         handlingInfo.getSignatureHandlingInfoBody().setActingEntity(DTWitness.getTicketBooking());
         handlingInfo.getSignatureHandlingInfoBody().setResultCode(IFSignatureHandlingInfo.SUCCESS);
         final DigesterProcess digProc2 = new DigesterProcess(handlingInfo, digAgreeReq);
         new Thread(new Runnable() {
            public void run() {
               digProc2.perform();
               IFDigestAgreementResponse resp = digProc2.getDigestAgreementResponse();
               assertTrue(resp.isSuccess());
            }
         }).start();
         digProc.perform();
         IFDigestAgreementResponse resp = digProc.getDigestAgreementResponse();
         assertTrue(resp.isSuccess());
      }
      assertEquals(0, clientAccount.getVirtualDebitSum().getAmount(), 0);
      assertEquals(0, bookingAccount.getVirtualCreditSum().getAmount(), 0);
      assertEquals((sourceAmount - 20), clientAccount.getAmount().getAmount(), 0);
      assertEquals((targetAmount + 20), bookingAccount.getAmount().getAmount(), 0);
      assertEquals(0, clientAccount.getVirtualDebitSum().getAmount(), 0);
      assertEquals(0, bookingAccount.getVirtualCreditSum().getAmount(), 0);
   }
}
