package de.tu_dresden.diplom.richter_mirko_mat2628335.common.handler;

import org.apache.axis.MessageContext;
import org.apache.axis.AxisFault;
import org.apache.log4j.Logger;
import de.tu_dresden.diplom.richter_mirko_mat2628335.common.entity.IFEntity;
import de.tu_dresden.diplom.richter_mirko_mat2628335.witness.entity.EntityManagerFactory;

/**
 * base-class for all handlers the are used to encrypt
 */
public abstract class BaseEncrypter extends BaseCrypt{

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

   protected static final int ENCRYPTION_METHOD_XSS4J_CONTENT = 0;
   protected static final int ENCRYPTION_METHOD_TSIK_WSSEC = 1;

   protected static final int ENCRYPTION_LEVEL_BODY = 10;
   protected static final int ENCRYPTION_LEVEL_COUNTINGCONTEXT = 11;

   /**
    * Encrypt the content of the target-Element.
    */
   public static final String ENCRYPTION_TYPE_CONTENT = "content";

   /**
    * Encyrpt the Element itself.
    */
   public static final String ENCRYPTION_TYPE_SELF = "self";

   /**
    * Encrypt using XSS4J.
    */
   public static final String ENCRYPTION_IMPLEMENTATION_XSS4J = "xss4j";

   /**
    * Encrypt using TSIK from Verisign.
    */
   public static final String ENCRYPTION_IMPLEMENTATION_TSIK = "tsik";

   /**
    * Encrypt using an encrypted symmetric key. The keyinfo is beeing safed
    * in the encrypted Data itself.
    */
   public static final String ENCRYPTION_KEYHANDLING_SYMMETRIC_LOCAL = "symmLocal";

   /**
    * Encrypt using an encrypted symmetric key. The keyinfo is beeing safed
    * in the WS-Security-section of the Header.
    */
   public static final String ENCRYPTION_KEYHANDLING_SYMMETRIC_WSSEC = "symmWSSec";

   public static final String OPTION_ENCRYPTING_ENTITY = "encryptingEntity";
   public static final String OPTION_ENCRYPTION_TYPE = "encryptionType";
   public static final String OPTION_ENCRYPTION_IMPLEMENTATION = "encryptionImpl";
   public static final String OPTION_KEY_HANDLING = "keyHandling";

   private int encryptionMethod = ENCRYPTION_METHOD_XSS4J_CONTENT;
   private String encryptionType = ENCRYPTION_TYPE_CONTENT;
   private String encryptionImpl = ENCRYPTION_IMPLEMENTATION_XSS4J;
   private String keyHandling = ENCRYPTION_KEYHANDLING_SYMMETRIC_LOCAL;

   public void invoke(MessageContext messageContext) throws AxisFault {
      final String fn = "[invoke] ";
      String encType = (String) getOption(OPTION_ENCRYPTION_TYPE);
      if(encType != null){
         if(encType.equals(ENCRYPTION_TYPE_CONTENT)){
            encryptionType = ENCRYPTION_TYPE_CONTENT;
         }else if(encType.equals(ENCRYPTION_TYPE_SELF)){
            encryptionType = ENCRYPTION_TYPE_SELF;
         }else{
            logger.error(fn + "unknown encryptionType '" + encType + "'. Using default '" + ENCRYPTION_TYPE_CONTENT + "'");
            encryptionType = ENCRYPTION_TYPE_CONTENT;
         }
      }else{
         if(logger.isInfoEnabled())logger.info(fn + "No explicite encryption type given. Using default '" + ENCRYPTION_TYPE_CONTENT + "'");
         encryptionType = ENCRYPTION_TYPE_CONTENT;
      }
      String encImpl = (String) getOption(OPTION_ENCRYPTION_IMPLEMENTATION);
      if(encImpl != null){
         if(encImpl.equals(ENCRYPTION_IMPLEMENTATION_XSS4J)){
            encryptionImpl = ENCRYPTION_IMPLEMENTATION_XSS4J;
         }else if(encImpl.equals(ENCRYPTION_IMPLEMENTATION_TSIK)){
            encryptionImpl = ENCRYPTION_IMPLEMENTATION_TSIK;
         }else{
            logger.error(fn + "unknown encryptionImpl '" + encImpl + "'. Using default '" + ENCRYPTION_IMPLEMENTATION_XSS4J + "'");
            encryptionImpl = ENCRYPTION_IMPLEMENTATION_XSS4J;
         }
      }else{
         if(logger.isInfoEnabled())logger.info(fn + "No explicite encyption method given. Using default '" + ENCRYPTION_IMPLEMENTATION_XSS4J + "'");
         encryptionImpl = ENCRYPTION_IMPLEMENTATION_XSS4J;
      }
      String keyHdl = (String) getOption(OPTION_KEY_HANDLING);
      if(keyHdl != null){
         if(keyHdl.equals(ENCRYPTION_KEYHANDLING_SYMMETRIC_LOCAL)){
            keyHandling = ENCRYPTION_KEYHANDLING_SYMMETRIC_LOCAL;
         }else if(keyHdl.equals(ENCRYPTION_KEYHANDLING_SYMMETRIC_WSSEC)){
            keyHandling = ENCRYPTION_KEYHANDLING_SYMMETRIC_WSSEC;
         }else{
            logger.error(fn + "unknown keyHandling '" + keyHdl + "'. Using default '" + ENCRYPTION_KEYHANDLING_SYMMETRIC_LOCAL + "'.");
            keyHandling = ENCRYPTION_KEYHANDLING_SYMMETRIC_LOCAL;
         }
      }else{
         if(logger.isInfoEnabled())logger.info(fn + "No explicite key handling method given. Using default '" + ENCRYPTION_KEYHANDLING_SYMMETRIC_LOCAL + "'");
         keyHandling = ENCRYPTION_KEYHANDLING_SYMMETRIC_LOCAL;
      }
      if(encryptionType == ENCRYPTION_TYPE_CONTENT && encryptionImpl == ENCRYPTION_IMPLEMENTATION_TSIK && keyHandling == ENCRYPTION_KEYHANDLING_SYMMETRIC_WSSEC){
         encryptionMethod = ENCRYPTION_METHOD_TSIK_WSSEC;
      }else{
         encryptionMethod = ENCRYPTION_METHOD_XSS4J_CONTENT;
      }
   }

   public int getEncryptionMethod() {
      return encryptionMethod;
   }

   public String getEncryptionType() {
      return encryptionType;
   }

   public String getEncryptionImpl() {
      return encryptionImpl;
   }

   public String getKeyHandling() {
      return keyHandling;
   }

   /**
    * Is the encryption Method XSS4J with encryption of the content of the target-Element
    * and the keyinfo is beeing given within the encrypted section.
    * @return
    */
   public boolean isXSS4JContentLocal(){
      return getEncryptionMethod() == ENCRYPTION_METHOD_XSS4J_CONTENT;
   }

   /**
    * Is the encryptionMethod TSIK with encryption of the content of the target-Element
    * and the keyinfo is beeing given in the WS-Secuity compliant Header-Section
    * @return
    */
   public boolean isTSIKContentWSSec(){
      return getEncryptionMethod() == ENCRYPTION_METHOD_XSS4J_CONTENT;
   }

   protected IFEntity getEncryptingEntity(){
      final String fn = "[getEncryptingEntity] ";
      IFEntity result = null;
      String encryptingEntity = (String) getOption(OPTION_ENCRYPTING_ENTITY);
      if(encryptingEntity != null){
         if(encryptingEntity.equals("@handlingInfo")){
            result = getEncryptingEntityFromHandlingInfo();
         }else{
            result = EntityManagerFactory.getEntityManager().locateEntityByAlias(encryptingEntity);
            if(result == null){
               logger.fatal(fn + "couldn't locate entity that was specified by '" + encryptingEntity + "' in the handler-WSDD!");
            }
         }
      }else{
         if(logger.isInfoEnabled())logger.info(fn + "No encryptingEntity-parameter defined ... taking it from HandlingInfo!");
         result = getEncryptingEntityFromHandlingInfo();
      }
      return result;
   }

   public abstract IFEntity getEncryptingEntityFromHandlingInfo();

}
