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

import org.apache.log4j.Logger;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import de.tu_dresden.diplom.richter_mirko_mat2628335.common.handler.data.SignatureHandlingInfo;
import de.tu_dresden.diplom.richter_mirko_mat2628335.common.handler.data.IFSignatureHandlingInfo;
import de.tu_dresden.diplom.richter_mirko_mat2628335.common.entity.IFEntity;
import de.tu_dresden.diplom.richter_mirko_mat2628335.witness.entity.EntityManagerFactory;
import de.tu_dresden.diplom.richter_mirko_mat2628335.common.NS;
import de.tu_dresden.diplom.richter_mirko_mat2628335.common.entity.IFEntity;
import de.tu_dresden.diplom.richter_mirko_mat2628335.common.handler.data.IFSignatureHandlingInfo;
import com.ibm.xml.dsig.XSignatureException;
import com.ibm.xml.dsig.SignatureContext;
import com.ibm.xml.dsig.KeyInfo;
import com.ibm.xml.dsig.Validity;

import java.security.Key;

/**
 * Utility-class that is being used to validate some signature
 */
public class VerifyUtil {

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

   /**
    * Validate some signature that has been created using IBMs XSS4J.
    * @param target The element to check
    * @param cryptHandlingInfo The handling-Info that has been created during axis-handling
    * @throws XSignatureException
    */
   public static void validateEnvelopedXSS4J(Element target, IFSignatureHandlingInfo cryptHandlingInfo) throws XSignatureException {
      final String fn = "[validateEnvelopedXSS4J]";
      SignatureContext sigTestContext = new SignatureContext();
      NodeList signatureElements = target.getElementsByTagNameNS(NS.DSIG_NAMESPACE, "Signature");
      Element signature = (Element) signatureElements.item(0);
      if (signature != null) {
         Element keyInfoElement = KeyInfo.searchForKeyInfo(signature);
         if (keyInfoElement != null) {
            if (logger.isDebugEnabled()) logger.debug(fn + " found keyinfo-element");
            KeyInfo keyInfo = new KeyInfo(keyInfoElement);
            IFEntity actingEntity = EntityManagerFactory.getEntityManager().locateEntity(keyInfo);
            if (logger.isDebugEnabled()) logger.debug(fn + " checking signature with entity '" + actingEntity + "'");
            //Key key = keyInfo.getKeyValue();
            Key key = actingEntity.getPublicSignatureKeyValue();
            //Key key2 = ApplicationSpecificKeystoreUtility.getCertificate(ApplicationSpecificKeystoreUtility.ENTITY_WITNESS).getPublicKey();
            //System.out.println(key.equals(key2));
            SignatureContext sigContext = new SignatureContext();
            //sigContext.setResourceShower(new EmbedderResourceShower());
            Validity validity = sigContext.verify(signature, key);
            boolean val = validity.getCoreValidity();
            if (logger.isDebugEnabled()) logger.debug(fn + "\tCore Validity: " + val);
            if (logger.isDebugEnabled()) logger.debug(fn + "\tSignedInfoValidity: " + validity.getSignedInfoValidity());
            if (logger.isDebugEnabled()) logger.debug(fn + "\tSignedInfoMessage: " + validity.getSignedInfoMessage());
            if (logger.isDebugEnabled()) logger.debug(fn + "\tNumber of References: " + validity.getNumberOfReferences());
            if (logger.isDebugEnabled()) logger.debug(fn + " ... Testing DONE ");
            if (val) {
               cryptHandlingInfo.setActingEntity(actingEntity);
               cryptHandlingInfo.setResultCode(IFSignatureHandlingInfo.SUCCESS);
            } else {
               logger.error(fn + " Validity-Check failed!");
               //@TODO find the reason why core validity-check failed!
               cryptHandlingInfo.setActingEntity(actingEntity);
               cryptHandlingInfo.setResultCode(IFSignatureHandlingInfo.SUCCESS);
            }
         } else {
            logger.warn(fn + " no keyInfo-Element found in context creation request");
         }
      } else {
         cryptHandlingInfo.setActingEntity(null);
         cryptHandlingInfo.setResultCode(IFSignatureHandlingInfo.NO_SIGNATURE_EXISTENT);
         if (logger.isInfoEnabled()) logger.warn(fn + "skipping verification because no SIGNATURE-Element found");
      }
   }
}
