package demo;

import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Iterator;
import java.util.List;

import at.gv.egiz.pdfas.PdfAsFactory;
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.exceptions.PdfAsException;
import at.gv.egiz.pdfas.api.io.DataSource;
import at.gv.egiz.pdfas.api.sign.SignParameters;
import at.gv.egiz.pdfas.api.sign.pos.SignaturePositioning;
import at.gv.egiz.pdfas.api.verify.VerifyAfterAnalysisParameters;
import at.gv.egiz.pdfas.api.verify.VerifyResult;
import at.gv.egiz.pdfas.commandline.Main;
import at.gv.egiz.pdfas.framework.config.SettingsHelper;
import at.gv.egiz.pdfas.framework.vfilter.VerificationFilterParameters;
import at.gv.egiz.pdfas.io.FileBasedDataSink;
import at.gv.egiz.pdfas.io.FileBasedDataSource;

public final class APIDemo {
   
   /**
    * Disable instantiation.
    */
   private APIDemo() {
   }
   
   /**
    * Verifies a pdf document.
    * @param configuration The folder containing the pdf-as work directory (including the configuration).
    * @param source The signed pdf document.
    * @param verifyDevice The device used for verification
    *    (see {@link Constants#SIGNATURE_DEVICE_MOA} and {@link Constants#SIGNATURE_DEVICE_BKU}).
    * @throws PdfAsException Thrown in case of an error.
    * @throws IOException Thrown in case of an i/o error.
    */
   public static void verify(File configuration, File source, String verifyDevice) throws PdfAsException, IOException {
      
      // instantiate api
      PdfAs pdfasAPI = PdfAsFactory.createPdfAs(configuration);

      // set source
      DataSource dataSource = new FileBasedDataSource(source, "application/pdf");

      // evaluate settings
      VerificationFilterParameters parameters = SettingsHelper.readVerificationFilterParametersFromSettings();
      String verifyMode = Constants.VERIFY_MODE_FULL_CONSERVATIVE;
      
      if (parameters.extractBinarySignaturesOnly()) {
         verifyMode = Constants.VERIFY_MODE_BINARY_ONLY;
      } else if (parameters.assumeOnlySignatureUpdateBlocks()) {
         verifyMode = Constants.VERIFY_MODE_SEMI_CONSERVATIVE;
      } else {
         verifyMode = Constants.VERIFY_MODE_FULL_CONSERVATIVE;
      }
      
      // configure analyze parameters
      AnalyzeParameters analyzeParameters = new AnalyzeParameters();
      analyzeParameters.setDocument(dataSource);
      analyzeParameters.setVerifyMode(verifyMode);
      
      // analyze
      System.out.println("Analyzing...");
      AnalyzeResult analyzeResult = pdfasAPI.analyze(analyzeParameters);
      System.out.println("Successfully analyzed.");

      // setup verification
      VerifyAfterAnalysisParameters vaap = new VerifyAfterAnalysisParameters();
      vaap.setAnalyzeResult(analyzeResult);
      vaap.setReturnHashInputData(true);
      vaap.setSignatureDevice(verifyDevice);
      vaap.setVerificationTime(null);
      
      // invoke verification
      System.out.println("Verifying...");
      List verifyResults = pdfasAPI.verify(vaap).getResults();
      System.out.println("Verification complete.");

      // iterate over results
      PrintWriter out = new PrintWriter(System.out);
      Iterator it = verifyResults.iterator();
      while (it.hasNext()) {
         VerifyResult result = (VerifyResult) it.next();
         Main.formatVerifyResult(result, out);
      }
      out.flush();
      out.close();

   }
   
   /**
    * Signs a pdf document.
    * @param configuration The folder containing the pdf-as work directory (including the configuration).
    * @param source The unsigned pdf document.
    * @param signatureDevice The device used for signature
    *    (see {@link Constants#SIGNATURE_DEVICE_MOA} and {@link Constants#SIGNATURE_DEVICE_BKU}).
    * @throws PdfAsException Thrown in case of an error.
    * @throws IOException Thrown in case of an i/o error.
    * @param destination The signed pdf document.
    * @param signatureMode The mode used for signature (see {@link Constants#SIGNATURE_TYPE_BINARY}
    * resp. {@link Constants#SIGNATURE_TYPE_TEXTUAL} or {@link Constants#SIGNATURE_TYPE_DETACHEDTEXTUAL}).
    * @param signatureProfile The profile used for signature.
    * @param signaturePos The position of the signature (see {@link SignaturePositioning}) or {@code null}.
    */
   private static void sign(File configuration, File source, File destination,
         String signatureMode, String signatureDevice, String signatureProfile,
         SignaturePositioning signaturePos) throws PdfAsException, IOException {
      
      // instantiate api
      PdfAs pdfasAPI = PdfAsFactory.createPdfAs(configuration);

      // set source
      DataSource dataSource = new FileBasedDataSource(source, "application/pdf");

      // set output
      FileBasedDataSink dataSink = new FileBasedDataSink(destination);

      // configure signature
      SignParameters signParameters = new SignParameters();
      signParameters.setDocument(dataSource);
      signParameters.setOutput(dataSink);
      signParameters.setSignatureType(signatureMode);
      signParameters.setSignatureDevice(signatureDevice);
      signParameters.setSignatureProfileId(signatureProfile);
      signParameters.setSignaturePositioning(signaturePos);

       // sign
      System.out.println("Signing...");
      pdfasAPI.sign(signParameters);
      
      System.out.println("Successfully signed.");
         
   }

   /**
    * Start a demo that signs a document and performs a verification afterwards.
    * @param args The parameter(s).
    */
   public static void main(String[] args) {
      
      File configdir = new File("./work");
      File unsignedFile = new File("./test-files/blindtext.pdf");
      File signedFile = new File("./test-files/blindtext_signed.pdf");
      
      String signatureMode    = Constants.SIGNATURE_TYPE_BINARY;
      String signatureDevice  = Constants.SIGNATURE_DEVICE_MOA;
      String signatureProfile = "SIGNATURBLOCK_DE";
      SignaturePositioning signaturePos = null;
         
      try {

         sign(configdir, unsignedFile, signedFile, signatureMode, signatureDevice, signatureProfile, signaturePos);
         verify(configdir, signedFile, signatureDevice);
         
      } catch (PdfAsException e) {
         e.printStackTrace();
      } catch (IOException e) {
         e.printStackTrace();
      }
      
   }

}