/*
 * Copyright (c) 1997-2019 IDRsolutions (https://www.idrsolutions.com)
 */

package org.jpedal.examples.text;

import org.jpedal.exception.PdfException;
import org.jpedal.utils.LogWriter;

import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;

/**
 <h2>Extract text from PDF files</h2>
 <br>
 * This class provides a simple Java API to extract text from a PDF file
 * and also a static convenience method if you just want to dump all the text
 * from a PDF file or directory containing PDF files<br>
 <br>
 <h3>Example 1 - access API methods</h3>
 <pre><code> ExtractTextInRectangle extract=new ExtractTextInRectangle("C:/pdfs/mypdf.pdf");
 * //extract.setPassword("password");
 * if (extract.openPDFFile()) {
 *     int pageCount=extract.getPageCount();
 *     for (int page=1; page&lt;=pageCount; page++) {
 *
 *        String text=extract.getTextOnPage(page);
 *     }
 * }
 *
 * extract.closePDFfile();</code></pre>
 <br>
 <h3>Example 2 - convenience static method</h3>
 * Extract text from a file or set of files and write out results as a txt file
 * Last value is maximum number of pages to process or -1 for all pages
 <br>
 <pre><code>ExtractTextInRectangle.writeAllOutlinesToDir("pdfs", "output", -1);</code></pre>
 *
 <h3>Example 3 - Access directly from the Jar</h3>
 * ExtractTextInRectangle can run from jar directly using the command line and
 * will extract any outlines from a PDF file or directory
 * to a defined output directory:<br>
 *
 <code>java -cp libraries_needed org/jpedal/examples/text/ExtractTextInRectangle inputValues</code><br>
 *
 * 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 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>
 *
 <br><a href="https://support.idrsolutions.com/hc/en-us/articles/115001889651-Extract-text-from-PDF-files">See our Support Pages for more information on Text Extraction.</a><br>
 */
public class ExtractTextInRectangle extends BaseTextExtraction {

    public static boolean isTest = true;

    private static String outputDirectory;
    
    /**
     * Sets up an ExtractTextInRectangle instance to open a PDF File
     *
     @param fileName full path to a single PDF file
     */
    public ExtractTextInRectangle(final String fileName) {
        super(fileName);

        init();
    }
    
    /**
     * Sets up an ExtractTextInRectangle instance to open a PDF File
     *
     @param fileName full path to a single PDF file
     @param extractPlainText flag to extract plain text rather than XML
     */
    public ExtractTextInRectangle(final String fileName, final boolean extractPlainText) {
        super(fileName, extractPlainText);
        
        init();
    }

    /**
     * Sets up an ExtractTextInRectangle instance to open  a PDF file contained as a BLOB within a byte[] stream
     *
     @param byteArray
     */
    public ExtractTextInRectangle(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()) {

            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 outputDir = outputDirectory + name + separator;

            //page range
            final int start = 1;
            int end = getPageCount();

            //limit to 1st ten pages in testing
            if (end > 10 && maxCount > && end > maxCount) {
                end = maxCount;
            }

            try {
                for (int page = start; page < end + 1; page++) { //read pages

                    selectPage(page);
                    
                    /*Co-ordinates are x1,y1 (top left hand corner), x2,y2(bottom right) */
                    final int x1 = currentPageData.getMediaBoxX(page);
                    final int x2 = currentPageData.getMediaBoxWidth(page+ x1;
                    final int y2 = currentPageData.getMediaBoxY(page);
                    final int y1 = currentPageData.getMediaBoxHeight(page+ y2;

                    /*
      text extracted by call
     */
                    String text = getTextOnPage(page, x1, y1, x2, y2);

                    if (isTest && text != null) { //ensure we test estimateParagrpahs flag in our code
                        text += currentGrouping.extractTextInRectangle(
                                x1,
                                y1,
                                x2,
                                y2,
                                page,
                                true,
                                true);
                    }


                    if (text != null) {

                        //ensure a directory for data
                        final File page_path = new File(outputDir + separator);
                        if (!page_path.exists()) {
                            page_path.mkdirs();
                        }

                        String prefix = ".txt";
                        final String encoding = System.getProperty("file.encoding");


                        if (ExtractTextInRectangle.isTest) {
                            prefix = ".xml";
                        }

                        OutputStreamWriter output_stream = null;
                                
                        try {
                            output_stream = new OutputStreamWriter(
                                        new FileOutputStream(outputDir + page + prefix),
                                        encoding
                            );
                            if (isTest) {
                                output_stream.write(
                                        "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\n");
                                output_stream.write(
                                        "<!-- Pixel Location of text x1,y1,x2,y2\n");
                                output_stream.write("(x1,y1 is top left corner)\n");
                                output_stream.write("(x1,y1 is bottom right corner)\n");
                                output_stream.write(
                                        "(origin is bottom left corner)  -->\n");
                                output_stream.write("\n\n<ARTICLE>\n");
                                output_stream.write(
                                        "<LOCATION x1=\""
                                                + x1
                                                "\" "
                                                "y1=\""
                                                + y1
                                                "\" "
                                                "x2=\""
                                                + x2
                                                "\" "
                                                "y2=\""
                                                + y2
                                                "\" />\n");
                                output_stream.write("\n\n<TEXT>\n");
                                //NOTE DATA IS TECHNICALLY UNICODE
                                output_stream.write(text)//write actual data
                                output_stream.write("\n\n</TEXT>\n");
                                output_stream.write("\n\n</ARTICLE>\n");
                            else {
                                output_stream.write(text)//write actual data
                            }
                        finally {
                            if (output_stream != null) {
                                try {
                                    output_stream.close();
                                catch (Exception e) {
                                    LogWriter.writeLog(e);
                                }
                            }                            
                        }
                    }
                    

                    //remove data once written out
                    decode_pdf.flushObjectValues(false);
                }
            catch (final Exception e) {
                throw new PdfException(e.getMessage());
            }
        }
    }

    public String getTextOnPage(final int pagethrows PdfException {

        checkFileOpened();

        selectPage(page);
        
        /*Co-ordinates are x1,y1 (top left hand corner), x2,y2(bottom right) */
        final int x1 = currentPageData.getMediaBoxX(page);
        final int x2 = currentPageData.getMediaBoxWidth(page+ x1;
        final int y2 = currentPageData.getMediaBoxY(page);
        final int y1 = currentPageData.getMediaBoxHeight(page+ y2;

        return currentGrouping.extractTextInRectangle(x1, y1, x2, y2, page, false, true);
    }

    public String getTextOnPage(final int page, final int x1, final int y1, final int x2, final int y2throws PdfException {

        checkFileOpened();

        selectPage(page);

        return currentGrouping.extractTextInRectangle(x1, y1, x2, y2, page, false, true);
    }


    /**
     * This class will allow you to extract any Words from page as a list via command line from a single PDF file or a directory of PDF files.
     <br>
     * The example expects two:
     <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.
     */
    @SuppressWarnings("unused")
    public static void main(final String[] args) {
        final int len = args.length;
        switch (len) {
            case 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);
            case 2:
                try {
                    ExtractTextAsWordlist.writeAllWordlistsToDir(args[0], args[1], -1);
                catch (final PdfException e) {
                    e.printStackTrace();
                }   
                break;
            default:
                System.out.println("too many arguments entered - run with no values to see defaults");
                
                final StringBuilder arguments = new StringBuilder();
                for (final String arg : args) {
                    arguments.append(arg).append('\n');
                }
                System.out.println("you entered:\n" + arguments + "as the arguments");
                
                System.exit(0);
        }
    }

    @Override
    void init() {

        type = BaseTextExtraction.ExtractTypes.TEXT_IN_RECTANGLE;

        super.init();

    }

    /**
     * Convenience method to write all the text in a directory of PDF files
     *
     @param inputDir  directory containing PDF files
     @param outputDir directory for writing out wordlists
     @throws org.jpedal.exception.PdfException
     */
    public static void writeAllTextToDir(final String inputDir, final String outputDir, final int maxPagesthrows PdfException {

        ExtractTextInRectangle.outputDirectory = outputDir;

        final ExtractTextInRectangle extract = new ExtractTextInRectangle(inputDir);

        extract.setup(outputDir, maxPages);

        extract.processFiles(inputDir);

        extract.closePDFfile();

    }

    private void setup(String outputDir, final int maxCount) {

        //check output dir has separator
        if (!outputDir.endsWith(separator)) {
            outputDir += separator;
        }

        this.output_dir = outputDir;
        this.maxCount = maxCount;
    }


}