/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.apache.pdfbox.pdmodel.interactive.digitalsignature.visible;

import java.awt.geom.AffineTransform;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.pdfbox.cos.COSName;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDResources;
import org.apache.pdfbox.pdmodel.common.PDRectangle;
import org.apache.pdfbox.pdmodel.common.PDStream;
import org.apache.pdfbox.pdmodel.graphics.form.PDFormXObject;
import org.apache.pdfbox.pdmodel.interactive.form.PDAcroForm;
import org.apache.pdfbox.pdmodel.interactive.form.PDSignatureField;

/**
 * Using that class, we build pdf template.
 * @author Vakhtang Koroghlishvili
 */
public class PDFTemplateCreator
{
    PDFTemplateBuilder pdfBuilder;
    private static final Log logger = LogFactory.getLog(PDFTemplateCreator.class);

    /**
     * sets PDFBuilder
     * 
     * @param bookBuilder
     */
    public PDFTemplateCreator(PDFTemplateBuilder bookBuilder)
    {
        pdfBuilder = bookBuilder;
    }

    /**
     * that method returns object of PDFStructure
     * 
     * @return PDFStructure
     */
    public PDFTemplateStructure getPdfStructure()
    {
        return pdfBuilder.getStructure();
    }

    /**
     * this method builds pdf  step by step, and finally it returns stream of visible signature
     * @param properties
     * @return InputStream
     * @throws IOException
     */
    public InputStream buildPDF(PDVisibleSignDesigner properties) throws IOException
    {
        logger.info("pdf building has been started");
        PDFTemplateStructure pdfStructure = pdfBuilder.getStructure();

        // we create array of [Text, ImageB, ImageC, ImageI]
        pdfBuilder.createProcSetArray();
        
        //create page
        pdfBuilder.createPage(properties);
        PDPage page = pdfStructure.getPage();

        //create template
        pdfBuilder.createTemplate(page);
        PDDocument template = pdfStructure.getTemplate();
        
        //create /AcroForm
        pdfBuilder.createAcroForm(template);
        PDAcroForm acroForm = pdfStructure.getAcroForm();

        // AcroForm contains signature fields
        pdfBuilder.createSignatureField(acroForm);
        PDSignatureField pdSignatureField = pdfStructure.getSignatureField();
        
        // create signature
        pdfBuilder.createSignature(pdSignatureField, page, properties.getSignatureFieldName());
       
        // that is /AcroForm/DR entry
        pdfBuilder.createAcroFormDictionary(acroForm, pdSignatureField);
        
        // create AffineTransform
        pdfBuilder.createAffineTransform(properties.getAffineTransformParams());
        AffineTransform transform = pdfStructure.getAffineTransform();
       
        // rectangle, formatter, image. /AcroForm/DR/XObject contains that form
        pdfBuilder.createSignatureRectangle(pdSignatureField, properties);
        pdfBuilder.createFormatterRectangle(properties.getFormatterRectangleParams());
        PDRectangle formatter = pdfStructure.getFormatterRectangle();
        pdfBuilder.createSignatureImage(template, properties.getImage());

        // create form stream, form and  resource. 
        pdfBuilder.createHolderFormStream(template);
        PDStream holderFormStream = pdfStructure.getHolderFormStream();
        pdfBuilder.createHolderFormResources();
        PDResources holderFormResources = pdfStructure.getHolderFormResources();
        pdfBuilder.createHolderForm(holderFormResources, holderFormStream, formatter);
        
        // that is /AP entry the appearance dictionary.
        pdfBuilder.createAppearanceDictionary(pdfStructure.getHolderForm(), pdSignatureField);
        
        // inner form stream, form and resource (hlder form containts inner form)
        pdfBuilder.createInnerFormStream(template);
        pdfBuilder.createInnerFormResource();
        PDResources innerFormResource = pdfStructure.getInnerFormResources();
        pdfBuilder.createInnerForm(innerFormResource, pdfStructure.getInnerFormStream(), formatter);
        PDFormXObject innerForm = pdfStructure.getInnerForm();
       
        // inner form must be in the holder form as we wrote
        pdfBuilder.insertInnerFormToHolderResources(innerForm, holderFormResources);
        
        //  Image form is in this structure: /AcroForm/DR/FRM0/Resources/XObject/n0
        pdfBuilder.createImageFormStream(template);
        PDStream imageFormStream = pdfStructure.getImageFormStream();
        pdfBuilder.createImageFormResources();
        PDResources imageFormResources = pdfStructure.getImageFormResources();
        pdfBuilder.createImageForm(imageFormResources, innerFormResource, imageFormStream, formatter,
                transform, pdfStructure.getImage());
       
        // now inject procSetArray
        pdfBuilder.injectProcSetArray(innerForm, page, innerFormResource, imageFormResources,
                holderFormResources, pdfStructure.getProcSet());

        COSName imgFormName = pdfStructure.getImageFormName();
        COSName imgName = pdfStructure.getImageName();
        COSName innerFormName = pdfStructure.getInnerFormName();

        // now create Streams of AP
        pdfBuilder.injectAppearanceStreams(holderFormStream, imageFormStream, imageFormStream,
                imgFormName, imgName, innerFormName, properties);
        pdfBuilder.createVisualSignature(template);
        pdfBuilder.createWidgetDictionary(pdSignatureField, holderFormResources);
        
        ByteArrayInputStream in = pdfStructure.getTemplateAppearanceStream();
        logger.info("stream returning started, size= " + in.available());
        
        // we must close the document
        template.close();
        
        // return result of the stream 
        return in;
    }
}

@@ -1563,38 +1563,26 @@
 %0A * 
-Using that class, we
+Class to
  build 
-pdf
+PDF
  tem
@@ -1588,16 +1588,19 @@
 mplate.%0A
+ *%0A
  * @auth
@@ -1664,24 +1664,38 @@
 eator%0A%7B%0A    
+private final 
 PDFTemplateB
@@ -1816,23 +1816,20 @@
   * 
-sets PDFBuilder
+Constructor.
 %0A   
@@ -1847,20 +1847,24 @@
  @param 
-book
+template
 Builder%0A
@@ -1920,20 +1920,24 @@
 Builder 
-book
+template
 Builder)
@@ -1968,12 +1968,16 @@
 r = 
-book
+template
 Buil
@@ -2007,41 +2007,31 @@
   * 
-that method returns object of PDF
+Returns the PDFTemplate
 Stru
@@ -2031,24 +2031,32 @@
 ateStructure
+ object.
 %0A     * %0A   
@@ -2070,21 +2070,8 @@
 turn
- PDFStructure
 %0A   
@@ -2199,96 +2199,92 @@
   * 
-this method builds pdf  step by step, and finally it returns stream of visible signature
+Build a PDF with a visible signature step by step, and return it as a stream.%0A     *
 %0A   

improve javadoc, rename parameter names