/*
 * Copyright (c) 1997-2024 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.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.MouseModeCommand;
import org.jpedal.examples.viewer.commands.NavigateDocuments;
import org.jpedal.examples.viewer.commands.NextResults;
import org.jpedal.examples.viewer.commands.Objects;
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.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.UpdateGUILayout;
import org.jpedal.examples.viewer.commands.ViewStack;
import org.jpedal.examples.viewer.commands.VisitWebsite;
import org.jpedal.examples.viewer.commands.Xref;
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.popups.SaveImage;
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.Exporter;
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 javax.swing.JOptionPane;
import java.awt.Rectangle;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
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://support.idrsolutions.com/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
     */

    /*
     * Important! You must also update ViewerCommands.java
     */
    protected final ViewStack viewStack = new ViewStack();

    public boolean extractingAsImage;

    private final Printer currentPrinter;

         //0-50 handled in executeMenuBarCommands(final int ID, Object[] args)
    public static final int ABOUT = 1;
    public static final int BITMAP = 2;
    public static final int IMAGES = 3;
    public static final int TEXT = 4;
    public static final int SAVE = 5;
    public static final int PRINT = 6;
    public static final int EXIT = 7;
    public static final int AUTOSCROLL = 8;
    public static final int DOCINFO = 9;
    public static final int OPENFILE = 10;
    public static final int BOOKMARK = 11;
    public static final int FIND = 12;
    public static final int SNAPSHOT = 13;
    public static final int OPENURL = 14;
    public static final int VISITWEBSITE = 15;
    public static final int PREVIOUSDOCUMENT = 16;
    public static final int NEXTDOCUMENT = 17;
    public static final int PREVIOUSRESULT = 18;
    public static final int NEXTRESULT = 19;
    public static final int TIP = 20;
    public static final int PREFERENCES = 24;
    public static final int COPY = 25;
    public static final int SELECTALL = 26;
    public static final int DESELECTALL = 27;
    public static final int UPDATEGUILAYOUT = 28;
    public static final int MOUSEMODE = 29;
    public static final int PANMODE = 30;
    public static final int TEXTSELECT = 31;
    public static final int SEPARATECOVER = 32;
    public static final int EXTRACTTEXT = 33;
    public static final int EXTRACTASIMAGE = 34;
    public static final int ROTATELEFT = 35;
    public static final int ROTATERIGHT = 36;
    public static final int OPENINSYSTEMDEFAULT = 37;
    public static final int XREF = 38;
    public static final int OBJECTS = 39;
    //0-49 handled in executeMenuBarCommands(final int ID, Object[] args)

    //50-249 handled in executeDisplayCommands(final int ID, Object[] args)
    public static final int FIRSTPAGE = 50;
    public static final int FBACKPAGE = 51;
    public static final int BACKPAGE = 52;
    public static final int FORWARDPAGE = 53;
    public static final int FFORWARDPAGE = 54;
    public static final int LASTPAGE = 55;
    public static final int GOTO = 56;

    public static final int SINGLE = 57;
    public static final int CONTINUOUS = 58;
    public static final int CONTINUOUS_FACING = 59;
    public static final int FACING = 60;
    public static final int PAGEFLOW = 61;

    public static final int FULLSCREEN = 62;
    public static final int ZOOMIN = 63;
    public static final int ZOOMOUT = 64;

    public static final int PORTFOLIO_DETAIL = 65;
    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
    public static final int ROTATION = 251;
    public static final int SCALING = 252;
    //250-299 handled in executeComboCommands(final int ID, Object[] args)

    //300-499 not handled here
    public static final int CURRENTMENU = 300;
    public static final int CONTENTMENU = 304;
    public static final int PDFMENU = 306;
    public static final int EXPORTMENU = 307;
    public static final int WINDOWMENU = 308;
    public static final int PAGELAYOUTMENU = 309;
    public static final int EDITMENU = 310;
    public static final int GOTOMENU = 311;
    public static final int VIEWMENU = 312;
    public static final int OPENMENU = 316;
    public static final int FILEMENU = 317;

    public static final int HELPFORUM = 318;

    public static final int PORTFOLIOMENU = 319;
    //300-499 not handled here

    
    // external/itext 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)
    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)
    public static final int HIGHLIGHT = 600;
    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
    public static final int ADDVIEW = 700, FORWARD = 701, BACK = 702, PAGECOUNT = 703, CURRENTPAGE = 704;

    public static final int GETOUTLINEPANEL = 705;
    public static final int GETTHUMBNAILPANEL = 706;
    public static final int GETPAGECOUNTER = 707;
    public static final int PAGEGROUPING = 708;

    public static final int SETPAGECOLOR = 709;
    public static final int SETUNDRAWNPAGECOLOR = 710;
    public static final int REPLACETEXTCOLOR = 711;
    public static final int SETTEXTCOLOR = 712;
    public static final int CHANGELINEART = 713;
    public static final int SETDISPLAYBACKGROUND = 714;
    public static final int SETREPLACEMENTCOLORTHRESHOLD = 715;
    public static final int SETENHANCEFRACTIONALLINES = 717;
    public static final int SETHIDELINEWEIGHTS = 718;
    public static final int SETHIGHLIGHTFORMFIELDS = 719;
    public static final int HIDEVERSIONNUMBER = 720;
    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)
    public static final int HELP = 998;
    public static final int BUY = 999;
    //997-999 handled in executeDemoVersionCommands(final int ID, Object[] args)


    //>=1000 handled in executeDebugCommands(final int ID, Object[] args)
    public static final int RESET = 1_002;
    public static final int ACCELERATIONON = 1_003;
    public static final int ACCELERATIONOFF = 1_004;
    public static final int SHOWFORMNAMES = 1_006;
    public static final int DELETEPROPERTIESONEXIT = 1_007;
    public static final int ALWAYSSHOWMOUSE = 1_008;
    //>=1000 handled in executeDebugCommands(final int ID, Object[] args)

    //status values returned by command
    public static final Integer FIRST_DOCUMENT_SEARCH_RESULT_NOW_SHOWN = 1;
    public static final Integer SEARCH_RETURNED_TO_START = 2;
    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();

    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();
    }

    

    /**
     * main routine which executes code for current command
     <p>
     * Values can also be passed in so it can be called from your own code
     <p>
     * some commands return a status Object otherwise null
     *
     @deprecated use {@link #executeCommand(ViewerCommands, Object[])} instead.
     *
     @param ID   is of type Int
     @param args Program arguments passed into the Viewer.
     @return the status object
     */
    @Deprecated
    public Object executeCommand(final int ID, final Object[] args) {
        return commandExecutor(ID, args);
    }

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

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

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

        if (jpedalActionHandlers != null) {
            final JPedalActionHandler jpedalAction = (JPedalActionHandlerjpedalActionHandlers.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 {
            executeDebugCommands(ID, args);
        }
        return status;
    }

    public Object executeCommand(final ViewerCommands command, final Object[] args) {
        return commandExecutor(command.commandID, args);
    }

    public Object getValue(final ViewerValues value) {
        switch (value) {
            case PAGECOUNT:
                return commandExecutor(PAGECOUNT, null);
            case PDFNAME:
                return commonValues.getSelectedFile();
            case CURRENTPAGE:
                return commandExecutor(CURRENTPAGE, null);
            case SCALE:
                return decode_pdf.getScaling();
            case PAGELAYOUT:
                return decode_pdf.getDisplayView();
            case ROTATION:
                return decode_pdf.getDisplayRotation();
            default:
                return null;
        }
    }

    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.writeLog(e);
            }
        }
        Values.setOpeningTransferedFile(true);

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

            if (!isURL) {
                commonValues.setFileIsURL(false);
                commonValues.setFileSize(new File(file).length() >> 10);
            else {
                commonValues.setFileIsURL(true);
            }

            commonValues.setSelectedFile(file);

            currentGUI.setViewerTitle();
        catch (final Exception e) {
            LogWriter.writeLog("Exception " + e + " getting paths");
        }

        // check file exists
        final Path testFile;
        if (isURL) {
            testFile = Paths.get(URI.create(commonValues.getSelectedFile()));
        else {
            testFile = Paths.get(commonValues.getSelectedFile());
        }

        if (!isURL && Files.notExists(testFile)) {
            currentGUI.showMessageDialog(Messages.getMessage("PdfViewerFile.text"+ commonValues.getSelectedFile() + Messages.getMessage("PdfViewerNotExist"));
        else if (commonValues.getSelectedFile() != null && !Values.isProcessing()) {
            openTransferedFile();
            if (commonValues.isPDF()) {
                Values.setOpeningTransferedFile(false);
            }
        }
    }

    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.writeLog(ee);
            }
        }
    }

    /**
     * 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();
    }

    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;
        }

        boolean isLinear = false;
        //read first few bytes
        try (InputStream is = new URL(pdfUrl).openStream()) {

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

            //test if linearized

            //scan for Linearized in text
            final int len = buffer.length;
            for (int i = 0; i < len; 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') {
                    isLinear = true;
                    i = len;
                }
            }

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

        return isLinear;
    }

    protected void openTransferedFile() {
        decode_pdf.flushObjectValues(true);

        OpenFile.openFile(commonValues.getSelectedFile(), commonValues, searchFrame, currentGUI,
                decode_pdf, properties, thumbnails);

    }


    @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
                break;
            case BITMAP:
                BitMap.execute(args, currentGUI, commonValues, decode_pdf);
                break;
            case IMAGES:
                saveImage(args, currentGUI, commonValues, decode_pdf);
                break;
            case TEXT:
                Text.execute(args, currentGUI, commonValues, decode_pdf);
                break;
            case SAVE:
                SaveFile.execute(args, currentGUI, commonValues);
                break;
            case PRINT:
                Print.execute(args, currentGUI, commonValues, properties, currentPrinter, decode_pdf);
                break;
            case EXIT:
                Exit.execute(args, thumbnails, currentGUI, commonValues, decode_pdf, properties);
                break;
            case AUTOSCROLL:
                AutoScroll.execute(args, currentGUI);
                break;
            case DOCINFO:
                DocInfo.execute(args, currentGUI, commonValues, decode_pdf);
                break;
            case OPENFILE:
                OpenFile.executeOpenFile(args, commonValues, searchFrame, currentGUI,
                        decode_pdf, properties, thumbnails);
                break;
            case BOOKMARK:
                Bookmark.execute(args, currentGUI);
                break;
            case FIND:
                Find.execute(args, commonValues, currentGUI, decode_pdf, searchFrame);
                break;

            case SNAPSHOT:
                status = Snapshot.execute(args, currentGUI, decode_pdf, extractingAsImage);

                //we need to sync value
                extractingAsImage = (Booleanstatus;
                break;

            case OPENURL:
                OpenFile.executeOpenURL(args, commonValues, searchFrame, currentGUI,
                        decode_pdf, properties, thumbnails);
                break;
            case VISITWEBSITE:
                VisitWebsite.execute(args, currentGUI);
                break;
            case PREVIOUSDOCUMENT:
                NavigateDocuments.executePrevDoc(args, currentGUI);
                break;
            case NEXTDOCUMENT:
                NavigateDocuments.executeNextDoc(args, currentGUI);
                break;
            case PREVIOUSRESULT:
                status = PreviousResult.execute(args, commonValues, currentGUI, decode_pdf, searchFrame);
                break;
            case NEXTRESULT:
                status = NextResults.execute(args, commonValues, searchFrame, currentGUI, decode_pdf);
                break;
            case TIP:
                Tip.execute(args, currentGUI, properties);
                break;
            case PREFERENCES:
                Preferences.execute(args, currentGUI);
                break;
            case COPY:
                Copy.execute(currentGUI, decode_pdf, commonValues);
                break;
            case SELECTALL:
                SelectAll.execute(currentGUI, decode_pdf, commonValues);
                break;
            case DESELECTALL:
                DeSelectAll.execute(currentGUI, decode_pdf);
                break;
            case UPDATEGUILAYOUT:
                UpdateGUILayout.execute(args, currentGUI);
                break;
            case MOUSEMODE:
                MouseModeCommand.execute(args, currentGUI, mouseMode, decode_pdf);
                break;
            case PANMODE:
                PanMode.execute(args, currentGUI, mouseMode, decode_pdf);
                break;
            case TEXTSELECT:
                TextSelect.execute(args, currentGUI, mouseMode);
                break;
            case SEPARATECOVER:
                SeparateCover.execute(args, decode_pdf, properties, currentGUI, commonValues);
                break;
            case EXTRACTTEXT:
                ExtractText.execute(args, currentGUI, decode_pdf, commonValues);
                break;
            case EXTRACTASIMAGE:
                ExtractSelectionAsImage.execute(commonValues, currentGUI, decode_pdf);
                break;
            case ROTATELEFT:
                RotationLeft.execute(currentGUI, commonValues);
                break;
            case ROTATERIGHT:
                RotationRight.execute(currentGUI, commonValues);
                break;
            case OPENINSYSTEMDEFAULT:
                OpenInSystemDefault.execute(args, currentGUI, commonValues);
                break;
            case XREF:
                Xref.execute(args, currentGUI, commonValues, decode_pdf);
                break;
            case OBJECTS:
                Objects.execute(args, currentGUI, commonValues, decode_pdf);
                break;
        }
        return status;
    }

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

        switch (ID) {
            case FIRSTPAGE:
                PageNavigator.goFirstPage(args, commonValues, decode_pdf, currentGUI);
                break;

            case FBACKPAGE:
                PageNavigator.goFBackPage(args, commonValues, decode_pdf, currentGUI);
                break;

            case BACKPAGE:
                PageNavigator.goBackPage(args, commonValues, decode_pdf, currentGUI);
                break;

            case FORWARDPAGE:
                PageNavigator.goForwardPage(args, commonValues, decode_pdf, currentGUI);
                break;

            case FFORWARDPAGE:
                PageNavigator.goFForwardPage(args, commonValues, decode_pdf, currentGUI);
                break;

            case LASTPAGE:
                PageNavigator.goLastPage(args, commonValues, decode_pdf, currentGUI);
                break;

            case GOTO:
                PageNavigator.goPage(args, currentGUI, commonValues, decode_pdf);
                break;

            case SINGLE:
                Single.execute(args, decode_pdf, currentGUI);
                TextSelect.execute(args, currentGUI, mouseMode)//Enable text selection
                break;

            case CONTINUOUS:
                Continuous.execute(decode_pdf, currentGUI, args);
                PanMode.execute(args, currentGUI, mouseMode, decode_pdf)//Enables Panning of document
                break;

            case CONTINUOUS_FACING:
                ContinuousFacing.execute(args, decode_pdf, currentGUI, commonValues);
                PanMode.execute(args, currentGUI, mouseMode, decode_pdf)//Enables Panning of document
                break;

            case FACING:
                Facing.execute(args, decode_pdf, currentGUI, commonValues);
                PanMode.execute(args, currentGUI, mouseMode, decode_pdf)//Enables Panning of document
                break;

            case PAGEFLOW:
                PageFlow.execute(args, currentGUI, commonValues, decode_pdf, properties, searchFrame);
                break;

            case FULLSCREEN:
                FullScreen.execute(args, currentGUI, thumbnails, commonValues, decode_pdf, properties);
                break;

            case ZOOMIN:
                ZoomIn.execute(args, currentGUI, decode_pdf);
                break;

            case ZOOMOUT:
                ZoomOut.execute(args, currentGUI, decode_pdf);
                break;

            case PORTFOLIO_DETAIL:
                currentGUI.setDisplayView(Display.PORTFOLIO_DETAIL, Display.DISPLAY_CENTERED);
                break;

            case PORTFOLIO_TILES:
                currentGUI.setDisplayView(Display.PORTFOLIO_TILE, Display.DISPLAY_CENTERED);
                break;

        }
    }

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

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

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

        switch (ID) {
            case SCALING:
                Scaling.execute(args, commonValues, decode_pdf, currentGUI, viewStack);
                break;

            case ROTATION:
                Rotation.execute(args, currentGUI, commonValues);
                break;
        }
    }

    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);
                break;
            case SCROLL:
                Scroll.execute(args, currentGUI, commonValues, decode_pdf);
                break;
        }
    }

    @SuppressWarnings({"OverlyLongMethod""java:S138"})
    private Object executeViewerFunctionalityCommands(final int ID, final Object[] args) {
        Object status = null;
        switch (ID) {
            case ADDVIEW:
                viewStack.add((Integerargs[0](Rectangleargs[1](Integerargs[2]);
                break;
            case FORWARD:
                //go forward to next viewed location
                if (viewStack.forward() != null) {
                    decode_pdf.getFormRenderer().getActionHandler().changeTo(null, viewStack.forward().getPage(),
                            viewStack.forward().getLocation(), viewStack.forward().getType()false);
                }
                break;
            case BACK:
                //go back to last viewed location
                if (viewStack.back() != null) {
                    decode_pdf.getFormRenderer().getActionHandler().changeTo(null, viewStack.back().getPage(),
                            viewStack.back().getLocation(), viewStack.back().getType()false);
                }
                break;
            case PAGECOUNT:
                status = PageCount.execute(decode_pdf);
                break;
            case CURRENTPAGE:
                status = currentGUI.getValues().getCurrentPage();
                break;
            case GETOUTLINEPANEL:
                //ensure setup
                currentGUI.setBookmarks(true);
                status = currentGUI.getOutlinePanel();
                break;
            case GETTHUMBNAILPANEL:
                //ensure setup
                currentGUI.setBookmarks(true);
                status = currentGUI.getThumbnailPanel();
                break;
            case GETPAGECOUNTER:
                status = currentGUI.getPageCounter(SwingGUI.PageCounter.PAGECOUNTER2);
                break;
            case PAGEGROUPING:
                status = PageGrouping.execute(args, decode_pdf)//Group Pages
                break;

            case SETPAGECOLOR:
                SetPageColor.execute(args, decode_pdf);
                break;

            case SETUNDRAWNPAGECOLOR:
                SetUndrawnPageColor.execute(args, decode_pdf);
                break;

            case REPLACETEXTCOLOR:
                ReplaceTextColor.execute(args, decode_pdf);
                break;

            case SETTEXTCOLOR:
                SetTextColor.execute(args, decode_pdf);
                break;

            case CHANGELINEART:
                ChangeLineArt.execute(args, decode_pdf);
                break;
            case SETDISPLAYBACKGROUND:
                SetDisplayBackground.execute(args, decode_pdf);
                break;
            case SETREPLACEMENTCOLORTHRESHOLD:
                SetReplacementThreshold.execute(args, decode_pdf);
                break;
            case SETENHANCEFRACTIONALLINES: //Used for JavaFX Netbeans PDF Viewer Plugin.
                SetEnhanceFractionalLines.execute(args, decode_pdf);
                break;
            case SETHIDELINEWEIGHTS:
                SetHideLineWeights.execute(args, decode_pdf);
                break;
            case SETHIGHLIGHTFORMFIELDS:
                SetHighlightFormFields.execute(args, decode_pdf);
                break;
            case HIDEVERSIONNUMBER:
                currentGUI.hideVersionNumber();
                break;
            case SHOWVERSIONNUMBER:
                currentGUI.showVersionNumber();
                break;
        }

        return status;
    }

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

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

    private static void saveImage(final Object[] args, final SwingGUI currentGUI, final Values commonValues, final PdfDecoderInt decode_pdf) {

        if (args == null) {
            if (commonValues.getSelectedFile() == null) {
                currentGUI.showMessageDialog(Messages.getMessage("PdfViewer.NoFile"));
            else if (!decode_pdf.isExtractionAllowed()) {
                if (commonValues.isPDF()) {
                    currentGUI.showMessageDialog(Messages.getMessage("PdfViewerPermissionsError.Extraction"));
                }
            else {

                // get values from user

                final SaveImage current_selection = new SaveImage(commonValues.getInputDir(),
                        commonValues.getPageCount(), commonValues.getCurrentPage());
                final int userChoice = current_selection.display(currentGUI.getFrame(),
                        Messages.getMessage("PdfViewerTitle.SaveImagesFromPageRange"));

                // get parameters and call if YES
                if (commonValues.getFileIsURL()) {
                    currentGUI.showMessageDialog(Messages.getMessage("PdfViewerMessage.CannotExportFromURL"));
                else if (userChoice == JOptionPane.OK_OPTION) {
                    final Exporter exporter = new Exporter(currentGUI, commonValues.getSelectedFile(), decode_pdf);
                    exporter.extractImagesOnPages(current_selection);
                }
            }
        }
    }
}