/*
 * ===========================================
 * Java Pdf Extraction Decoding Access Library
 * ===========================================
 *
 * Project Info:  http://www.idrsolutions.com
 * Help section for developers at http://www.idrsolutions.com/support/
 *
 * (C) Copyright 1997-2015 IDRsolutions and Contributors.
 *
 * This file is part of JPedal/JPDF2HTML5
 *
 
 *
 * ---------------
 * ExtractStructuredText.java
 * ---------------
 */

package org.jpedal.examples.text;

import java.io.File;
import java.io.InputStream;

import org.jpedal.exception.PdfException;

import org.w3c.dom.Document;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.Transformer;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamSource;
import javax.xml.transform.stream.StreamResult;

/**
 <h2>Extract Structured Content (if present) from PDF files</h2>
 *
 * This class provides a simple Java API to extract Structured Content (if present) from a PDF file and also a static convenience method if you just want to dump any structured outlines from a PDF file or directory containing PDF files<p>
 * If no Structure is present a blank file is returned<p>
 <h3>Example 1 - access API methods</h3>
 <pre><code>ExtractStructuredText extract=new ExtractStructuredText("C:/pdfs/mypdf.pdf");
 * //extract.setPassword("password");
 * if (extract.openPDFFile()) {
 *     Document anyStructuredText=extract.getStructuredTextContent();
 * }
 *
 * extract.closePDFfile();</code></pre>
 *
 <h3>Example 2 - convenience static method</h3>
 * Extract any Structured test for a file or set of files and write out results as XML in a txt file (separate directory for each PDF file)<p>
 *
 <pre><code>ExtractStructuredText.writeAllStructuredTextOutlinesToDir("pdfs", "output");</code></pre>
 
 <h3>Example 3 - Access directly from the Jar</h3>
 * ExtractStructuredText can run from jar directly using the command line and will extract any data from a PDF file or directory
 * to a defined output directory<p>
 *
 <code>java -cp libraries_needed org/jpedal/examples/text/ExtractStructuredText inputValues</code><p>
 *
 * Where inputValues is 2 values:
 <ul>
 <li>First value:  The PDF filename (including the path if needed) or a directory containing PDF files. If it contains spaces it must be enclosed by double quotes (ie "C:/Path with spaces/").</li>
 <li>Second value: The location to write out outline data extracted from the PDF file or files. If it contains spaces it must be enclosed by double quotes (ie "C:/Path with spaces/").</li>
 </ul>
 *
 <p>For non-structured files, consider:
 <ul>
 <li>http://files.idrsolutions.com/samplecode/org/jpedal/examples/text/ExtractTextAsWordlist.java.html</li>
 <li>http://files.idrsolutions.com/samplecode/org/jpedal/examples/text/ExtractTextInRectangle.java.html</li>
 </ul>
 
 <p><a href="http://www.idrsolutions.com/how-to-extract-text-from-pdf-files/">See our Support Pages for more information on Text Extraction</a></p>
 */
public class ExtractStructuredText extends BaseTextExtraction{

    /** Sets up an ExtractStructuredText instance to open a PDF File
     @param fileName full path to a single PDF file
     */
    public ExtractStructuredTextString fileName )
    {
        super(fileName);
        
        init();
    }
    
    /** Sets up an ExtractStructuredText instance to open  a PDF file contained as a BLOB within a byte[] stream
     *
     @param byteArray
     */
    public ExtractStructuredText(final byte[] byteArray )
    {
        super(byteArray);
        
        init();
    }
    
    /**
     * routine to decode a file
     */
    @Override
    void decodeFile(final String file_namethrows PdfException {
        
        this.fileName=file_name;
        if(openPDFFile()){
            
            //read pages -if you already have code this is probably
            //all you need!
            final Document tree = getStructuredTextContent();
            
            if (tree != null) {
                
                /**
                 * format tree
                 */
                final InputStream stylesheet = this.getClass().getResourceAsStream("/org/jpedal/examples/text/xmlstyle.xslt");
                
                final TransformerFactory transformerFactory = TransformerFactory.newInstance();
                
                /**output tree*/
                try {
                    final Transformer transformer = transformerFactory.newTransformer(new StreamSource(stylesheet));
                    
                    //useful for debugging
                    //transformer.transform(new DOMSource(tree), new StreamResult(System.out));
                    
                    if(tree==null || !tree.hasChildNodes()){
                       return;
                    }
                    
                    //warn user if no content present
                    if(!tree.getDocumentElement().hasChildNodes()){
                        tree.appendChild(tree.createComment("There is NO Structured text in the file to extract!!"));
                        tree.appendChild(tree.createComment("JPedal can only extract it if it has been added when PDF created"));
                        tree.appendChild(tree.createComment("Please read our blog post at http://www.jpedal.org/PDFblog/2010/09/the-easy-way-to-discover-if-a-pdf-file-contains-structured-content/ "));
                    }
                    
                    //get just the name of the file without the path to use as a sub-directory or .pdf
                    String name = "demo"//set a default just in case
                    
                    final int pointer = file_name.lastIndexOf(separator);
                    
                    if (pointer != -1) {
                        name = file_name.substring(pointer + 1, file_name.length() 4);
                    }
                    
                    final String outputFile=output_dir + separator + name + ".xml";
                    
                    final File output = new File(output_dir);
                    
                    if(!output.exists()){
                        final File createDir = new File(output_dir);
                        createDir.mkdirs();
                        output.createNewFile();
                    }
                    
                    transformer.transform(new DOMSource(tree)new StreamResult(outputFile));
                    
                catch (final Exception e) {
                    throw new PdfException(e.getMessage());
                catch (final Error e) {
                    throw new PdfException(e.getMessage());
                }
            }
        }      
    }

    
    /**
     * This class will allow you to extract any Structured Text data via command line from a single PDF file or a directory of PDF files.
     <p>
     * The example expects two or three parameters:
     <ul>
     *     <li>Value 1 is the file name or directory of PDF files to process</li>
     *     <li>Value 2 is directory to write out the outline data</li>
     </ul>
     @param args The expected arguments are described above.
     */
    public static void mainfinal String[] args )
    {
        final int len=args.length;
        if (len == 0){
            System.out.println("Example takes 2 parameters");
            System.out.println("Value 1 is the file name or directory of PDF files to process");
            System.out.println("Value 2 is Directory for writing the data as text files");
            System.exit(0);
            
        }else if(len==2){
            
            try{
                ExtractStructuredText.writeAllStructuredTextOutlinesToDir(args[0],args[1]);
            }catch(PdfException e){
                e.printStackTrace();
            }
            
        }else {
            
            System.out.println("too many arguments entered - run with no values to see defaults");
            
            StringBuilder arguments=new StringBuilder();
            for (final String arg : args) {
                arguments.append(arg).append('\n');
            }
            System.out.println("you entered:\n"+ arguments +"as the arguments");
            //<start-demo><end-demo>
        }
    }
    
    @Override
    void init() {
        
        type=BaseTextExtraction.ExtractTypes.STRUCTURED_TEXT;
        
        super.init();
        
    }
    
    /**
     * Convenience method to write any Structured text in a directory of PDF files
     *
     @param inputDir directory containing PDF files
     @param outputDir directory for writing out images
     @throws org.jpedal.exception.PdfException
     */
    public static void writeAllStructuredTextOutlinesToDir(String inputDir,String outputDirthrows PdfException
    {
        ExtractStructuredText extract=new ExtractStructuredText(inputDir);
        
        extract.setup(outputDir);
        
        extract.processFiles(inputDir);
        
        extract.closePDFfile();
    }
    
    private void setup(String outputDir) {
        
        //check output dir has separator
        if (!outputDir.endsWith(separator)) {
            outputDir += separator;
        }
        
        this.output_dir=outputDir;
    }
    
    /**
     * gets the Document containing any Structured text (if present) as a Document structure
     
     * If the Document does not contain the meta data for Structured Content, an empty Document is returned
     @return Document
     */
    public Document getStructuredTextContent() {
        return decode_pdf.getMarkedContent();
    }
}