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

import org.apache.log4j.Logger;
import de.tu_dresden.diplom.richter_mirko_mat2628335.common.handler.data.IFSignatureHandlingInfo;
import de.tu_dresden.diplom.richter_mirko_mat2628335.common.handler.data.IFHandlingInfo;
import de.tu_dresden.diplom.richter_mirko_mat2628335.common.digestAgreement.DigestAgreementResponse;
import de.tu_dresden.diplom.richter_mirko_mat2628335.common.digestAgreement.IFDigestAgreementRequest;
import de.tu_dresden.diplom.richter_mirko_mat2628335.common.digestAgreement.IFDigestAgreementResponse;
import de.tu_dresden.diplom.richter_mirko_mat2628335.common.evidence.BodyEvidence;
import de.tu_dresden.diplom.richter_mirko_mat2628335.common.evidence.BodyEvidence;
import de.tu_dresden.diplom.richter_mirko_mat2628335.common.context.IFCountingContext;
import de.tu_dresden.diplom.richter_mirko_mat2628335.witness.process.result.IFDigestAgreementConfirmationResult;
import de.tu_dresden.diplom.richter_mirko_mat2628335.witness.context.IFWitnessContextManager;
import de.tu_dresden.diplom.richter_mirko_mat2628335.witness.context.WitnessContextManagerFactory;
import de.tu_dresden.diplom.richter_mirko_mat2628335.witness.context.IFWitnessContextInfo;
import de.tu_dresden.diplom.richter_mirko_mat2628335.witness.context.ex.ContextInfoInvalidException;

/**
 * 
 */
public class DigesterProcess implements IFProcess {

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

   private IFHandlingInfo requestHandlingInfo = null;
   private IFDigestAgreementRequest digestAgreementRequest = null;
   private IFWitnessContextInfo contextInfo = null;

   private IFDigestAgreementResponse digestAgreementResponse = null;

   public DigesterProcess(IFHandlingInfo requestHandlingInfo, IFDigestAgreementRequest digestAgreementRequest) {
      final String fn = "[<init>] ";
      this.requestHandlingInfo = requestHandlingInfo;
      this.digestAgreementRequest = digestAgreementRequest;
      this.contextInfo = WitnessContextManagerFactory.getContextManager().getContext(digestAgreementRequest.getContextID());
   }

   private IFHandlingInfo getRequestHandlingInfo() {
      return requestHandlingInfo;
   }

   private IFDigestAgreementRequest getDigestAgreementRequest() {
      return digestAgreementRequest;
   }

   private IFWitnessContextInfo getContextInfo() {
      return contextInfo;
   }

   /**
    * The digestAgreementResponse as beeing sent to the requester in the SOAP-Body
    *
    * @return
    */
   public IFDigestAgreementResponse getDigestAgreementResponse() {
      return digestAgreementResponse;
   }

   private void setDigestAgreementResponse(IFDigestAgreementResponse digestAgreementResponse) {
      this.digestAgreementResponse = digestAgreementResponse;
   }

   public void perform() {
      final String fn = "[perform] ";
      IFSignatureHandlingInfo bodyHandlingInfo = getRequestHandlingInfo().getSignatureHandlingInfoBody();
      DigestAgreementResponse result = new DigestAgreementResponse();
      setDigestAgreementResponse(result);
      if (bodyHandlingInfo.isSuccess()) {
         if (logger.isDebugEnabled()) logger.debug(fn + "handlingInfo was successful -> performing DigesterProcess");
         IFWitnessContextManager witnessContextManager = WitnessContextManagerFactory.getContextManager();
         if (witnessContextManager.registerDigestAgreementRequest(getDigestAgreementRequest(), bodyHandlingInfo.getActingEntity(), new BodyEvidence(getRequestHandlingInfo()))) {
            boolean wait = true;
            long start = System.currentTimeMillis();
            while (wait) {
               IFDigestAgreementConfirmationResult confResult = witnessContextManager.getConfirmationState(getDigestAgreementRequest());
               if (confResult.isSuccess()) {
                  if (logger.isDebugEnabled()) logger.debug(fn + " digestAgreementConfirmationResult says SUCCESS!");
                  wait = false;
                  result.setSuccess(true);
                  result.setAgreementReference(confResult.getReference());
                  result.setPhase(getDigestAgreementRequest().getPhase());
                  result.setCoordinationCtxIdentification(getDigestAgreementRequest().getContextID());
               } else if (confResult.isFailure()) {
                  if (logger.isDebugEnabled()) logger.debug(fn + " digestAgreementConfirmationResult says FAILURE!");
                  wait = false;
                  result.setSuccess(false);
                  result.setCoordinationCtxIdentification(getDigestAgreementRequest().getContextID());
               } else if (confResult.isUnknown()){
                  if (logger.isDebugEnabled()) logger.debug(fn + " digestAgreementConfirmationResult says UNKNOWN!");
               }else{
                  logger.fatal(fn + "unknown state of DigestAgreementConfirmationResult: '" + confResult.getResultCode() + "' -> '" + confResult.getResultMessage() + "'");
               }
               if (digestAgreementRequest.isRequestPhase() && wait) {
                  try {
                     if ((System.currentTimeMillis() - start) >= getContextInfo().getContextObject().getTimeoutDigestAgreementOnRequestPhaseMSLong()) {
                        wait = false;
                        if (logger.isDebugEnabled()) logger.debug(fn + "stopping to wait for other digest because of timeout!");
                     }
                  } catch (ContextInfoInvalidException e) {
                     e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
                     wait = false;
                  }
               }else{
                  try {
                     if ((System.currentTimeMillis() - start) >= getContextInfo().getContextObject().getTimeoutDigestAgreementOnResponsePhaseMSLong()) {
                        wait = false;
                        if (logger.isDebugEnabled()) logger.debug(fn + "stopping to wait for other digest because of timeout!");
                     }
                  } catch (ContextInfoInvalidException e) {
                     e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
                     wait = false;
                  }
               }
               if (wait) {
                  try {
                     long msToSleep = 1000;
                     if (logger.isDebugEnabled()) logger.debug(fn + " sleeping for '" + msToSleep + "' millis");
                     Thread.sleep(msToSleep);
                  } catch (InterruptedException e) {
                     e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
                  }
               }
            }
         } else {
            logger.error(fn + "wasn't able to register DigestAgreementRequest '" + getDigestAgreementRequest() + "'");
            result.setSuccess(false);
         }
      }else{
         logger.error(fn + "don't perform digesterProcess because HandlingInfo wasn't successful");
      }
   }
}
