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

import org.apache.log4j.Logger;
import de.tu_dresden.diplom.richter_mirko_mat2628335.witness.process.result.IFContextRemovalResult;
import de.tu_dresden.diplom.richter_mirko_mat2628335.witness.process.result.ContextRemovalResult;
import de.tu_dresden.diplom.richter_mirko_mat2628335.witness.context.ex.ContextInfoInvalidException;
import de.tu_dresden.diplom.richter_mirko_mat2628335.common.context.IFCoordinationContext;

import java.util.Iterator;

/**
 * 
 */
public class WitnessContextLifeCycleManager {

   private static final Logger logger = Logger.getLogger(WitnessContextLifeCycleManager.class);
   public static final Logger contextStateMonitor = Logger.getLogger("monitor.state.context.witness");

   //private WitnessContextManager managingWitnessContextManager = null;
   private WitnessContextInfoPool witnessContextInfoPool = null;

   public WitnessContextLifeCycleManager(WitnessContextInfoPool witnessContextInfoPool) {
      final String fn = "[<init>] ";
      //this.managingWitnessContextManager = managingWitnessContextManager;
      this.witnessContextInfoPool = witnessContextInfoPool;
      //new Thread(new LifetimeChecker(), "LifetimeChecker").start();
      if (logger.isDebugEnabled()) logger.debug(fn + "New Instance");
   }

   public IFContextRemovalResult removeContext(IFWitnessContextInfo witnessContextInfo) {
      final String fn = "[removeContext] ";
      ContextRemovalResult result = new ContextRemovalResult();
      try {
         if (witnessContextInfoPool.containsContextInfo(witnessContextInfo)) {
            if (witnessContextInfo.isInvalid()) {
               logger.warn(fn + "context to remove already invalidated... reason: '" + witnessContextInfo.getInvalidityReason() + "'");
               result.setResultCode(IFContextRemovalResult.CONTEXT_ALREADY_INVALID);
               result.setResultMessage("context to remove already invalidated... reason: '" + witnessContextInfo.getInvalidityReason() + "'");
            } else {
               if (witnessContextInfo.hasOpenAccountTransferContexts()) {
                  if (logger.isInfoEnabled()) logger.info(fn + "context could not be removed because of open transfer contexts");
                  result.setResultCode(IFContextRemovalResult.CONTEXT_WITH_OPEN_TRANSFER_CONTEXTS);
                  result.setResultMessage("context could not be removed because of open transfer contexts");
               } else {
                  if (logger.isDebugEnabled()) logger.debug(fn + "invalidating context with id '" + witnessContextInfo.getContextObject().getIdentification() + "'");
                  result.setResultCode(IFContextRemovalResult.SUCCESS);
                  result.setResultMessage("suceesfully removed");
                  //contextInfoPool.remove(contextInfo);
                  if (contextStateMonitor.isDebugEnabled()) {
                     StringBuffer mon = new StringBuffer(fn);
                     mon.append("removed WitnessContextInfo '" + witnessContextInfo.getIdentification() + "'");
                     contextStateMonitor.debug(mon);
                  }
                  witnessContextInfoPool.remove(witnessContextInfo);
                  witnessContextInfo.setInvalid("invalidated by user");
               }
            }
         } else {
            logger.warn(fn + "context to remove is not managed by the underlying WitnessContextInfoPool!");
            result.setResultCode(IFContextRemovalResult.CONTEXT_NOT_MANAGED);
            result.setResultMessage("context to remove is not managed by the underlying WitnessContextInfoPool!");
         }
      } catch (ContextInfoInvalidException e) {
         logger.warn(fn + "context to remove already invalidated... reason: '" + witnessContextInfo.getInvalidityReason() + "'");
         result.setResultCode(IFContextRemovalResult.CONTEXT_ALREADY_INVALID);
         result.setResultMessage("context to remove already invalidated... reason: '" + witnessContextInfo.getInvalidityReason() + "'");
      }
      return result;
   }

   public IFWitnessContextInfo getContext(IFCoordinationContext coordinationContext) {
      final String fn = "[getContext] ";
      IFWitnessContextInfo result = null;
      result = getContext(coordinationContext.getIdentification());
      return result;
   }

   public IFWitnessContextInfo getContext(String ident) {
      final String fn = "[getContext] ";
      IFWitnessContextInfo result = null;
      if (ident != null) {
         if (logger.isDebugEnabled()) logger.debug(fn + " identification: '" + ident + "'");
         result = witnessContextInfoPool.getContextInfo(ident);
         if (result != null) {
            checkLifeTime(result);
         }else{
            logger.warn(fn + "context with ident '" + ident + "' doesn't exist!");
         }
      }
      return result;
   }

   /**
    * Sets the contextInfo-state to invalid if expiration-time is reached
    *
    * @param ctxInfo
    */
   private void checkLifeTime(IFWitnessContextInfo ctxInfo) {
      final String fn = "[checkLifeTime] ";
      try {
         long expiration = ctxInfo.getContextObject().getExpiresLong();
         long now = System.currentTimeMillis();
         if (expiration <= now) {
            ctxInfo.setInvalid("end of lifetime reached at '" + expiration + "'!");
            witnessContextInfoPool.remove(ctxInfo);
            if (contextStateMonitor.isDebugEnabled()) {
               StringBuffer mon = new StringBuffer(fn);
               mon.append("removed WitnessContextInfo '" + ctxInfo.getIdentification() + "'");
               contextStateMonitor.debug(mon);
            }
         }
      } catch (ContextInfoInvalidException e) {
         logger.info(fn + "contextInfo-object to chekc already invalidated! reason: '" + ctxInfo.getInvalidityReason() + "'");
      }
   }

   private class LifetimeChecker implements Runnable {

      public void run() {
         final String fn = "[LifetimeChecker:run] ";
         while (true) {
            if (logger.isDebugEnabled()) logger.debug(fn + "performing check");
            Iterator it = witnessContextInfoPool.iterate();
            while (it.hasNext()) {
               IFWitnessContextInfo info = (IFWitnessContextInfo) it.next();
               checkLifeTime(info);
            }
            try {
               Thread.sleep(10000);
            } catch (InterruptedException e) {
               e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
            }
         }
      }
   }

}
