package de.renew.gui;

import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.StringTokenizer;
import javax.swing.DefaultListModel;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JPanel;

import de.renew.draw.storables.ontology.Drawing;
import de.renew.plugin.command.CLCommand;
import de.renew.simulator.api.SimulationManager;


public class Demonstrator implements CLCommand {
    private static final org.apache.log4j.Logger logger =
        org.apache.log4j.Logger.getLogger(Demonstrator.class);
    private static JFrame frame = null;
    private static JList<String> list = null;
    private static DefaultListModel<String> listModel = null;

    /* specified by the CLCommand interface */
    @Override
    public String getDescription() {
        return "opens a window with a list of drawing file names";
    }

    /**
     * @see de.renew.plugin.command.CLCommand#getArguments()
     */
    @Override
    public String getArguments() {
        return "fileNames";
    }

    /* specified by the CLCommand interface */
    @Override
    public void execute(String[] args, PrintStream response) {
        response.println("The Renew demonstration GUI");
        if (args.length == 0) {
            response.println("Usage: demonstrator files...");
            response.println("or     demonstrator -conffile");
        } else if (args[0].startsWith("-")) {
            try {
                FileReader fileReader = new FileReader(args[0].substring(1));
                BufferedReader reader = new BufferedReader(fileReader);

                List<String> names = new ArrayList<>();
                while (reader.ready()) {
                    String name = reader.readLine();
                    if (name != null && !name.isEmpty()) {
                        names.add(name);
                    }
                }
                String[] arr = names.toArray(new String[0]);
                setup(arr);
                reader.close();
            } catch (Exception e) {
                response.println("Error: could not access configuration file.");
                logger.error("Could not access configuration file.", e);
            }
        } else {
            setup(args);
        }
    }

    /**
     * Shows a frame with the given array of filenames.
     *
     * @param args an array of filenames
     **/
    public static synchronized void setup(final String[] args) {
        if (frame == null) {
            frame = new JFrame("Demonstration Drawings");

            frame.setSize(600, 200);
            GridBagLayout gridBag = new GridBagLayout();
            frame.getContentPane().setLayout(gridBag);

            GridBagConstraints c = new GridBagConstraints();
            c.fill = GridBagConstraints.BOTH;
            c.weightx = 1;
            c.weighty = 1;
            c.gridwidth = GridBagConstraints.REMAINDER;

            listModel = new DefaultListModel<>();
            list = new JList<>(listModel);
            list.addMouseListener(new ActionJList(list));
            gridBag.setConstraints(list, c);
            frame.getContentPane().add(list);

            JPanel panel = new JPanel();
            c.fill = GridBagConstraints.HORIZONTAL;
            c.weighty = 0;
            gridBag.setConstraints(panel, c);
            frame.getContentPane().add(panel);

            gridBag = new GridBagLayout();
            panel.setLayout(gridBag);
            c = new GridBagConstraints();
            c.weightx = 1;
            c.fill = GridBagConstraints.BOTH;
            c.gridwidth = 1;

            JButton button;
            button = new JButton("Replace");
            button.addActionListener(e -> replaceDrawings());
            gridBag.setConstraints(button, c);
            panel.add(button);

            button = new JButton("Include");
            button.addActionListener(e -> openDrawings());
            gridBag.setConstraints(button, c);
            panel.add(button);

            button = new JButton("Exit");
            button.addActionListener(e -> {
                GuiPlugin.getCurrent().closeGui();
                frame.setVisible(false);
            });
            gridBag.setConstraints(button, c);
            panel.add(button);

        }

        listModel.removeAllElements();
        for (String arg : args) {
            listModel.addElement(arg);
        }

        EventQueue.invokeLater(() -> frame.setVisible(true));
    }

    static synchronized void replaceDrawings() {
        CPNApplication app = GuiPlugin.getCurrent().getGui();
        if (app == null) {
            GuiPlugin.getCurrent().openGui();
            app = GuiPlugin.getCurrent().getGui();
        }

        int i = list.getSelectedIndex();
        if (i >= 0 && i < listModel.size()) {
            SimulationManager.terminateSimulation();
            app.cleanupSimulationWindows();

            Enumeration<Drawing> enumeration = app.drawings();
            while (enumeration.hasMoreElements()) {
                Drawing drawing = enumeration.nextElement();
                app.closeDrawing(drawing);
            }
        }

        openDrawings();
    }

    private static synchronized void openDrawings() {
        CPNApplication app = GuiPlugin.getCurrent().getGui();
        if (app == null) {
            GuiPlugin.getCurrent().openGui();
            app = GuiPlugin.getCurrent().getGui();
        }

        int i = list.getSelectedIndex();
        if (i >= 0 && i < listModel.size()) {
            StringTokenizer tokenizer = new StringTokenizer(listModel.elementAt(i), ",", false);
            List<String> tokens = new ArrayList<>();
            while (tokenizer.hasMoreTokens()) {
                tokens.add(tokenizer.nextToken());
            }
            app.loadAndOpenCommandLineDrawings(tokens.toArray(new String[0]));
        }
    }

    public static synchronized void cleanup() {
        if (frame != null) {
            final JFrame finalFrame = frame;
            EventQueue.invokeLater(() -> {
                finalFrame.setVisible(false);
                finalFrame.dispose();
            });
        }
        frame = null;
        list = null;
        listModel = null;
    }
}


class ActionJList extends MouseAdapter {
    protected final JList<String> list;

    public ActionJList(JList<String> l) {
        list = l;
    }

    @Override
    public void mouseClicked(MouseEvent e) {
        if (e.getClickCount() == 2) {
            int index = list.locationToIndex(e.getPoint());
            list.ensureIndexIsVisible(index);
            Demonstrator.replaceDrawings();
        }
    }
}