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

import org.jpedal.PdfDecoderInt;
import org.jpedal.display.Display;
import org.jpedal.examples.viewer.commands.AccelerationOff;
import org.jpedal.examples.viewer.commands.AccelerationOn;
import org.jpedal.examples.viewer.commands.AlwaysShowMouse;
import org.jpedal.examples.viewer.commands.AutoScroll;
import org.jpedal.examples.viewer.commands.BitMap;
import org.jpedal.examples.viewer.commands.Bookmark;
import org.jpedal.examples.viewer.commands.Buy;
import org.jpedal.examples.viewer.commands.ChangeLineArt;
import org.jpedal.examples.viewer.commands.Continuous;
import org.jpedal.examples.viewer.commands.ContinuousFacing;
import org.jpedal.examples.viewer.commands.Copy;
import org.jpedal.examples.viewer.commands.DeSelectAll;
import org.jpedal.examples.viewer.commands.DeletePropertiesOnExit;
import org.jpedal.examples.viewer.commands.DocInfo;
import org.jpedal.examples.viewer.commands.Exit;
import org.jpedal.examples.viewer.commands.ExtractImages;
import org.jpedal.examples.viewer.commands.ExtractSelectionAsImage;
import org.jpedal.examples.viewer.commands.ExtractText;
import org.jpedal.examples.viewer.commands.Facing;
import org.jpedal.examples.viewer.commands.Find;
import org.jpedal.examples.viewer.commands.FullScreen;
import org.jpedal.examples.viewer.commands.Help;
import org.jpedal.examples.viewer.commands.Highlight;
import org.jpedal.examples.viewer.commands.Info;
import org.jpedal.examples.viewer.commands.Manipulate;
import org.jpedal.examples.viewer.commands.MouseModeCommand;
import org.jpedal.examples.viewer.commands.NavigateDocuments;
import org.jpedal.examples.viewer.commands.NextResults;
import org.jpedal.examples.viewer.commands.OpenFile;
import org.jpedal.examples.viewer.commands.OpenInSystemDefault;
import org.jpedal.examples.viewer.commands.PageCount;
import org.jpedal.examples.viewer.commands.PageFlow;
import org.jpedal.examples.viewer.commands.PageGrouping;
import org.jpedal.examples.viewer.commands.PageNavigator;
import org.jpedal.examples.viewer.commands.PanMode;
import org.jpedal.examples.viewer.commands.Preferences;
import org.jpedal.examples.viewer.commands.PreviousResult;
import org.jpedal.examples.viewer.commands.Print;
import org.jpedal.examples.viewer.commands.ReplaceTextColor;
import org.jpedal.examples.viewer.commands.Reset;
import org.jpedal.examples.viewer.commands.Rotation;
import org.jpedal.examples.viewer.commands.RotationLeft;
import org.jpedal.examples.viewer.commands.RotationRight;
import org.jpedal.examples.viewer.commands.SaveFile;
import org.jpedal.examples.viewer.commands.SaveForm;
import org.jpedal.examples.viewer.commands.Scaling;
import org.jpedal.examples.viewer.commands.Scroll;
import org.jpedal.examples.viewer.commands.SelectAll;
import org.jpedal.examples.viewer.commands.SeparateCover;
import org.jpedal.examples.viewer.commands.SetDisplayBackground;
import org.jpedal.examples.viewer.commands.SetEnhanceFractionalLines;
import org.jpedal.examples.viewer.commands.SetHideLineWeights;
import org.jpedal.examples.viewer.commands.SetHighlightFormFields;
import org.jpedal.examples.viewer.commands.SetPageColor;
import org.jpedal.examples.viewer.commands.SetReplacementThreshold;
import org.jpedal.examples.viewer.commands.SetTextColor;
import org.jpedal.examples.viewer.commands.SetUndrawnPageColor;
import org.jpedal.examples.viewer.commands.ShowFormNames;
import org.jpedal.examples.viewer.commands.Sign;
import org.jpedal.examples.viewer.commands.Single;
import org.jpedal.examples.viewer.commands.Snapshot;
import org.jpedal.examples.viewer.commands.Text;
import org.jpedal.examples.viewer.commands.TextSelect;
import org.jpedal.examples.viewer.commands.Tip;
import org.jpedal.examples.viewer.commands.TriggerGC;
import org.jpedal.examples.viewer.commands.UpdateGUILayout;
import org.jpedal.examples.viewer.commands.ViewStack;
import org.jpedal.examples.viewer.commands.Viewable;
import org.jpedal.examples.viewer.commands.VisitWebsite;
import org.jpedal.examples.viewer.commands.ZoomIn;
import org.jpedal.examples.viewer.commands.ZoomOut;
import org.jpedal.examples.viewer.gui.SwingGUI;
import org.jpedal.examples.viewer.gui.swing.SearchList;
import org.jpedal.examples.viewer.gui.swing.SwingSearchWindow;
import org.jpedal.examples.viewer.gui.swing.SwingThumbnailPanel;
import org.jpedal.examples.viewer.utils.Printer;
import org.jpedal.examples.viewer.utils.PropertiesFile;
import org.jpedal.external.JPedalActionHandler;
import org.jpedal.external.Options;
import org.jpedal.utils.LogWriter;
import org.jpedal.utils.Messages;

import java.awt.Rectangle;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Map;

/**
 * <h2><b>Commands</b></h2>
 * <br>
 * <p>This class contains code to execute the actual commands :
 * <a href="https://www.idrsolutions.com/docs/jpedal/tutorials/viewer/access-pdf-viewer-features-from-your-code">Access
 * PDF Viewer features from your code.</a></p>
 */
@SuppressWarnings({"WeakerAccess", "OverlyLongMethod"})
public class Commands {

    /**
     * used to store the IE views so we can go back to previous views and store changes
     */
    protected final ViewStack viewStack = new ViewStack();

    /**
     * True while the Viewer is waiting for the user to drag an area to extract as an image, after {@link #SNAPSHOT}. It
     * is set back to false once the area has been extracted.
     */
    public boolean extractingAsImage;

    private final Printer currentPrinter;

    /*
     * Important! You must also update ViewerCommands.java
     */
    //0-50 handled in executeMenuBarCommands(final int ID, Object[] args)
    /** Show the About dialog with the version details. Does nothing if arguments are passed. */
    public static final int ABOUT = 1;
    /** Show a dialog to export a range of pages as images. Does nothing if arguments are passed. */
    public static final int BITMAP = 2;
    /** Show a dialog to extract the images embedded in a range of pages. Does nothing if arguments are passed. */
    public static final int IMAGES = 3;
    /** Show a dialog to extract the text from a range of pages. Does nothing if arguments are passed. */
    public static final int TEXT = 4;
    /** Show a dialog to save the open file. Does nothing if arguments are passed. */
    public static final int SAVE = 5;
    /** Show the print dialog for the open document. Does nothing if arguments are passed. */
    public static final int PRINT = 6;
    /**
     * Close the document and the Viewer, saving the Viewer settings and warning about unsaved forms first. The JVM
     * exits if {@link Viewer#exitOnClose} is true. Does nothing if arguments are passed.
     */
    public static final int EXIT = 7;
    /**
     * Toggle auto scrolling, which scrolls the view when the mouse is dragged past its edge. Does nothing if arguments
     * are passed.
     */
    public static final int AUTOSCROLL = 8;
    /** Show the document properties dialog. Does nothing if arguments are passed. */
    public static final int DOCINFO = 9;
    /**
     * Open a file. With no arguments a file chooser is shown. Otherwise, args are a File or String path, optionally
     * followed by a String named destination to go to; an InputStream, optionally followed by a String file name; or a
     * byte[] followed by a String file name. The file name's extension decides whether it is opened as a PDF or an
     * image.
     */
    public static final int OPENFILE = 10;
    /** Go to the page of a bookmark. The arg is the String bookmark title and must be passed. */
    public static final int BOOKMARK = 11;
    /**
     * Search the document. With no arguments the search window is shown, filled in with any highlighted text. Otherwise,
     * args are the String search term, optionally followed by all three of an Integer of
     * {@link org.jpedal.grouping.SearchType} flags, a Boolean for whether the term holds several words to search for
     * separately, and a Boolean for whether to search only the current page. If all 3 optional values aren't present only the first is used.
     */
    public static final int FIND = 12;
    /**
     * Let the user drag an area of the page to extract as an image. Only works in single page view. Returns a Boolean
     * that is true while waiting for the user to drag the area.
     */
    public static final int SNAPSHOT = 13;
    /** Open a PDF from a URL. With no arguments a dialog asks for the URL. Otherwise, the arg is the String URL. */
    public static final int OPENURL = 14;
    /** Open the IDRsolutions website in the default browser. Does nothing if arguments are passed. */
    public static final int VISITWEBSITE = 15;
    /** Open the previous document in the recent documents list. Does nothing if arguments are passed. */
    public static final int PREVIOUSDOCUMENT = 16;
    /** Open the next document in the recent documents list. Does nothing if arguments are passed. */
    public static final int NEXTDOCUMENT = 17;
    /**
     * Show the previous search result, wrapping round to the last result. Returns {@link #SEARCH_RETURNED_TO_START},
     * {@link #SEARCH_NOT_FOUND}, {@link #FIRST_DOCUMENT_SEARCH_RESULT_NOW_SHOWN} or null. Does nothing if arguments are
     * passed.
     */
    public static final int PREVIOUSRESULT = 18;
    /**
     * Show the next search result, wrapping round to the first result. Returns {@link #SEARCH_RETURNED_TO_START},
     * {@link #SEARCH_NOT_FOUND}, {@link #FIRST_DOCUMENT_SEARCH_RESULT_NOW_SHOWN} or null. Does nothing if arguments are
     * passed.
     */
    public static final int NEXTRESULT = 19;
    /** Show the Tip of the Day dialog. Does nothing if arguments are passed. */
    public static final int TIP = 20;
    /** Show the preferences dialog. Does nothing if arguments are passed. */
    public static final int PREFERENCES = 24;
    /** Copy the highlighted text to the clipboard. Arguments are ignored. */
    public static final int COPY = 25;
    /** Highlight all the text on the current page. Only works in single page view. Arguments are ignored. */
    public static final int SELECTALL = 26;
    /** Clear all highlighted text and images. Only works in single page view. Arguments are ignored. */
    public static final int DESELECTALL = 27;
    /**
     * Show or hide part of the Viewer's GUI. Args are the String property name of the component and a Boolean for
     * whether to show it. Does nothing unless exactly 2 arguments are passed.
     */
    public static final int UPDATEGUILAYOUT = 28;
    /**
     * Toggle the mouse between selecting text and panning the page. Not available in facing or page flow view. Does
     * nothing if arguments are passed.
     */
    public static final int MOUSEMODE = 29;
    /** Set the mouse to pan the page. Does nothing if arguments are passed. */
    public static final int PANMODE = 30;
    /** Set the mouse to select text. Does nothing if arguments are passed. */
    public static final int TEXTSELECT = 31;
    /**
     * Toggle whether the first page is shown on its own in facing views, and save the setting. Does nothing if
     * arguments are passed.
     */
    public static final int SEPARATECOVER = 32;
    /** Show a dialog to extract the highlighted text. Does nothing if arguments are passed. */
    public static final int EXTRACTTEXT = 33;
    /** Show a preview of the selected area as an image, which can be copied or saved. Arguments are ignored. */
    public static final int EXTRACTASIMAGE = 34;
    /** Rotate the display 90 degrees anticlockwise. Arguments are ignored. */
    public static final int ROTATELEFT = 35;
    /** Rotate the display 90 degrees clockwise. Arguments are ignored. */
    public static final int ROTATERIGHT = 36;
    /**
     * Open the current file in the operating system's default application. Optionally the arg is a String path of a
     * different file to open.
     */
    public static final int OPENINSYSTEMDEFAULT = 37;
    /** Show the dialog to digitally sign the open file. Does nothing if arguments are passed. */
    public static final int SIGN = 40;
    //0-49 handled in executeMenuBarCommands(final int ID, Object[] args)

    //50-249 handled in executeDisplayCommands(final int ID, Object[] args)
    /** Go to the first page. Does nothing if arguments are passed. */
    public static final int FIRSTPAGE = 50;
    /** Go back 10 pages, stopping at the first page. Does nothing if arguments are passed. */
    public static final int FBACKPAGE = 51;
    /** Go back 1 page. Optionally the arg is the number of pages to go back, as a String. */
    public static final int BACKPAGE = 52;
    /** Go forward 1 page. Optionally the arg is the number of pages to go forward, as a String. */
    public static final int FORWARDPAGE = 53;
    /** Go forward 10 pages, stopping at the last page. Does nothing if arguments are passed. */
    public static final int FFORWARDPAGE = 54;
    /** Go to the last page. Does nothing if arguments are passed. */
    public static final int LASTPAGE = 55;
    /**
     * Go to a page. With no arguments a dialog asks for the page number. Otherwise the arg is the page number as a
     * String.
     */
    public static final int GOTO = 56;

    /** Show one page at a time and set the mouse to select text. Does nothing if arguments are passed. */
    public static final int SINGLE = 57;
    /**
     * Show the pages in a continuous vertical column and set the mouse to pan. Does nothing if arguments are passed.
     */
    public static final int CONTINUOUS = 58;
    /**
     * Show the pages in a continuous column of facing pairs, fit to the page, and set the mouse to pan. Does nothing if
     * arguments are passed.
     */
    public static final int CONTINUOUS_FACING = 59;
    /**
     * Show the pages as facing pairs, fit to the page, and set the mouse to pan. Does nothing if arguments are passed.
     */
    public static final int FACING = 60;
    /** Show the pages in the page flow view, which needs JavaFX. Does nothing if arguments are passed. */
    public static final int PAGEFLOW = 61;

    /** Toggle full screen mode, if supported. Does nothing if arguments are passed. */
    public static final int FULLSCREEN = 62;
    /** Zoom in to the next preset scaling, up to 1000%. Does nothing if arguments are passed. */
    public static final int ZOOMIN = 63;
    /** Zoom out to the next preset scaling, down to 25%. Does nothing if arguments are passed. */
    public static final int ZOOMOUT = 64;

    /** Show a PDF portfolio's files as a detailed list. Arguments are ignored. */
    public static final int PORTFOLIO_DETAIL = 65;
    /** Show a PDF portfolio's files as tiles. Arguments are ignored. */
    public static final int PORTFOLIO_TILES = 66;
    //50-249 handled in executeDisplayCommands(final int ID, Object[] args)

    //250-299 handled in executeComboCommands(final int ID, Object[] args)
    //combo boxes start at 250
    /**
     * Rotate the display. With no arguments the rotation selected in the toolbar is applied. Otherwise, the arg is the
     * rotation in degrees as a String: 0, 90, 180 or 270.
     */
    public static final int ROTATION = 251;
    /**
     * Set the scaling. With no arguments the scaling selected in the toolbar is applied. Otherwise, the arg is the
     * scaling as a percentage number or one of the toolbar's text options, such as "Fit Width".
     */
    public static final int SCALING = 252;
    //250-299 handled in executeComboCommands(final int ID, Object[] args)

    //300-499 not handled here
    /**
     * Identifies the whole Swing menu bar, for showing, hiding, enabling or disabling it. Running it as a command does
     * nothing.
     */
    public static final int CURRENTMENU = 300;
    /**
     * Identifies the Content menu in the Swing menu bar, for showing, hiding, enabling or disabling it. Running it as a
     * command does nothing.
     */
    public static final int CONTENTMENU = 304;
    /** Not used by the Viewer. Running it as a command does nothing. */
    public static final int PDFMENU = 306;
    /**
     * Identifies the Export menu in the Swing menu bar, for showing, hiding, enabling or disabling it. Running it as a
     * command does nothing.
     */
    public static final int EXPORTMENU = 307;
    /** Not used by the Viewer. Running it as a command does nothing. */
    public static final int WINDOWMENU = 308;
    /**
     * Identifies the Page Layout menu in the Swing menu bar, for showing, hiding, enabling or disabling it. Running it
     * as a command does nothing.
     */
    public static final int PAGELAYOUTMENU = 309;
    /**
     * Identifies the Edit menu in the Swing menu bar, for showing, hiding, enabling or disabling it. Running it as a
     * command does nothing.
     */
    public static final int EDITMENU = 310;
    /**
     * Identifies the Go To menu in the Swing menu bar, for showing, hiding, enabling or disabling it. Running it as a
     * command does nothing.
     */
    public static final int GOTOMENU = 311;
    /**
     * Identifies the View menu in the Swing menu bar, for showing, hiding, enabling or disabling it. Running it as a
     * command does nothing.
     */
    public static final int VIEWMENU = 312;
    /**
     * Identifies the Open menu in the Swing menu bar, for showing, hiding, enabling or disabling it. Running it as a
     * command does nothing.
     */
    public static final int OPENMENU = 316;
    /**
     * Identifies the File menu in the Swing menu bar, for showing, hiding, enabling or disabling it. Running it as a
     * command does nothing.
     */
    public static final int FILEMENU = 317;

    /** Not used by the Viewer. The Help menu is identified by {@link #HELP}. Running it as a command does nothing. */
    public static final int HELPFORUM = 318;

    /**
     * Identifies the Portfolio menu, which is only shown for PDF portfolios, in the Swing menu bar, for showing,
     * hiding, enabling or disabling it. Running it as a command does nothing.
     */
    public static final int PORTFOLIOMENU = 319;

    /**
     * Identifies the Tools menu in the Swing menu bar, for showing, hiding, enabling or disabling it. Running it as a
     * command does nothing.
     */
    public static final int TOOLSMENU = 320;
    //300-499 not handled here

    // external menu options start at 500 - add your own CONSTANT here
    // and refer to action using name at ALL times
    //500-599 (existing values) handled in executeExternalCommands(final int ID, Object[] args)
    /**
     * Show a dialog to save the document after annotations have been added. If no annotation has been added, no file is
     * written. Does nothing if arguments are passed.
     */
    public static final int SAVEFORM = 500;
    //500-599 (existing values) handled in executeExternalCommands(final int ID, Object[] args)

    //600-699 handled in executePageCommands(final int ID, Object[] args)
    /**
     * Clear the current text highlights, then highlight areas on a page. Args are an int[][] of {x, y, width, height}
     * rectangles in PDF coordinates, the Integer page, and an optional Boolean, default true, where true highlights the
     * rectangles and false highlights whole lines from the top left to the bottom right. With no arguments the
     * highlights are only cleared.
     */
    public static final int HIGHLIGHT = 600;
    /**
     * Scroll an area of a page into view. Args are an int[] {x, y, width, height} rectangle and an optional Integer
     * page, default the current page. Does nothing with no arguments.
     */
    public static final int SCROLL = 601;
    //600-699 handled in executePageCommands(final int ID, Object[] args)

    //700-899 handled in executeViewerFunctionalityCommands(final int ID, Object[] args)
    // commands for the forward and back tracking of views, ie when a page changes
    /**
     * Add a view to the history used by {@link #FORWARD} and {@link #BACK}. Args are the Integer page, the Rectangle
     * location and the Integer scaling type.
     */
    public static final int ADDVIEW = 700;
    /** Go forward to the next view in the history added by {@link #ADDVIEW}. Arguments are ignored. */
    public static final int FORWARD = 701;
    /** Go back to the previous view in the history added by {@link #ADDVIEW}. Arguments are ignored. */
    public static final int BACK = 702;
    /**
     * Return the number of pages in the open document as an Integer, or -1 if there is no decoder. Arguments are
     * ignored.
     */
    public static final int PAGECOUNT = 703;
    /** Return the current page number as an Integer. Arguments are ignored. */
    public static final int CURRENTPAGE = 704;

    /** Rebuild the bookmarks and return the outline (bookmarks) panel. Arguments are ignored. */
    public static final int GETOUTLINEPANEL = 705;
    /** Return the thumbnail panel. Arguments are ignored. */
    public static final int GETTHUMBNAILPANEL = 706;
    /** Return the page number text field from the navigation bar. Arguments are ignored. */
    public static final int GETPAGECOUNTER = 707;
    /**
     * Return the text grouping object for a page, decoding the page in the background if it is not the page being
     * displayed. The arg is the Integer page. Returns null with no arguments or if an error occurs.
     */
    public static final int PAGEGROUPING = 708;

    /** Set the page background colour and repaint. The arg is the colour as an Integer RGB value. */
    public static final int SETPAGECOLOR = 709;
    /** Set the colour shown for pages that have not been drawn yet. The arg is the colour as an Integer RGB value. */
    public static final int SETUNDRAWNPAGECOLOR = 710;
    /**
     * Set the colour all text is drawn in, without repainting. The arg is the colour as an Integer RGB value.
     * {@link #SETTEXTCOLOR} does the same and repaints.
     */
    public static final int REPLACETEXTCOLOR = 711;
    /** Set the colour all text is drawn in and repaint. The arg is the colour as an Integer RGB value. */
    public static final int SETTEXTCOLOR = 712;
    /**
     * Set whether shapes and line art are recoloured along with the text when a text colour is set, then repaint. The
     * arg is a Boolean.
     */
    public static final int CHANGELINEART = 713;
    /**
     * Set the background colour of the display area around the pages. The arg is the colour as an Integer RGB value.
     */
    public static final int SETDISPLAYBACKGROUND = 714;
    /**
     * Set the threshold that decides which text is recoloured when a text colour is set. The arg is the threshold as an
     * Integer.
     */
    public static final int SETREPLACEMENTCOLORTHRESHOLD = 715;
    /** Set whether lines thinner than 1 pixel are widened so they stay visible, then repaint. The arg is a Boolean. */
    public static final int SETENHANCEFRACTIONALLINES = 717;
    /** Set whether all shapes are drawn with a 1 pixel stroke after scaling, then repaint. The arg is a Boolean. */
    public static final int SETHIDELINEWEIGHTS = 718;
    /** Set whether interactive form fields are highlighted, then repaint. The arg is a Boolean. */
    public static final int SETHIGHLIGHTFORMFIELDS = 719;
    /** Remove the version number from the window title. Arguments are ignored. */
    public static final int HIDEVERSIONNUMBER = 720;
    /** Show the version number in the window title. Arguments are ignored. */
    public static final int SHOWVERSIONNUMBER = 721;
    //700-899 handled in executeViewerFunctionalityCommands(final int ID, Object[] args)

    //997-999 handled in executeDemoVersionCommands(final int ID, Object[] args)
    /** Open the JPedal documentation in the default browser. Does nothing if arguments are passed. */
    public static final int HELP = 998;
    /** Open the JPedal pricing page in the default browser. Does nothing if arguments are passed. */
    public static final int BUY = 999;
    //997-999 handled in executeDemoVersionCommands(final int ID, Object[] args)


    //1000-1099 handled in executeDebugCommands(final int ID, Object[] args)
    /**
     * Debug command that resets the Viewer's internal viewport scale and offsets. Does nothing if arguments are passed.
     */
    public static final int RESET = 1_002;
    /**
     * Debug command that turns on hardware acceleration for screen rendering and repaints. Does nothing if arguments
     * are passed.
     */
    public static final int ACCELERATIONON = 1_003;
    /**
     * Debug command that turns off hardware acceleration for screen rendering and repaints. Does nothing if arguments
     * are passed.
     */
    public static final int ACCELERATIONOFF = 1_004;
    /** Debug command that prints the names of all form fields to standard out. Does nothing if arguments are passed. */
    public static final int SHOWFORMNAMES = 1_006;
    /**
     * Debug command that makes the Viewer delete its properties file when its window is closed. Does nothing if
     * arguments are passed.
     */
    public static final int DELETEPROPERTIESONEXIT = 1_007;
    /** Debug command that toggles whether the mouse cursor is always shown. Does nothing if arguments are passed. */
    public static final int ALWAYSSHOWMOUSE = 1_008;
    /** Debug command that calls {@link System#gc()}. Does nothing if arguments are passed. */
    public static final int TRIGGERGC = 1_009;
    //1000-1099 handled in executeDebugCommands(final int ID, Object[] args)

    //1100-1199 handle in executeToolsCommands(final int ID, Object[] args)
    // manipulations and sanitizations
    /**
     * Show a dialog to insert blank pages of a chosen size, then save the document (asking whether to overwrite the
     * open file) and reopen it. Does nothing if arguments are passed.
     */
    public static final int ADDPAGE = 1_101;
    /**
     * Show a dialog to choose pages and an image, then let the user drag the area to place it in, then save the
     * document (asking whether to overwrite the open file) and reopen it. Does nothing if arguments are passed.
     */
    public static final int ADDIMAGE = 1_102;
    /**
     * Show a dialog to copy a page to another position, then save the document (asking whether to overwrite the open
     * file) and reopen it. Does nothing if arguments are passed.
     */
    public static final int COPYPAGE = 1_103;
    /**
     * Show a dialog to crop pages, then save the document (asking whether to overwrite the open file) and reopen it.
     * Does nothing if arguments are passed.
     */
    public static final int CROPPAGE = 1_104;
    /**
     * Show a dialog to embed a file in the document as an attachment, then save the document (asking whether to
     * overwrite the open file) and reopen it. Does nothing if arguments are passed.
     */
    public static final int EMBEDFILE = 1_105;
    /**
     * Show a dialog to choose pages to keep, removing all the others, then save the document (asking whether to
     * overwrite the open file) and reopen it. Does nothing if arguments are passed.
     */
    public static final int ISOLATEPAGE = 1_106;
    /**
     * Show a dialog to combine several pages onto each page in a grid of rows and columns, then save the document
     * (asking whether to overwrite the open file) and reopen it. Does nothing if arguments are passed.
     */
    public static final int NUP = 1_107;
    /**
     * Show a dialog to remove pages, then save the document (asking whether to overwrite the open file) and reopen it.
     * Does nothing if arguments are passed.
     */
    public static final int REMOVEPAGE = 1_108;
    /**
     * Show a dialog to rotate pages, then save the document (asking whether to overwrite the open file) and reopen it.
     * Does nothing if arguments are passed.
     */
    public static final int ROTATEPAGE = 1_109;
    /**
     * Show a dialog to scale pages, then save the document (asking whether to overwrite the open file) and reopen it.
     * Does nothing if arguments are passed.
     */
    public static final int SCALEPAGE = 1_110;
    /**
     * Show a dialog to edit the document information, which is written to both the Info dictionary and the XMP
     * metadata, then save the document (asking whether to overwrite the open file) and reopen it. Does nothing if
     * arguments are passed.
     */
    public static final int SETDOCUMENTINFO = 1_112;
    /**
     * Show a dialog to set the page, page layout and page mode the document opens with, then save the document (asking
     * whether to overwrite the open file) and reopen it. Does nothing if arguments are passed.
     */
    public static final int SETINITIALVIEW = 1_113;
    /**
     * Remove all bookmarks, then save the document (asking whether to overwrite the open file) and reopen it. Does
     * nothing if arguments are passed.
     */
    public static final int REMOVEBOOKMARKS = 1_114;
    /**
     * Remove all embedded files, then save the document (asking whether to overwrite the open file) and reopen it. Does
     * nothing if arguments are passed.
     */
    public static final int REMOVEEMBEDDEDFILES = 1_115;
    /**
     * Remove the initial view settings, then save the document (asking whether to overwrite the open file) and reopen
     * it. Does nothing if arguments are passed.
     */
    public static final int REMOVEINITIALVIEW = 1_116;
    /**
     * Remove all JavaScript, then save the document (asking whether to overwrite the open file) and reopen it. Does
     * nothing if arguments are passed.
     */
    public static final int REMOVEJAVASCRIPT = 1_117;
    /**
     * Remove all links, then save the document (asking whether to overwrite the open file) and reopen it. Does nothing
     * if arguments are passed.
     */
    public static final int REMOVELINKS = 1_118;
    /**
     * Remove the document metadata, then save the document (asking whether to overwrite the open file) and reopen it.
     * Does nothing if arguments are passed.
     */
    public static final int REMOVEMETADATA = 1_119;
    /**
     * Show a dialog to move a page to another position, then save the document (asking whether to overwrite the open
     * file) and reopen it. Does nothing if arguments are passed.
     */
    public static final int MOVEPAGE = 1_120;
    /**
     * Show a dialog to choose pages to remove annotations from, then save the document (asking whether to overwrite the
     * open file) and reopen it. Does nothing if arguments are passed.
     */
    public static final int REMOVEANNOTATIONS = 1_121;
    /**
     * Reverse the page order, then save the document (asking whether to overwrite the open file) and reopen it. Does
     * nothing if arguments are passed.
     */
    public static final int REVERSEPAGES = 1_122;
    /**
     * Show a dialog to choose pages, then let the user drag the area of text to redact, then save the document (asking
     * whether to overwrite the open file) and reopen it. Does nothing if arguments are passed.
     */
    public static final int REDACT = 1_123;
    /**
     * Downsample all images using the default settings, then save the document (asking whether to overwrite the open
     * file) and reopen it. Does nothing if arguments are passed.
     */
    public static final int DOWNSAMPLEIMAGES = 1_124;
    /**
     * Flatten all layers, removing hidden layers and making visible layers permanent, then save the document (asking
     * whether to overwrite the open file) and reopen it. Does nothing if arguments are passed.
     */
    public static final int FLATTENLAYERS = 1_125;
    /**
     * Optimise image colour palettes to fit an indexed colour space, losslessly reducing image size, then save the
     * document (asking whether to overwrite the open file) and reopen it. Does nothing if arguments are passed.
     */
    public static final int OPTIMIZECOLORPALETTE = 1_126;
    /**
     * Remove blank pages, then save the document (asking whether to overwrite the open file) and reopen it. Does
     * nothing if arguments are passed.
     */
    public static final int REMOVEBLANKPAGES = 1_127;
    /**
     * Remove all digital signatures, then save the document (asking whether to overwrite the open file) and reopen it.
     * Does nothing if arguments are passed.
     */
    public static final int REMOVEDIGITALSIGNATURES = 1_128;
    //1100-1199 handle in executeToolsCommands(final int ID, Object[] args)

    //status values returned by command
    /**
     * Returned by {@link #NEXTRESULT} and {@link #PREVIOUSRESULT} when the first search result in the document is now
     * shown.
     */
    public static final Integer FIRST_DOCUMENT_SEARCH_RESULT_NOW_SHOWN = 1;
    /**
     * Returned by {@link #NEXTRESULT} and {@link #PREVIOUSRESULT} when the search wrapped round past the end or start
     * of the document.
     */
    public static final Integer SEARCH_RETURNED_TO_START = 2;
    /** Returned by {@link #NEXTRESULT} and {@link #PREVIOUSRESULT} when no page has any search results. */
    public static final Integer SEARCH_NOT_FOUND = 3;

    protected final Values commonValues;
    protected final SwingGUI currentGUI;
    protected final PdfDecoderInt decode_pdf;

    protected final SwingThumbnailPanel thumbnails;

    protected final PropertiesFile properties;

    protected final SwingSearchWindow searchFrame;

    /**
     * tracks mouse operation mode currently selected
     */
    protected final MouseMode mouseMode = new MouseMode();

    /**
     * Create the command handler for a Viewer. The Viewer creates this itself, so most code should get it from the
     * Viewer rather than constructing one.
     *
     * @param commonValues the Viewer's shared state, such as the open file and current page
     * @param currentGUI the Swing GUI the commands act on
     * @param decode_pdf the decoder displaying the PDF
     * @param thumbnails the thumbnail panel
     * @param properties the Viewer's preferences
     * @param searchFrame the search window used by the find and search result commands
     */
    public Commands(final Values commonValues, final SwingGUI currentGUI, final PdfDecoderInt decode_pdf, final SwingThumbnailPanel thumbnails,
                    final PropertiesFile properties, final SwingSearchWindow searchFrame) {
        this.commonValues = commonValues;
        this.currentGUI = currentGUI;
        this.decode_pdf = decode_pdf;

        this.thumbnails = thumbnails;
        this.properties = properties;

        this.searchFrame = searchFrame;


        //Define printer here as it is only required for the Swing Viewer
        currentPrinter = new Printer();
    }

    private Object commandExecutor(final int ID, Object[] args) {

        //teat null and Object[]{null} as both null
        if (args != null && ((args.length == 1 && args[0] == null) || args.length == 0)) {
            args = null;
        }

        final Map<Integer, Object> jpedalActionHandlers = (Map<Integer, Object>) decode_pdf.getExternalHandler(Options.JPedalActionHandlers);

        if (jpedalActionHandlers != null) {
            final JPedalActionHandler jpedalAction = (JPedalActionHandler) jpedalActionHandlers.get(ID);
            if (jpedalAction != null) {
                jpedalAction.actionPerformed(currentGUI, this);
                return null;
            }
        }

        Object status = null;

        if (ID < FIRSTPAGE) {
            status = executeMenuBarCommands(ID, args);
        } else if (ID < ROTATION) {
            executeDisplayCommands(ID, args);
        } else if (ID < CURRENTMENU) {
            executeComboCommands(ID, args);
        } else if (ID < HIGHLIGHT) {
            executeExternalCommands(ID, args);
        } else if (ID < ADDVIEW) {
            executePageCommands(ID, args);
        } else if (ID < 997) {
            status = executeViewerFunctionalityCommands(ID, args);
        } else if (ID < 1_000) { //Use hard coded value for a debug value remvoed during build
            executeDemoVersionCommands(ID, args);
        } else if (ID < 1_100) {
            executeDebugCommands(ID, args);
        } else {
            executeToolsCommands(ID, args, commonValues, searchFrame,
                    currentGUI, decode_pdf, properties, thumbnails);
        }
        return status;
    }

    /**
     * Run a Viewer command. A null, empty or single-null {@code args} array is treated as no arguments, which for most
     * commands means they use the current Viewer state or show a dialog. If a {@link JPedalActionHandler} has been
     * registered for the command with {@link Options#JPedalActionHandlers}, that handler is run instead and null is
     * returned.
     *
     * @param command the command to run
     * @param args the arguments for the command, or null
     *
     * @return the command's result for commands that return one (such as {@link #PAGECOUNT} or the search result
     *         commands), otherwise null
     */
    public Object executeCommand(final ViewerCommands command, final Object[] args) {
        return commandExecutor(command.commandID, args);
    }

    /**
     * Returns a value from the Viewer.
     *
     * @param value the value to get
     *
     * @return the page count or current page as an Integer, the open file name as a String, the scaling as a float,
     *         the page layout or the rotation as an int, or null for an unknown value
     */
    public Object getValue(final ViewerValues value) {
        return switch (value) {
            case PAGECOUNT -> commandExecutor(PAGECOUNT, null);
            case PDFNAME -> commonValues.getSelectedFile();
            case CURRENTPAGE -> commandExecutor(CURRENTPAGE, null);
            case SCALE -> decode_pdf.getScaling();
            case PAGELAYOUT -> decode_pdf.getDisplayView();
            case ROTATION -> decode_pdf.getDisplayRotation();
        };
    }

    /**
     * Open a file dropped onto the Viewer. Any unsaved form changes are handled first, then this waits until no other
     * dropped file is opening and the Viewer is not processing. A message is shown if a local file does not exist.
     *
     * @param file the path or http/https URL of the file to open
     */
    public void handleTransferedFile(final String file) {


        //Before anything handle any unsaved forms
        SaveFile.handleUnsaveForms(currentGUI, commonValues);

        while (Values.getOpeningTransferedFile() || Values.isProcessing()) {
            try {
                Thread.sleep(250);
            } catch (final InterruptedException e) {
                LogWriter.error(e, "Exception thrown, waiting for transferred file to open interrupted");
            }
        }
        Values.setOpeningTransferedFile(true);


        try {
            final boolean isURL = file.startsWith("http:") || file.startsWith("https:");

            if (!isURL && Files.notExists(Paths.get(file))) {
                currentGUI.showMessageDialog(Messages.getMessage("PdfViewerFile.text") + file + Messages.getMessage("PdfViewerNotExist"));
                return;
            }

            commonValues.setFileIsURL(isURL);

            if (!isURL) {
                commonValues.setFileSize(new File(file).length() >> 10);
            }
            commonValues.setSelectedFile(file);
            currentGUI.setViewerTitle();

            if (!Values.isProcessing()) {
                OpenFile.executeOpenFile(new Object[] {commonValues.getSelectedFile()}, commonValues, searchFrame, currentGUI, decode_pdf, properties, thumbnails);
            }
        } catch (final Exception e) {
            LogWriter.writeLog("Exception " + e + " opening transferred file");
        } finally {
            Values.setOpeningTransferedFile(false);
        }
    }

    /**
     * Rebuild the recent documents menu from the list stored in the Viewer's preferences.
     */
    public void recentDocumentsOption() {

        currentGUI.setRecentDocument();

        final String[] recentDocs = properties.getRecentDocuments();
        if (recentDocs == null) {
            return;
        }

        for (int i = 0; i < PropertiesFile.getNoRecentDocumentsToDisplay(); i++) {

            if (recentDocs[i] == null) {
                recentDocs[i] = "";
            }

            try {
                final String fileNameToAdd = recentDocs[i];
                currentGUI.getRecentDocument().createMenuItems(fileNameToAdd, i, currentGUI, commonValues);
            } catch (final Exception ee) {
                LogWriter.error(ee, "Error generating recent documents list for Viewer");
            }
        }
    }

    /**
     * Returns the searchList of the last search preformed. If currently searching this method will return the results
     * for last completed search
     *
     * @return SearchList of all results, all data but the actual highlgiht areas
     */
    public SearchList getSearchList() {
        return searchFrame.getResults();
    }

    /**
     * {@return the mouse mode, which records whether the mouse is selecting text or panning the page}
     */
    public MouseMode getMouseMode() {
        return mouseMode;
    }

    /**
     * examine first few bytes to see if linearized and return true linearized file
     *
     * @param pdfUrl is of type String
     *
     * @return the isLinear
     */
    public static boolean isPDFLinearized(final String pdfUrl) {

        if (pdfUrl.startsWith("jar")) {
            return false;
        }

        //read first few bytes
        try (InputStream is = new URI(pdfUrl).toURL().openStream()) {

            // Download buffer
            final byte[] buffer = new byte[128];
            is.read(buffer);
            is.close();

            //scan for Linearized in text
            final int lim = buffer.length - 6;
            for (int i = 0; i < lim; i++) {

                if (buffer[i] == '/' && buffer[i + 1] == 'L' && buffer[i + 2] == 'i' && buffer[i + 3] == 'n' && buffer[i + 4] == 'e' && buffer[i + 5] == 'a' && buffer[i + 6] == 'r') {
                    return true;
                }
            }

        } catch (final IOException | URISyntaxException e) {
            LogWriter.writeLog("[PDF] Exception " + e + " scanning URL " + pdfUrl);
        }

        return false;
    }

    @SuppressWarnings({"OverlyLongMethod", "java:S138"})
    private Object executeMenuBarCommands(final int ID, final Object[] args) {
        Object status = null;

        switch (ID) {
            case ABOUT -> Info.execute(args, currentGUI); //Gets the info box
            case BITMAP -> BitMap.execute(args, currentGUI, commonValues, decode_pdf);
            case IMAGES -> ExtractImages.execute(args, currentGUI, commonValues, decode_pdf);
            case TEXT -> Text.execute(args, currentGUI, commonValues, decode_pdf);
            case SAVE -> SaveFile.execute(args, currentGUI, commonValues);
            case PRINT -> Print.execute(args, currentGUI, commonValues, properties, currentPrinter, decode_pdf);
            case EXIT -> Exit.execute(args, thumbnails, currentGUI, commonValues, decode_pdf, properties);
            case AUTOSCROLL -> AutoScroll.execute(args, currentGUI);
            case DOCINFO -> DocInfo.execute(args, currentGUI, commonValues, decode_pdf);
            case OPENFILE -> OpenFile.executeOpenFile(args, commonValues, searchFrame, currentGUI,
                    decode_pdf, properties, thumbnails);
            case BOOKMARK -> Bookmark.execute(args, currentGUI);
            case FIND -> Find.execute(args, commonValues, currentGUI, decode_pdf, searchFrame);
            case SNAPSHOT -> {
                status = Snapshot.execute(args, currentGUI, decode_pdf, extractingAsImage);

                //we need to sync value
                extractingAsImage = (Boolean) status;
            }
            case OPENURL -> OpenFile.executeOpenURL(args, commonValues, searchFrame, currentGUI,
                    decode_pdf, properties, thumbnails);
            case VISITWEBSITE -> VisitWebsite.execute(args, currentGUI);
            case PREVIOUSDOCUMENT -> NavigateDocuments.executePrevDoc(args, currentGUI);
            case NEXTDOCUMENT -> NavigateDocuments.executeNextDoc(args, currentGUI);
            case PREVIOUSRESULT ->
                    status = PreviousResult.execute(args, commonValues, currentGUI, decode_pdf, searchFrame);
            case NEXTRESULT -> status = NextResults.execute(args, commonValues, searchFrame, currentGUI, decode_pdf);
            case TIP -> Tip.execute(args, currentGUI, properties);
            case PREFERENCES -> Preferences.execute(args, currentGUI);
            case COPY -> Copy.execute(currentGUI, decode_pdf, commonValues);
            case SELECTALL -> SelectAll.execute(currentGUI, decode_pdf, commonValues);
            case DESELECTALL -> DeSelectAll.execute(currentGUI, decode_pdf);
            case UPDATEGUILAYOUT -> UpdateGUILayout.execute(args, currentGUI);
            case MOUSEMODE -> MouseModeCommand.execute(args, currentGUI, mouseMode, decode_pdf);
            case PANMODE -> PanMode.execute(args, currentGUI, mouseMode, decode_pdf);
            case TEXTSELECT -> TextSelect.execute(args, currentGUI, mouseMode);
            case SEPARATECOVER -> SeparateCover.execute(args, decode_pdf, properties, currentGUI, commonValues);
            case EXTRACTTEXT -> ExtractText.execute(args, currentGUI, decode_pdf, commonValues);
            case EXTRACTASIMAGE -> ExtractSelectionAsImage.execute(commonValues, currentGUI, decode_pdf);
            case ROTATELEFT -> RotationLeft.execute(currentGUI, commonValues);
            case ROTATERIGHT -> RotationRight.execute(currentGUI, commonValues);
            case OPENINSYSTEMDEFAULT -> OpenInSystemDefault.execute(args, currentGUI, commonValues);
            case SIGN -> Sign.execute(args, currentGUI, commonValues);
        }
        return status;
    }

    private void executeDisplayCommands(final int ID, final Object[] args) {

        switch (ID) {
            case FIRSTPAGE -> PageNavigator.goFirstPage(args, commonValues, decode_pdf, currentGUI);
            case FBACKPAGE -> PageNavigator.goFBackPage(args, commonValues, decode_pdf, currentGUI);
            case BACKPAGE -> PageNavigator.goBackPage(args, commonValues, decode_pdf, currentGUI);
            case FORWARDPAGE -> PageNavigator.goForwardPage(args, commonValues, decode_pdf, currentGUI);
            case FFORWARDPAGE -> PageNavigator.goFForwardPage(args, commonValues, decode_pdf, currentGUI);
            case LASTPAGE -> PageNavigator.goLastPage(args, commonValues, decode_pdf, currentGUI);
            case GOTO -> PageNavigator.goPage(args, currentGUI, commonValues, decode_pdf);
            case SINGLE -> {
                Single.execute(args, decode_pdf, currentGUI);
                TextSelect.execute(args, currentGUI, mouseMode); //Enable text selection
            }
            case CONTINUOUS -> {
                Continuous.execute(decode_pdf, currentGUI, args);
                PanMode.execute(args, currentGUI, mouseMode, decode_pdf); //Enables Panning of document
            }
            case CONTINUOUS_FACING -> {
                ContinuousFacing.execute(args, decode_pdf, currentGUI, commonValues);
                PanMode.execute(args, currentGUI, mouseMode, decode_pdf); //Enables Panning of document
            }
            case FACING -> {
                Facing.execute(args, decode_pdf, currentGUI, commonValues);
                PanMode.execute(args, currentGUI, mouseMode, decode_pdf); //Enables Panning of document
            }
            case PAGEFLOW -> PageFlow.execute(args, currentGUI, commonValues, decode_pdf, properties, searchFrame);
            case FULLSCREEN -> FullScreen.execute(args, currentGUI);
            case ZOOMIN -> ZoomIn.execute(args, currentGUI, decode_pdf);
            case ZOOMOUT -> ZoomOut.execute(args, currentGUI, decode_pdf);
            case PORTFOLIO_DETAIL -> currentGUI.setDisplayView(Display.PORTFOLIO_DETAIL, Display.DISPLAY_CENTERED);
            case PORTFOLIO_TILES -> currentGUI.setDisplayView(Display.PORTFOLIO_TILE, Display.DISPLAY_CENTERED);
        }
    }

    private void executeDemoVersionCommands(final int ID, final Object[] args) {

        switch (ID) {
            case HELP -> Help.execute(args); //gets the help box
            case BUY -> Buy.execute(args, currentGUI); //takes user to pricing page
        }
    }

    private void executeComboCommands(final int ID, final Object[] args) {

        switch (ID) {
            case SCALING -> Scaling.execute(args, commonValues, decode_pdf, currentGUI, viewStack);
            case ROTATION -> Rotation.execute(args, currentGUI, commonValues);
        }
    }

    private void executeExternalCommands(final int ID, final Object[] args) {

        if (ID == SAVEFORM) {
            SaveForm.execute(args, currentGUI, decode_pdf, commonValues);
        }
    }

    private void executePageCommands(final int ID, final Object[] args) {
        switch (ID) {
            case HIGHLIGHT -> Highlight.execute(args, decode_pdf);
            case SCROLL -> Scroll.execute(args, currentGUI, commonValues, decode_pdf);
        }
    }

    @SuppressWarnings("java:S138")
    private Object executeViewerFunctionalityCommands(final int ID, final Object[] args) {
        Object status = null;
        switch (ID) {
            case ADDVIEW -> viewStack.add((Integer) args[0], (Rectangle) args[1], (Integer) args[2]);
            case FORWARD -> {
                //go forward to next viewed location
                final Viewable next = viewStack.forward();
                if (next != null) {
                    decode_pdf.getFormRenderer().getActionHandler().changeTo(null, next.getPage(),
                            next.getLocation(), next.getType(), false);
                }
            }
            case BACK -> {
                //go back to last viewed location
                final Viewable previous = viewStack.back();
                if (previous != null) {
                    decode_pdf.getFormRenderer().getActionHandler().changeTo(null, previous.getPage(),
                            previous.getLocation(), previous.getType(), false);
                }
            }
            case PAGECOUNT -> status = PageCount.execute(decode_pdf);
            case CURRENTPAGE -> status = currentGUI.getValues().getCurrentPage();
            case GETOUTLINEPANEL -> {
                //ensure setup
                currentGUI.setBookmarks(true);
                status = currentGUI.getOutlinePanel();
            }
            case GETTHUMBNAILPANEL -> {
                //ensure setup
                currentGUI.setBookmarks(true);
                status = currentGUI.getThumbnailPanel();
            }
            case GETPAGECOUNTER -> status = currentGUI.getPageCounter(SwingGUI.PageCounter.PAGECOUNTER2);
            case PAGEGROUPING -> status = PageGrouping.execute(args, decode_pdf); //Group Pages
            case SETPAGECOLOR -> SetPageColor.execute(args, decode_pdf);
            case SETUNDRAWNPAGECOLOR -> SetUndrawnPageColor.execute(args, decode_pdf);
            case REPLACETEXTCOLOR -> ReplaceTextColor.execute(args, decode_pdf);
            case SETTEXTCOLOR -> SetTextColor.execute(args, decode_pdf);
            case CHANGELINEART -> ChangeLineArt.execute(args, decode_pdf);
            case SETDISPLAYBACKGROUND -> SetDisplayBackground.execute(args, decode_pdf);
            case SETREPLACEMENTCOLORTHRESHOLD -> SetReplacementThreshold.execute(args, decode_pdf);
            case SETENHANCEFRACTIONALLINES -> //Used for JavaFX Netbeans PDF Viewer Plugin.
                    SetEnhanceFractionalLines.execute(args, decode_pdf);
            case SETHIDELINEWEIGHTS -> SetHideLineWeights.execute(args, decode_pdf);
            case SETHIGHLIGHTFORMFIELDS -> SetHighlightFormFields.execute(args, decode_pdf);
            case HIDEVERSIONNUMBER -> currentGUI.hideVersionNumber();
            case SHOWVERSIONNUMBER -> currentGUI.showVersionNumber();
        }

        return status;
    }

    private void executeDebugCommands(final int ID, final Object[] args) {

        switch (ID) {
            case RESET -> Reset.execute(args, commonValues);
            case ACCELERATIONON -> AccelerationOn.execute(args, decode_pdf);
            case ACCELERATIONOFF -> AccelerationOff.execute(args, decode_pdf);
            case SHOWFORMNAMES -> ShowFormNames.execute(args, decode_pdf);
            case DELETEPROPERTIESONEXIT -> DeletePropertiesOnExit.execute(args);
            case ALWAYSSHOWMOUSE -> AlwaysShowMouse.execute(args);
            case TRIGGERGC -> TriggerGC.execute(args);
        }
    }

    /**
     * Handle commands for the {@link org.jpedal.manipulator.PdfManipulator}
     */
    private static void executeToolsCommands(final int ID, final Object[] args, final Values commonValues,
            final SwingSearchWindow searchFrame, final SwingGUI currentGUI, final PdfDecoderInt decode_pdf,
            final PropertiesFile properties, final SwingThumbnailPanel thumbnails) {

        Manipulate.execute(ID, args, commonValues, searchFrame,
                currentGUI, decode_pdf, properties, thumbnails);
    }

}