/**
 * 
 */
package at.gv.egiz.pdfas.impl.api;

import java.io.File;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;
import java.util.Vector;

import org.apache.commons.lang.builder.ToStringBuilder;
import org.apache.commons.lang.math.NumberUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import at.gv.egiz.pdfas.api.PdfAs;
import at.gv.egiz.pdfas.api.analyze.AnalyzeParameters;
import at.gv.egiz.pdfas.api.analyze.AnalyzeResult;
import at.gv.egiz.pdfas.api.commons.Constants;
import at.gv.egiz.pdfas.api.commons.DynamicSignatureLifetimeEnum;
import at.gv.egiz.pdfas.api.commons.DynamicSignatureProfile;
import at.gv.egiz.pdfas.api.commons.DynamicSignatureProfileImpl;
import at.gv.egiz.pdfas.api.commons.SignatureInformation;
import at.gv.egiz.pdfas.api.exceptions.PdfAsException;
import at.gv.egiz.pdfas.api.sign.SignParameters;
import at.gv.egiz.pdfas.api.sign.SignResult;
import at.gv.egiz.pdfas.api.verify.VerifyAfterAnalysisParameters;
import at.gv.egiz.pdfas.api.verify.VerifyAfterReconstructXMLDsigParameters;
import at.gv.egiz.pdfas.api.verify.VerifyParameters;
import at.gv.egiz.pdfas.api.verify.VerifyResult;
import at.gv.egiz.pdfas.api.verify.VerifyResults;
import at.gv.egiz.pdfas.api.xmldsig.ExtendedSignatureInformation;
import at.gv.egiz.pdfas.api.xmldsig.ReconstructXMLDsigAfterAnalysisParameters;
import at.gv.egiz.pdfas.api.xmldsig.ReconstructXMLDsigParameters;
import at.gv.egiz.pdfas.api.xmldsig.ReconstructXMLDsigResult;
import at.gv.egiz.pdfas.api.xmldsig.XMLDsigData;
import at.gv.egiz.pdfas.commandline.CommandlineConnectorChooser;
import at.gv.egiz.pdfas.exceptions.ErrorCode;
import at.gv.egiz.pdfas.framework.DataSourceHolder;
import at.gv.egiz.pdfas.framework.config.SettingsHelper;
import at.gv.egiz.pdfas.framework.input.ExtractionStage;
import at.gv.egiz.pdfas.framework.input.PdfDataSource;
import at.gv.egiz.pdfas.framework.signator.SignatorInformation;
import at.gv.egiz.pdfas.framework.vfilter.VerificationFilterParameters;
import at.gv.egiz.pdfas.impl.api.analyze.AnalyzeResultImpl;
import at.gv.egiz.pdfas.impl.api.commons.DataSinkAdapter;
import at.gv.egiz.pdfas.impl.api.commons.PdfDataSourceAdapter;
import at.gv.egiz.pdfas.impl.api.commons.SignatureInformationAdapter;
import at.gv.egiz.pdfas.impl.api.commons.SignatureProfileImpl;
import at.gv.egiz.pdfas.impl.api.commons.TextDataSourceAdapter;
import at.gv.egiz.pdfas.impl.api.sign.ActualSignaturePositionAdapter;
import at.gv.egiz.pdfas.impl.api.sign.SignResultImpl;
import at.gv.egiz.pdfas.impl.api.verify.VerifyResultAdapter;
import at.gv.egiz.pdfas.impl.api.verify.VerifyResultsImpl;
import at.gv.egiz.pdfas.impl.input.DelimitedPdfDataSource;
import at.gv.egiz.pdfas.impl.vfilter.VerificationFilterParametersImpl;
import at.gv.egiz.pdfas.impl.xmldsig.XMLDsigReconstructor;
import at.gv.egiz.pdfas.placeholder.SignaturePlaceholderContext;
import at.gv.egiz.pdfas.placeholder.SignaturePlaceholderData;
import at.gv.egiz.pdfas.placeholder.SignaturePlaceholderExtractor;
import at.gv.egiz.pdfas.utils.ConfigUtils;
import at.knowcenter.wag.egov.egiz.PdfAS;
import at.knowcenter.wag.egov.egiz.PdfASID;
import at.knowcenter.wag.egov.egiz.cfg.SettingsReader;
import at.knowcenter.wag.egov.egiz.exceptions.OutOfMemoryException;
import at.knowcenter.wag.egov.egiz.exceptions.PDFDocumentException;
import at.knowcenter.wag.egov.egiz.exceptions.PresentableException;
import at.knowcenter.wag.egov.egiz.exceptions.SignatureException;
import at.knowcenter.wag.egov.egiz.framework.SignatorFactory;
import at.knowcenter.wag.egov.egiz.pdf.BinarySignatureHolder;
import at.knowcenter.wag.egov.egiz.pdf.NoSignatureHolder;
import at.knowcenter.wag.egov.egiz.pdf.ObjectExtractor;
import at.knowcenter.wag.egov.egiz.pdf.SignatureHolder;
import at.knowcenter.wag.egov.egiz.pdf.TablePos;
import at.knowcenter.wag.egov.egiz.pdf.TextualSignatureHolder;
import at.knowcenter.wag.egov.egiz.sig.SignatureResponse;
import at.knowcenter.wag.egov.egiz.sig.SignatureTypeDefinition;
import at.knowcenter.wag.egov.egiz.sig.SignatureTypes;

/**
 * Implementation of the {@link PdfAs} interface.
 * 
 * @author wprinz
 */
public class PdfAsObject implements PdfAs
{
//23.11.2010 changed by exthex - added methods for reconstructXMLDsig

  /**
   * The log.
   */
  private static Log log = LogFactory.getLog(CheckHelper.class);
  
  /**
   * This constructor is for internal use only - use
   * {@link at.gv.egiz.pdfas.PdfAsFactory} instead.
   * Note: IAIK JCE and IAIK ECC security providers are automatically registered.
   * 
   * @param workDirectory
   *          The work directory.
   * @throws PdfAsException
   *           Thrown, if the configuration cannot be processed.
   */
  public PdfAsObject(File workDirectory) throws PdfAsException
  {
     this(workDirectory, SettingsReader.REGISTER_IAIK_PROVIDERS_ON_DEFAULT);
  }
  
  /**
   * This constructor is for internal use only - use
   * {@link at.gv.egiz.pdfas.PdfAsFactory} instead.
   * 
   * @param workDirectory
   *          The work directory.
   * @param registerProvider <code>true</code>: automatically registers IAIK JCE and ECC Provider;
   * <code>false</code>: providers will NOT be automatically registered, providers
   * needed have to be registered by the API user 
   * @throws PdfAsException
   *           Thrown, if the configuration cannot be processed.
   */
  public PdfAsObject(File workDirectory, boolean registerProvider) throws PdfAsException
  {
    String path = workDirectory != null ? workDirectory.getPath() : null;
    SettingsReader.initialize(path, path);
    reloadConfig(registerProvider);
  }
  
  /**
   * This constructor is for internal use only - use
   * {@link at.gv.egiz.pdfas.PdfAsFactory} instead.
   * Note: IAIK JCE and IAIK ECC security providers are automatically registered.
   * 
   * @throws PdfAsException
   *           Thrown, if the configuration cannot be processed.
   */
  public PdfAsObject() throws PdfAsException
  {
     this(null);
  }
  
  /**
   * @see at.gv.egiz.pdfas.api.PdfAs#reloadConfig()
   */
  public void reloadConfig() throws PdfAsException
  {
     ConfigUtils.initializeLogger();
     SettingsReader.createInstance();
     SignatureTypes.createInstance();
  }
  
  /**
   * @param registerProvider <code>true</code>: automatically registers IAIK JCE and ECC Provider;
   * <code>false</code>: providers will NOT be automatically registered, providers
   * needed have to be registered by the API user 
   * @see at.gv.egiz.pdfas.api.PdfAs#reloadConfig()
   */
  private void reloadConfig(boolean registerProvider) throws PdfAsException
  {
    ConfigUtils.initializeLogger();
    SettingsReader.createInstance(registerProvider);
    SignatureTypes.createInstance();
  }

  /**
   * @see at.gv.egiz.pdfas.api.PdfAs#getProfileInformation()
   */
  public List getProfileInformation() throws PdfAsException
  {
     log.debug("Collecting profile information.");
    final String MOA_SIGN_KEY_IDENTIFIER_KEY = "moa.sign.KeyIdentifier";

    SettingsReader settings = SettingsReader.getInstance();
    final String defaultMoaKeyIdentifiert = settings.getSetting(MOA_SIGN_KEY_IDENTIFIER_KEY, null);

    SignatureTypes types = SignatureTypes.getInstance();
    List profiles = types.getSignatureTypeDefinitions();

    List profileInformation = new ArrayList(profiles.size());

    Iterator it = profiles.iterator();
    while (it.hasNext())
    {
      SignatureTypeDefinition profile = (SignatureTypeDefinition) it.next();

      final String profileId = profile.getType();
      log.debug("Processing profile \"" + profileId + "\".");
      final String moaKeyIdentifier = settings.getSetting("sig_obj." + profileId + "." + MOA_SIGN_KEY_IDENTIFIER_KEY, defaultMoaKeyIdentifiert);
      final String profileDescription = settings.getSetting("sig_obj." + profileId + "." + SignatureTypes.SIG_DESCR, null);

      // modified by tknall
      SignatureProfileImpl signatureProfile = new SignatureProfileImpl(profileId, profileDescription, moaKeyIdentifier);

      // start - added by tknall
      
      // signature entries relevant to the search algorithm
      Properties signatureEntries = new Properties();
      
      // search for table entries
      String parentPropertyKey = "sig_obj." + profileId + ".table";
      log.debug("Looking for subkeys of \"" + parentPropertyKey + "\".");
      Vector keysVector = settings.getSettingKeys(parentPropertyKey);
      if (keysVector != null) {
         Iterator keyIt = keysVector.iterator();
         while (keyIt.hasNext()) {
            String subKey = (String) keyIt.next();
            if (subKey != null && subKey.length() > 0) {
               String fullKey = parentPropertyKey + "." + subKey;
               String value = settings.getValueFromKey(fullKey);
               int lastIndex = fullKey.lastIndexOf(".");
               if (lastIndex != -1) {
                  String endsWith = fullKey.substring(lastIndex + 1);
                  if (value != null && value.length() > 0) {
                     if (NumberUtils.isDigits(endsWith)) {
                        signatureEntries.setProperty(fullKey, value);
                     } else {
                        log.debug("Ignoring table entry \"" + fullKey + "\" because it does not end with a digit. Therefore it is not relevant for the seach algorithm.");
                     }
                  } else {
                     log.warn("Problem detected with key \"" + fullKey + "\". The value is empty.");
                  }
               }
            }
         }
      }
      
      // search for table entries
      parentPropertyKey = "sig_obj." + profileId + ".key";
      log.debug("Looking for subkeys of \"" + parentPropertyKey + "\".");
      keysVector = settings.getSettingKeys(parentPropertyKey);
      if (keysVector != null) {
         Iterator keyIt = keysVector.iterator();
         while (keyIt.hasNext()) {
            String subKey = (String) keyIt.next();
            if (subKey != null && subKey.length() > 0) {
               String fullKey = parentPropertyKey + "." + subKey;
               String value = settings.getValueFromKey(fullKey);
               if (value != null && value.length() > 0) {
                  signatureEntries.setProperty(fullKey, value);
               } else {
                  log.warn("Problem detected with key \"" + fullKey + "\". The value is empty.");
               }
            }
         }
      }
      
      // set properties
      signatureProfile.setSignatureBlockEntries(signatureEntries);

      // stop - added by tknall
      
      profileInformation.add(signatureProfile);
    }

    return profileInformation;
  }

  /**
   * @see at.gv.egiz.pdfas.api.PdfAs#sign(at.gv.egiz.pdfas.api.sign.SignParameters)
   */
  public SignResult sign(SignParameters signParameters) throws PdfAsException
  {
    CheckHelper.checkSignParameters(signParameters);
    
    signParameters.setDocument(PdfAS.applyStrictMode(signParameters.getDocument()));
    
    SignaturePlaceholderData spd = null;
    SignaturePlaceholderContext.setSignaturePlaceholderData(null);
    if (signParameters.isCheckForPlaceholder()) {
       spd = SignaturePlaceholderExtractor.extract(signParameters.getDocument().createInputStream(), signParameters.getPlaceholderId(), signParameters.getPlaceholderMatchMode());
       if (spd != null){
          if (spd.getProfile() != null)
             signParameters.setSignatureProfileId(spd.getProfile());
          if (spd.getType() != null)
             signParameters.setSignatureType(spd.getType());
          if (spd.getKey() != null)
             signParameters.setSignatureKeyIdentifier(spd.getKey());
       }
    }
    CheckHelper.checkSignParameters(signParameters);
    
    if (signParameters.getSignatureProfileId() == null)
    {
      SettingsReader settings = SettingsReader.getInstance();
      String defaultProfile = settings.getValueFromKey(SignatureTypes.DEFAULT_TYPE);
      signParameters.setSignatureProfileId(defaultProfile);
    }

    PdfASID signatorId = null;
    if (signParameters.getSignatureType().equals(Constants.SIGNATURE_TYPE_BINARY))
    {
      signatorId = SignatorFactory.MOST_RECENT_BINARY_SIGNATOR_ID;
    }
    if (signParameters.getSignatureType().equals(Constants.SIGNATURE_TYPE_TEXTUAL))
    {
      signatorId = SignatorFactory.MOST_RECENT_TEXTUAL_SIGNATOR_ID;
    }
    if (signParameters.getSignatureType().equals(Constants.SIGNATURE_TYPE_DETACHEDTEXTUAL))
    {
      signatorId = SignatorFactory.MOST_RECENT_DETACHEDTEXT_SIGNATOR_ID;
    }

    TablePos pos = null;
    if (spd != null && spd.getTablePos() != null)
       pos = spd.getTablePos();
    else
       pos = PosHelper.formTablePos(signParameters.getSignaturePositioning());

    String connectorId = CommandlineConnectorChooser.chooseCommandlineConnectorForSign(signParameters.getSignatureDevice());

    try {
       SignatorInformation si = PdfAS.signCommandline(
             new PdfDataSourceAdapter(signParameters.getDocument()),
             new DataSinkAdapter(signParameters.getOutput()),
             signatorId,
             connectorId,
             signParameters.getSignatureProfileId(),
             signParameters.getSignatureKeyIdentifier(),
             pos,
             signParameters.getTimeStamperImpl(),
             signParameters.getProfileOverrideProperties()
       );
       return new SignResultImpl(signParameters.getOutput(), si.getSignSignatureObject().getX509Certificate(),
             new ActualSignaturePositionAdapter(si.getActualTablePos()), si.getNonTextualObjects());
    } catch (java.lang.OutOfMemoryError e) {
       throw new OutOfMemoryException(ErrorCode.OUT_OF_MEMORY_ERROR, "Insufficient memory allocated to virtual machine. Start Java with parameters \"-Xms128m -Xmx786m -XX:MaxPermSize=256m\".", e);
    }

  }

  /**
   * @see at.gv.egiz.pdfas.api.PdfAs#verify(at.gv.egiz.pdfas.api.verify.VerifyParameters)
   */
  public VerifyResults verify(VerifyParameters verifyParameters) throws PdfAsException
  {
    CheckHelper.checkVerifyParameters(verifyParameters);

    AnalyzeParameters ap = new AnalyzeParameters();
    fillAnalyzeParametersWithVerifyParameters(ap, verifyParameters);
    AnalyzeResult analyzeResult = analyze(ap);
    System.err.println(ToStringBuilder.reflectionToString(analyzeResult));

    if (verifyParameters.getSignatureToVerify() != Constants.VERIFY_ALL)
    {
      if (verifyParameters.getSignatureToVerify() >= analyzeResult.getSignatures().size())
      {
        throw new SignatureException(312, "The selected signature to be verified doesn't exist. " + verifyParameters.getSignatureToVerify());
      }

      Object stv = analyzeResult.getSignatures().get(verifyParameters.getSignatureToVerify());
      List selectedSignature = new ArrayList(1);
      selectedSignature.add(stv);
      analyzeResult = new AnalyzeResultImpl(selectedSignature);
    }

    VerifyAfterAnalysisParameters vaap = new VerifyAfterAnalysisParameters();
    vaap.setAnalyzeResult(analyzeResult);
    fillVerifyAfterAnalysisParametersWithVerifyParameters(vaap, verifyParameters);
    VerifyResults res = verify(vaap);
    
    return res;
    
  }
 

  /**
   * Copies all adequate parameters from the {@link VerifyParameters} to the
   * {@link AnalyzeParameters}.
   * 
   * @param ap
   *          The {@link AnalyzeParameters}.
   * @param vp
   *          The {@link VerifyParameters}.
   */
  protected void fillAnalyzeParametersWithVerifyParameters(AnalyzeParameters ap, VerifyParameters vp)
  {
    ap.setDocument(vp.getDocument());
    ap.setVerifyMode(vp.getVerifyMode());
    ap.setReturnNonTextualObjects(vp.isReturnNonTextualObjects());
  }

  protected void fillAnalyzeParametersWithReconstructXMLDsigParameters(AnalyzeParameters ap, ReconstructXMLDsigParameters rxp)
  {
    ap.setDocument(rxp.getDocument());
    ap.setVerifyMode(rxp.getVerifyMode());
    ap.setReturnNonTextualObjects(rxp.isReturnNonTextualObjects());
  }

  /**
   * Copies all adequate parameters from the {@link VerifyParameters} to the
   * {@link VerifyAfterAnalysisParameters}.
   * 
   * @param vaap
   *          The {@link VerifyAfterAnalysisParameters}.
   * @param vp
   *          The {@link VerifyParameters}.
   */
  protected void fillVerifyAfterAnalysisParametersWithVerifyParameters(VerifyAfterAnalysisParameters vaap, VerifyParameters vp)
  {
    vaap.setSignatureDevice(vp.getSignatureDevice());
    vaap.setVerificationTime(vp.getVerificationTime());
    vaap.setReturnHashInputData(vp.isReturnHashInputData());
  }


  protected void fillReconstructXMLDsigAfterAnalysisParametersWithVerifyAfterAnalysisParameters(
      ReconstructXMLDsigAfterAnalysisParameters reconstructParams,
      VerifyAfterAnalysisParameters verifyAfterAnalysisParameters) {
    reconstructParams.setAnalyzeResult(verifyAfterAnalysisParameters.getAnalyzeResult());
    reconstructParams.setReturnHashInputData(verifyAfterAnalysisParameters.isReturnHashInputData());
    reconstructParams.setSignatureDevice(verifyAfterAnalysisParameters.getSignatureDevice());
    reconstructParams.setVerificationTime(verifyAfterAnalysisParameters.getVerificationTime());
  }

  /**
   * @see at.gv.egiz.pdfas.api.PdfAs#analyze(at.gv.egiz.pdfas.api.analyze.AnalyzeParameters)
   */
  public AnalyzeResult analyze(AnalyzeParameters analyzeParameters) throws PdfAsException
  {
    CheckHelper.checkAnalyzeParameters(analyzeParameters);

    VerificationFilterParameters parametersConfig = SettingsHelper.readVerificationFilterParametersFromSettings();
    boolean binaryOnly = parametersConfig.extractBinarySignaturesOnly();
    if (analyzeParameters.getVerifyMode().equals(Constants.VERIFY_MODE_BINARY_ONLY))
    {
      binaryOnly = true;
    }
    boolean assumeOnlySB = parametersConfig.assumeOnlySignatureUpdateBlocks();
    if (analyzeParameters.getVerifyMode().equals(Constants.VERIFY_MODE_SEMI_CONSERVATIVE))
    {
      assumeOnlySB = true;
    }
    if (analyzeParameters.getVerifyMode().equals(Constants.VERIFY_MODE_FULL_CONSERVATIVE))
    {
      assumeOnlySB = false;
    }
    VerificationFilterParameters parameters = new VerificationFilterParametersImpl(binaryOnly, assumeOnlySB, parametersConfig.scanForOldSignatures());
    
    at.gv.egiz.pdfas.framework.input.DataSource inputDataSource = null;
    if (analyzeParameters.getDocument().getMimeType().equals("application/pdf"))
    {
      inputDataSource = new PdfDataSourceAdapter(analyzeParameters.getDocument());
    }
    else
    {
      try
      {
        inputDataSource = new TextDataSourceAdapter(analyzeParameters.getDocument());
      }
      catch (UnsupportedEncodingException e)
      {
        throw new PresentableException(ErrorCode.DOCUMENT_CANNOT_BE_READ, "The characterEncoding is not supported." + analyzeParameters.getDocument().getCharacterEncoding(), e);
      }
    }
    assert inputDataSource != null;
    
    try {
       ExtractionStage es = new ExtractionStage();
       DataSourceHolder dsh = new DataSourceHolder(inputDataSource);
       List signature_holders = es.extractSignatureHolders(dsh, parameters);
       
   
   //    List sigInfs = new ArrayList(signature_holders.size());
       List sigInfs = new ArrayList();
       List noSigs = new ArrayList();
       Iterator it = signature_holders.iterator();
       while (it.hasNext())
       {
         SignatureHolder sh = (SignatureHolder)it.next();
         
         if(sh instanceof NoSignatureHolder) {
           noSigs.add(sh);
         } else {
         
           SignatureInformation si = new SignatureInformationAdapter(sh);
           sigInfs.add(si);
           if (analyzeParameters.isReturnNonTextualObjects()) {           
              si.setNonTextualObjects(doExtractNonTexualObjects(sh, (PdfDataSource) dsh.getDataSource()));           
           }        
           
         }
       }
       return new AnalyzeResultImpl(sigInfs, noSigs, parameters.hasBeenCorrected());
    } catch (java.lang.OutOfMemoryError e) {
       throw new OutOfMemoryException(ErrorCode.OUT_OF_MEMORY_ERROR, "Insufficient memory allocated to virtual machine. Start Java with parameters \"-Xms128m -Xmx786m -XX:MaxPermSize=256m\".", e);
    }
    
  }

  private List doExtractNonTexualObjects(SignatureHolder sh, PdfDataSource pdfDataSource) {
     if (sh == null) return null;
     if (sh instanceof BinarySignatureHolder) {
        BinarySignatureHolder bsh = (BinarySignatureHolder)sh;
        return ObjectExtractor.extractNonTextInfo(bsh.getSignedPdf());
     } else if (sh instanceof TextualSignatureHolder) {
        TextualSignatureHolder tsh = (TextualSignatureHolder)sh;
        if (tsh.getUiBlockEndPos() == 0) {
           log.warn("uiblockendpos not available. Extract objects from final pdf document");
           return ObjectExtractor.extractNonTextInfo(pdfDataSource);
        }
        DelimitedPdfDataSource dpds = new DelimitedPdfDataSource(pdfDataSource, tsh.getUiBlockEndPos());
        return ObjectExtractor.extractNonTextInfo(dpds);
     } else {
        return null;
     }
  }

/**
   * @see at.gv.egiz.pdfas.api.PdfAs#verify(at.gv.egiz.pdfas.api.verify.VerifyAfterAnalysisParameters)
   */
  public VerifyResults verify(VerifyAfterAnalysisParameters verifyAfterAnalysisParameters) throws PdfAsException
  {
    CheckHelper.checkVerifyAfterAnalysisParameters(verifyAfterAnalysisParameters);

    List signatures = verifyAfterAnalysisParameters.getAnalyzeResult().getSignatures();
    
    // added by tknall
    if (signatures == null || signatures.isEmpty()) {
       throw new PDFDocumentException(ErrorCode.DOCUMENT_NOT_SIGNED, "PDF document not signed."); //$NON-NLS-1$
    }
    
    ReconstructXMLDsigAfterAnalysisParameters rxaap = new ReconstructXMLDsigAfterAnalysisParameters();
    fillReconstructXMLDsigAfterAnalysisParametersWithVerifyAfterAnalysisParameters(rxaap, verifyAfterAnalysisParameters);
    ReconstructXMLDsigResult reconstructResult = reconstructXMLDSIG(rxaap);
    
    VerifyAfterReconstructXMLDsigParameters varxp = new VerifyAfterReconstructXMLDsigParameters();
    fillVerifyAfterReconstructXMLDsigParametersWithVerifyAfterAnalysisParameters(varxp, verifyAfterAnalysisParameters);
    varxp.setReconstructXMLDsigResult(reconstructResult);
    
    return verify(varxp);
       
  }

  protected void fillVerifyAfterReconstructXMLDsigParametersWithVerifyAfterAnalysisParameters(
      VerifyAfterReconstructXMLDsigParameters varxp,
      VerifyAfterAnalysisParameters verifyAfterAnalysisParameters) {
    varxp.setReturnHashInputData(verifyAfterAnalysisParameters.isReturnHashInputData());
    varxp.setSignatureDevice(verifyAfterAnalysisParameters.getSignatureDevice());
    varxp.setVerificationTime(verifyAfterAnalysisParameters.getVerificationTime());
  }

  public ReconstructXMLDsigResult reconstructXMLDSIG(
      ReconstructXMLDsigParameters reconstructXMLDsigParameters)
      throws PdfAsException {
     
    AnalyzeParameters analyzeParameters = new AnalyzeParameters();
    fillAnalyzeParametersWithReconstructXMLDsigParameters(analyzeParameters, reconstructXMLDsigParameters);
    AnalyzeResult ar = analyze(analyzeParameters);
    
    ReconstructXMLDsigAfterAnalysisParameters rxaap = new ReconstructXMLDsigAfterAnalysisParameters();
    fillReconstructXMLDsigAfterAnalysisParametersWithReconstructXMLDsigParameters(rxaap, reconstructXMLDsigParameters);
    rxaap.setAnalyzeResult(ar);
    
    return reconstructXMLDSIG(rxaap);
  }

  protected void fillReconstructXMLDsigAfterAnalysisParametersWithReconstructXMLDsigParameters(
      ReconstructXMLDsigAfterAnalysisParameters rxaap,
      ReconstructXMLDsigParameters reconstructXMLDsigParameters) {
    rxaap.setReturnHashInputData(reconstructXMLDsigParameters.isReturnHashInputData());
    rxaap.setSignatureDevice(reconstructXMLDsigParameters.getSignatureDevice());
    rxaap.setVerificationTime(reconstructXMLDsigParameters.getVerificationTime());
  }

  public ReconstructXMLDsigResult reconstructXMLDSIG(
      ReconstructXMLDsigAfterAnalysisParameters reconstructXMLDsigParameters)
      throws PdfAsException {
     
    AnalyzeResult ar = reconstructXMLDsigParameters.getAnalyzeResult();
    List extendedSignatureInfos = new Vector();
    for (int i = 0; i < ar.getSignatures().size(); i++)
    {
       SignatureInformation si = (SignatureInformation)ar.getSignatures().get(i);
       XMLDsigData dsigData = XMLDsigReconstructor.reconstruct(si, reconstructXMLDsigParameters.getSignatureDevice());
       extendedSignatureInfos.add(new ExtendedSignatureInformation(si, dsigData));
    }
    return new ReconstructXMLDsigResult().setExtendedSignatures(extendedSignatureInfos);
  }

  public VerifyResults verify(
      VerifyAfterReconstructXMLDsigParameters verifyAfterReconstructXMLDsigParameters)
      throws PdfAsException {
     
     try {
        List extSignatures = verifyAfterReconstructXMLDsigParameters.getReconstructXMLDsigResult().getExtendedSignatures();
        List results = PdfAS.verifyExtendedSignatureHolders(extSignatures, 
              verifyAfterReconstructXMLDsigParameters.getSignatureDevice(), 
              verifyAfterReconstructXMLDsigParameters.isReturnHashInputData(), 
              verifyAfterReconstructXMLDsigParameters.getVerificationTime());
        
        List vrs = new ArrayList(results.size());
        
        assert extSignatures.size() == results.size() : "Not all signatures were verified.";
    
        for (int i = 0; i < extSignatures.size(); i++)
        {
          SignatureResponse response = (SignatureResponse) results.get(i);
          ExtendedSignatureInformation extSigInfo = (ExtendedSignatureInformation)extSignatures.get(i);
          SignatureHolder holder = (SignatureHolder) extSigInfo.getSignatureInformation().getInternalSignatureInformation();
    
          VerifyResult vr = new VerifyResultAdapter(response, holder, verifyAfterReconstructXMLDsigParameters.getVerificationTime());
          vr.setNonTextualObjects( extSigInfo.getSignatureInformation().getNonTextualObjects());
    
          vrs.add(vr);
        }
        
        VerifyResultsImpl verifyResults = new VerifyResultsImpl(vrs); 
        return verifyResults;
     } catch (java.lang.OutOfMemoryError e) {
        throw new OutOfMemoryException(ErrorCode.OUT_OF_MEMORY_ERROR, "Insufficient memory allocated to virtual machine. Start Java with parameters \"-Xms128m -Xmx786m -XX:MaxPermSize=256m\".", e);
     }
  }

   public DynamicSignatureProfile createDynamicSignatureProfile(String parentProfile, DynamicSignatureLifetimeEnum mode) {
      return DynamicSignatureProfileImpl.createFromParent(null, parentProfile, mode);
   }
   
   public DynamicSignatureProfile createEmptyDynamicSignatureProfile(DynamicSignatureLifetimeEnum mode) {
      return DynamicSignatureProfileImpl.createEmptyProfile(null, mode);
   }

   public DynamicSignatureProfile loadDynamicSignatureProfile(String name) {
      return DynamicSignatureProfileImpl.loadProfile(name);
   }

   public DynamicSignatureProfile createDynamicSignatureProfile(String myUniqueName,
         String parentProfile, DynamicSignatureLifetimeEnum mode) {
      return DynamicSignatureProfileImpl.createFromParent(myUniqueName, parentProfile, mode);
   }

   public DynamicSignatureProfile createEmptyDynamicSignatureProfile(String myUniqueName,
         DynamicSignatureLifetimeEnum mode) {
      return DynamicSignatureProfileImpl.createEmptyProfile(myUniqueName, mode);     
   }
   
     
}