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

import org.apache.log4j.Logger;
import org.apache.log4j.MDC;
import org.apache.axis.handlers.BasicHandler;
import org.apache.axis.MessageContext;
import org.apache.axis.Message;
import org.apache.axis.AxisFault;
import org.apache.axis.utils.XMLUtils;
import org.apache.axis.message.SOAPEnvelope;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import de.tu_dresden.diplom.richter_mirko_mat2628335.common.NS;
import de.tu_dresden.diplom.richter_mirko_mat2628335.common.handler.data.IFHandlingInfo;
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.common.keystore.ApplicationSpecificKeystoreUtility;
import de.tu_dresden.diplom.richter_mirko_mat2628335.common.crypto.SignUtil;

import javax.xml.transform.stream.StreamSource;
import java.io.StringReader;

/**
 * 
 */
public class BodySigner extends BaseSigner {

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

   /**
    * @see org.apache.axis.Handler#invoke(org.apache.axis.MessageContext)
    */
   public void invoke(MessageContext messageContext) throws AxisFault {
      String fn = "[invoke] ";
      String logInfo = (String) getOption(OPTION_LOG_INFO);
      if (logInfo != null) {
         //fn = fn + " -> " + logInfo + "::";
         MDC.put(OPTION_LOG_INFO, logInfo);
      }
      if (logger.isDebugEnabled()) logger.debug(fn + " --> BODYSIGNER");
      super.invoke(messageContext);
      if (getHandlingInfo().isSuccess()) {
         IFEntity signingEntity = getSigningEntity();
         if (logger.isDebugEnabled()) logger.debug(fn + " signing with entity '" + signingEntity + "'");
         if (isXSS4JEnveloped()) {
            signBodyEnvelopedXSS4J(messageContext, signingEntity);
         } else if(isTSIKWSSEC()) {

         }else{
            logger.error(fn + "signature-mechanism unknown");
         }
      } else {
         logger.fatal(fn + "Didn't perform operation because HandlingInfo FAILED!");
      }
      if (logger.isDebugEnabled()) logger.debug(fn + " <-- BODYSIGNER!");
      MDC.remove(OPTION_LOG_INFO);
   }

   public void signBodyEnvelopedXSS4J(MessageContext messageContext, IFEntity signingEntity) {
      //final String fn = "[signBodyEnvelopedXSS4J]";
      try {
         Message msg = messageContext.getCurrentMessage();
         SOAPEnvelope soapEnvelope = msg.getSOAPEnvelope();
         Document doc = soapEnvelope.getAsDocument();
         Element envelope = doc.getDocumentElement();
         Element body = (Element) envelope.getElementsByTagNameNS(NS.SOAP_ENVELOPE_NAMESPACE, "Body").item(0);
         SignUtil.signEnvelopedXSS4J(doc, body, signingEntity);
         String documentString = XMLUtils.DocumentToString(doc);
         StreamSource source = new StreamSource(new StringReader(documentString));
         msg.getSOAPPart().setContent(source);
      } catch (Exception e) {
         e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
      }
   }

   public IFEntity getSigningEntityFromHandlingInfo() {
      final String fn = "[getSigningEntityFromHandlingInfo] ";
      IFEntity result = null;
      IFHandlingInfo handlingInfo = getHandlingInfo();
      if(handlingInfo != null){
         IFSignatureHandlingInfo sigHandlInf = handlingInfo.getSignatureHandlingInfoBody();
         if(sigHandlInf != null){
            result = sigHandlInf.getActingEntity();
         }else{
            logger.warn(fn + "No signatureHandlingInfo set for Body in currentThread's handlingInfo!");
         }
      }else{
         logger.warn(fn + "No handlingInfo set in currentThread!");
      }
      return result;
   }

}
