/*
 * Copyright (c) 1997-2026 IDRsolutions (https://www.idrsolutions.com)
 */
package org.jpedal.examples.text;

import org.jpedal.PdfDecoderServer;
import org.jpedal.exception.PdfException;
import org.jpedal.grouping.SearchType;
import org.jpedal.utils.LogWriter;

import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 <h2>Find text in PDF files</h2>
 <p>
 * This class provides a simple Java API to find text in a PDF file
 * and also a static convenience method if you want to search a PDF file or directory containing PDF files
 <p>
 * <a href="https://www.idrsolutions.com/docs/jpedal/tutorials/search/find-text-in-a-pdf-file">See our Support Pages
 * for more information on Text Searching.</a>
 */
public class FindTextInRectangle extends BaseTextExtraction {

    /**
     * return value for testing
     */
    private final ArrayList<float[]> co_ords = new ArrayList<>();

    /**
     * word to find
     */
    private String textToFind;

    /**
     * Sets up an FindTextInRectangle instance to open a PDF File
     *
     @param file path to a single PDF file
     */
    public FindTextInRectangle(final File file) {
        this(file.getAbsolutePath());
    }

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

        init();
    }

    /**
     * Sets up an FindTextInRectangle instance to open  a PDF file contained as a BLOB within a byte[] stream
     *
     @param byteArray Array that will hold the BLOB
     */
    public FindTextInRectangle(final byte[] byteArray) {
        super(byteArray);

        init();
    }

    /**
     * routine to decode a file
     */
    @Override
    public void decodeFile(final String file_namethrows PdfException {

        fileName = file_name;
        if (!openPDFFile()) {
            return;
        }

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

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

                selectPage(currentPage);

                /* create a grouping object to apply grouping to data*/
                if (currentGrouping != null) {

                    /* Co-ordinates are x1,y1 (lower left hand corner), x2,y2(upper right) */

                    /* co-ords for start of object are returned in float object.
                     * if not found co-ords=null
                     * if found co_ords[0]=x1, co_ords[1]=y
                     */
                    final float[] co_ords = findTextOnPage(currentPage, textToFind, SearchType.MUTLI_LINE_RESULTS);

                    this.co_ords.add(co_ords);

                }
            }

            //remove data once written out
            decode_pdf.flushObjectValues(false);

        catch (final Exception e) {
            LogWriter.error(e,  "Exception thrown while trying to find text coordinates in " + file_name);

            System.exit(1);
        }
    }

    /**
     * Return the coords for the page specified.The origin of the coords is the bottom left hand corner (on unrotated
     * page)
     *
     @param textToFind test to look for
     @param page       :: Page number to check for results
     @param searchType A static int from org.jpedal.grouping.SearchType class
     *
     @return float[] containing all coords for the page, or empty array is no results found
     *         <br>[0]=result x1 coord
     *         <br>[1]=result y1 coord
     *         <br>[2]=result x2 coord
     *         <br>[3]=result y2 coord
     *         <br>[4]=either -101 to show that the next text area is the remainder of this word on another line else
     *         any other value is ignored.
     @throws org.jpedal.exception.PdfException PdfException
     */
    public float[] findTextOnPage(final int page, final String textToFind, final int searchTypethrows PdfException {
        checkFileOpened();
        selectPage(page);

        return currentGrouping.findText(new String[]{textToFind}, searchType);
    }

    /**
     * Return the coords for the page specified.The origin of the coords is the bottom left hand corner (on unrotated
     * page)
     *
     @param page       page to search
     @param x1         x1
     @param y1         y1
     @param x2         x2
     @param y2         y2
     @param textToFind text to look for
     @param searchType A static int from org.jpedal.grouping.SearchType class
     *
     @return float[] containing all coords for the page, or empty array is no results found
     *         <br>[0]=result x1 coord
     *         <br>[1]=result y1 coord
     *         <br>[2]=result x2 coord
     *         <br>[3]=result y2 coord
     *         <br>[4]=either -101 to show that the next text area is the remainder of this word on another line else
     *         any other value is ignored.
     @throws PdfException pdfException
     */
    public float[] findTextOnPage(final int page, final int x1, final int y1, final int x2, final int y2, final String textToFind, final int searchTypethrows PdfException {

        checkFileOpened();

        selectPage(page);

        return currentGrouping.findText(x1, y1, x2, y2, new String[]{textToFind}, searchType);
    }

    @Override
    void init() {
        //PdfDecoder returns a PdfException if there is a problem
        decode_pdf = new PdfDecoderServer(false);
        decode_pdf.setExtractionMode(PdfDecoderServer.TEXT)//extract just text
        PdfDecoderServer.init(true);
        //make sure widths in data CRITICAL if we want to split lines correctly!!
    }

    /**
     * Convenience method to find text in a PDF file
     *
     @param inputDir   a PDF file
     @param textToFind text to look for
     *
     @return ArrayList containing set of float[] values for all pages (-1 for actual page) * The origin of the coords
     *         is the bottom left hand corner (on unrotated page) organised in the following order.
     *         <br>[0]=result x1 coord
     *         <br>[1]=result y1 coord
     *         <br>[2]=result x2 coord
     *         <br>[3]=result y2 coord
     *         <br>[4]=either -101 to show that the next text area is the remainder of this word on another line else
     *         any other value is ignored. s
     @throws org.jpedal.exception.PdfException PdfException
     */
    public static List<float[]> findTextOnAllPages(final String inputDir, final String textToFindthrows PdfException {
        final FindTextInRectangle extract = new FindTextInRectangle(inputDir);

        extract.setup(textToFind);
        extract.processFiles(inputDir);

        extract.closePDFfile();

        return Collections.unmodifiableList(extract.co_ords);
    }

    private void setup(final String textToFind) {
        this.textToFind = textToFind;
    }
}