package de.renew.imagenetdiff;

import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.Enumeration;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.filechooser.FileFilter;

import CH.ifa.draw.DrawPlugin;
import CH.ifa.draw.IOHelper;
import CH.ifa.draw.application.DrawApplication;
import CH.ifa.draw.io.DrawingFileHelper;
import CH.ifa.draw.util.Command;
import de.renew.draw.storables.ontology.Drawing;


/**
 * Abstract base class for diff-related commands in the ImageNetDiff plugin.
 * Needs installed ImageMagick in the system.
 * <p>
 * Subclasses are expected to implement the {@code doDiff} method defined in the {@link DiffExecutor}
 * interface to carry out the actual comparison logic.
 * <p>
 * This class also includes a helper method {@code exchangeColor} for color replacement in images using a fuzzy match.
 * @author Lawrence Cabac
 *
 */
public abstract class AbstractDiffCommand extends Command implements DiffExecutor {

    private static final org.apache.log4j.Logger LOGGER =
        org.apache.log4j.Logger.getLogger(AbstractDiffCommand.class);
    private String _imageExtension;

    /**
     * Constructs a command with the given name.
     * @param name the name of the command.
     */
    public AbstractDiffCommand(String name) {
        super(name);
    }

    /**
     * Sets the image extension.
     * @param imageExtension Name of the image extension.
     */
    public void setImageExtension(String imageExtension) {
        this._imageExtension = imageExtension;
    }

    /**
     * Gets the image extension.
     * @return The name of the image extension as a String.
     */
    public String getImageExtension() {
        return _imageExtension;
    }

    /* (non-Javadoc)
     * @see CH.ifa.draw.util.Command#execute()
     */
    @Override
    public void execute() {
        //Get the environment. For now, we need the gui.
        DrawPlugin guiPlugin = DrawPlugin.getCurrent();
        DrawApplication gui = DrawPlugin.getGui();
        JFrame frame = gui.getFrame();

        // test weather ImageMagick is installed on the system.
        try {
            Runtime.getRuntime().exec("compare --version");
        } catch (IOException e2) {
            LOGGER.error(e2.getMessage());
            LOGGER.debug(e2.getMessage(), e2);
            JOptionPane.showMessageDialog(
                frame, "ImageMagick not found!", "ImageMagick not found!",
                JOptionPane.ERROR_MESSAGE);
            return;
        }


        // If (exactly) two drawings are open in editor ask to make diff
        // between them
        Enumeration<Drawing> en = gui.drawings();
        int i = 0;
        while (en.hasMoreElements()) {
            en.nextElement();
            i++;
        }
        Drawing[] d = new Drawing[2];
        int check = JOptionPane.NO_OPTION;
        if (i == 2) {
            Enumeration<Drawing> enu = gui.drawings();
            i = 0;
            while (enu.hasMoreElements()) {
                d[i++] = enu.nextElement();
            }
            String message = "Exactly two drawing are opened: " + d[0].getName() + " and "
                + d[1].getName() + ".\n Would you like to compare these?";
            String title = "Create diff...";
            check = JOptionPane.showOptionDialog(
                frame, message, title, JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE,
                null, null, null);
        }

        // If not (exactly) two drawings are open or if canceled dialogue.
        // Prompt for both comparable files.
        assert guiPlugin != null;
        IOHelper io = guiPlugin.getIOHelper();
        FileFilter ff = io.getFileFilterKnownTypes();

        // Do prompt for two files
        Drawing drawing1;
        Drawing drawing2;
        if (check == JOptionPane.YES_OPTION) {
            drawing1 = d[0];
            drawing2 = d[1];
        } else {
            String dir = System.getProperty("user.dir");
            File[] file1 = io.getLoadPath(new File(dir), ff, false);
            File[] file2 = io.getLoadPath(new File(dir), ff, false);
            System.out.println(Arrays.toString(file1));
            System.out.println(Arrays.toString(file2));
            if (file1 != null && file2 != null && file1.length > 0 && file2.length > 0
                && file1[0] != null && file2[0] != null) {
                drawing1 = DrawingFileHelper.loadDrawing(file1[0], gui);
                drawing2 = DrawingFileHelper.loadDrawing(file2[0], gui);

            } else {
                return;
            }
        }
        doDiff(gui, drawing1, drawing2, false);
    }

    /**
     * Method replaces a color in an image with a new color by building a shell command for ImageMagick.
     * @param name Pathname of the Image.
     * @param fuzz an integer percentage (0–100) indicating how close a color must be to match oldColor.
     * @param oldColor Name of the old color.
     * @param newColor Name of the new color.
     */
    protected void exchangeColor(String name, int fuzz, String oldColor, String newColor) {
        LOGGER.debug("exchangeColor called with: " + fuzz + " " + oldColor + " " + newColor);
        Process process;
        int exit;
        process = null;
        try {
            String cvrtstr =
                "convert " + name + getImageExtension() + " " + "-fuzz " + fuzz + "% -fill "
                    + newColor + "  -opaque " + oldColor + " " + name + getImageExtension();
            LOGGER.info(Object.class.getName() + ": Convert String:\n" + cvrtstr);
            process = Runtime.getRuntime().exec(cvrtstr);
        } catch (Exception e1) {
            LOGGER.error(e1.getMessage());
            LOGGER.debug(e1.getMessage(), e1);
        }
        if (process != null) {
            try {
                exit = process.waitFor();
                if (LOGGER.isDebugEnabled()) {
                    LOGGER.debug(
                        AbstractDiffClCommand.class.getSimpleName() + ": process' exit code = "
                            + exit);
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}