package surface;

import hu.swankey.ammo.common.script.AmmoScriptException;
import hu.swankey.ammo.common.yggdrasil.basics.YObject;
import hu.swankey.ammo.common.yggdrasil.ext.Command;
import hu.swankey.ammo.common.yggdrasil.ext.Universe;
import hu.swankey.ammo.common.yggdrasil.ext.World;

import java.awt.Component;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.HashMap;

import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingWorker;

import background.Controller;
import client_engine.Commander;
import client_engine.IClientControllerListener;

public class CommandBar extends JPanel implements IClientControllerListener {

    private static final long serialVersionUID = 1L;
    private static final int OPTIONS_BUTTON_WIDTH = 50;
    private static final String BUTTON_OPTIONS_OPEN = ">>";
    private static final String BUTTON_OPTIONS_CLOSE = "<<";
    private static final int TEXT_HEIGHT = 20;
    private static final int BUTTON_HEIGHT = 24;
    private static final String TITLE_ADD_COMMAND = "Add new command";
    private static final String NEW_COMMAND_NAME = "New Command";
    private static final String NO_UNIVERSE_SELECTED = "No universe selected";

    private static final String MSG_SYNTAX = " (Syntax error)";
    private static final String MSG_CLASS_NOT_FOUND = " (ClassNotFound)";
    private static final String MSG_EXCEPTION = " (Exception)";

    private final Controller controller;

    private final HashMap<Command, CommandPanel> commandPanels = new HashMap<Command, CommandPanel>();
    private final HashMap<Command, CommandPanel> hiddenCommandPanels = new HashMap<Command, CommandPanel>();

    // private final JPanel panel = new JPanel();

    private final boolean editor;

    private final JButton button_addNewCommand = new JButton(TITLE_ADD_COMMAND);

    private CommandBar(final Controller controller, final boolean editor) {
        this.controller = controller;
        this.editor = editor;
        regenerate(controller.getUniverse());

        // "Add Command" Button:
        if (editor) {
            button_addNewCommand.setAlignmentX(Component.CENTER_ALIGNMENT);
            button_addNewCommand.setAlignmentY(Component.CENTER_ALIGNMENT);
        }
        
        button_addNewCommand.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                controller.getUniverse().addCommand(
                        Command.yclass().create(NEW_COMMAND_NAME));
            }
        });
    }

    public static CommandBar createCommandBar(final Controller controller, final boolean editor) {
        final CommandBar commandBar = new CommandBar(controller, editor);

        commandBar.setLayout(new BoxLayout(commandBar, BoxLayout.Y_AXIS));



        controller.addListener(commandBar);
        return commandBar;
    };

    private static class CommandPanel extends JPanel {

        private static final long serialVersionUID = 1L;
        private final Command command;
        private final JButton commandButton;
        private final Commander commander;
        private final Controller controller;

        private CommandPanel(Controller controller, Command command) {
            this.controller = controller;
            this.command = command;
            this.commander = controller.getCommander();
            commandButton = new JButton(command.getTitle());
        }

        public static CommandPanel createCommandPanel(final Command command,
                final Controller controller) {

            final CommandPanel cp = new CommandPanel(controller, command);
            final JPanel visiblePanel = new JPanel();
            final JPanel optionsPanel = new JPanel();
            cp.setLayout(new BoxLayout(cp, BoxLayout.Y_AXIS));
            cp.setFont(Font.decode(Font.MONOSPACED).deriveFont(Font.BOLD, 11));
            cp.add(visiblePanel);
            cp.add(optionsPanel);

            // -- Options Panel ---
            final JTextField commandText = new JTextField(command.getTitle());
            final JTextField commandAliasText = new JTextField(command
                    .getCommand(), 1);
            optionsPanel.setFont(null);
            optionsPanel
                    .setLayout(new BoxLayout(optionsPanel, BoxLayout.Y_AXIS));
            optionsPanel.setVisible(false);
            optionsPanel.add(commandText);
            optionsPanel.add(commandAliasText);

            // -- Visible Panel --
            final JButton optionsButton = new JButton(BUTTON_OPTIONS_OPEN);
            visiblePanel
                    .setLayout(new BoxLayout(visiblePanel, BoxLayout.X_AXIS));
            visiblePanel.setFont(null);
            visiblePanel.add(cp.commandButton);
            visiblePanel.add(optionsButton);

            // Command Button:
            cp.commandButton.setFont(Font.decode(Font.MONOSPACED).deriveFont(Font.BOLD, 11));
            cp.commandButton.setMaximumSize(new Dimension(Integer.MAX_VALUE,BUTTON_HEIGHT));
            cp.actualize();
            cp.commandButton.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent evt) {
                    try {

                        SwingWorker<Void, Void> swingworker = new SwingWorker<Void, Void>() {
                            @Override
                            public Void doInBackground() {

                                try {
                                    controller.getCommander().execute(
                                            command.getCommand());
                                } catch (Exception e) {
                                    e.printStackTrace();
                                }

                                return null;
                            }
                        };

                        swingworker.execute();

                    } catch (AmmoScriptException e) {
                        controller.printError(e);
                    } catch (Exception e) {
                        controller.reportError(e);
                    }
                }
            });

            // Options Button:
            optionsButton.setFont(null);
            optionsButton.setMinimumSize(new Dimension(OPTIONS_BUTTON_WIDTH,
                    BUTTON_HEIGHT));
            optionsButton.setMaximumSize(new Dimension(OPTIONS_BUTTON_WIDTH,
                    BUTTON_HEIGHT));
            optionsButton.addActionListener(new ActionListener() {

                @Override
                public void actionPerformed(ActionEvent evt) {
                    optionsPanel.setVisible(!optionsPanel.isVisible());

                    if (!optionsPanel.isVisible()) {
                        command.setCommand(commandAliasText.getText());
                        command.setTitle(commandText.getText());

                        cp.actualize();
                        // cp.commandButton.setText(commandText.getText());
                        optionsButton.setText(BUTTON_OPTIONS_OPEN);
                        // cp.commandButton.setEnabled(
                        // controller.getCommander().isValid(command) );

                    } else
                        optionsButton.setText(BUTTON_OPTIONS_CLOSE);
                }
            });

            // Textfields:
            commandText.setFont(null);
            commandText.setMaximumSize(new Dimension(Integer.MAX_VALUE,
                    TEXT_HEIGHT));
            commandAliasText.setFont(null);
            commandAliasText.setMaximumSize(new Dimension(Integer.MAX_VALUE,
                    TEXT_HEIGHT));

            // Hotkey:
            // JTextField jtext_hotkey = new JTextField();
            // JComboBox jcombo_primary = new JComboBox();
            // jtext_hotkey.setText("CTRL + A");
            // jcombo_primary.setEditable(false);
            // jcombo_primary.add( new JLabel("Character") );

            // cp.add(jcombo_primary);
            // cp.add(jtext_hotkey);

            return cp;
        }

        private void actualize() {

            try {
                int commandStatus = commander.getCommandStatus(command);

                switch (commandStatus) {
                case Commander.STATUS_OK:
                    commandButton.setEnabled(true);
                    commandButton.setForeground(null);
                    commandButton.setText(command.getTitle());
                    break;
                case Commander.STATUS_SYNTAX_ERROR:
                    commandButton.setEnabled(false);
                    commandButton.setText(command.getTitle() + MSG_SYNTAX);
                    commander.getCommandStatus(command);
                    break;
                case Commander.STATUS_PRIMARY_CLASS_NOT_FOUND:
                case Commander.STATUS_SECONDARY_CLASS_NOT_FOUND:
                    commandButton.setEnabled(false);
                    commandButton.setText(command.getTitle() + MSG_CLASS_NOT_FOUND);
                    break;
                case Commander.STATUS_UNEXPECTED_PRIMARY_CLASS:
                case Commander.STATUS_UNEXPECTED_SECONDARY_CLASS:
                case Commander.STATUS_PRIMARY_ELEMENT_NULL:
                case Commander.STATUS_SECONDARY_ELEMENT_NULL:
                    commandButton.setEnabled(false);
                    break;
                default:
                    String msg;
                    commandButton.setEnabled(false);
                    commandButton.setText(command.getTitle());
                    controller.printToConsole("Unknown command status!: " + command.getTitle());
                    break;
                }

            } catch (AmmoScriptException ex) {
                commandButton.setEnabled(false);
                commandButton.setText(command.getTitle() + MSG_EXCEPTION);
                controller.printToConsole("Exception in command("
                        + command.getTitle() + "): " + ex.getMessage());
            } catch (Exception ex) {
                commandButton.setEnabled(false);
                commandButton.setText(command.getTitle() + MSG_EXCEPTION);
                controller.reportError(ex);
            }

            // if (command.getTitle().equals("Fire!!"))
            // //try {
            // commander.execute(command.getCommand());
            // } catch (Exception e) {
            // String status = (commandStatus ==
            // Commander.COMMAND_STATUS_INVALID ? "syntactically wrong" :
            // "invalid");
            // controller.printToConsole(command.getName() + " is " + status +
            // ": " + e.getMessage());
            // throw new RuntimeException(e);
            // }

            // if (valid) {
            //				
            // commandButton.setForeground(null);
            // commandButton.setText(command.getTitle());
            // } else {
            // commandButton.setEnabled(true);
            // commandButton.setForeground(COLOR_PROBLEM);
            // commandButton.setText(command.getTitle() + MSG_SYNTAX);
            // }

            // VALID & RUNNABLE -> normál
            // VALID & !RUNNABLE -> szürke
            // !VALID -> piros

            // commandButton.setText(command.getTitle());

            // try {
            //							
            //				
            // //commandButton.setForeground(null);
            // } catch (AmmoScriptSyntaxException e){
            // //commandButton.setEnabled(true);
            //				
            //				
            // controller.printError(e);
            // //System.out.println("Ilyen is vansdf");
            // } //catch (AmmoScriptRuntimeException e){
            // // //controller.printToConsole("");
            // // System.out.println("Ilyen is van: ");
            // // e.printStackTrace();
            // //
            // // }
        }

    }

    @Override
    public void primaryElementChanged(YObject newElement) {
        actualizeButtons();
    }

    @Override
    public void secondaryElementChanged(YObject newElement) {
        actualizeButtons();
    }

    @Override
    public void selectedWorldChanged(World world) {
    }

    @Override
    public void cursorChanged(Dimension cursor) {
        actualizeButtons();
    }

    @Override
    public void selectedUniverseChanged(Universe universe) {
        regenerate(universe);
    }

    private void regenerate(Universe universe) {

        removeAll();
        commandPanels.clear();

        if (universe != null) {
            for (YObject commandE : universe.getCommandContainer()
                    .getElements()) {
                CommandPanel commandPanel = CommandPanel.createCommandPanel(
                        (Command) commandE, controller);
                commandPanels.put((Command) commandE, commandPanel);

                if (editor) {
                    add(commandPanel);
                } else {
                    add(commandPanel.commandButton);
                }

            }
            add(button_addNewCommand);
        } else {
            JLabel label = new JLabel(NO_UNIVERSE_SELECTED);
            label.setAlignmentX(Component.CENTER_ALIGNMENT);
            label.setAlignmentY(Component.CENTER_ALIGNMENT);
            add(label);
        }
    }

    public JButton addHiddenCommand(String title, String code, String primary,
            String secondary) {
        Command command = Command.yclass().create(title, code, primary,
                secondary);
        CommandPanel commandPanel = CommandPanel.createCommandPanel(command,
                controller);
        hiddenCommandPanels.put(command, commandPanel);

        return commandPanel.commandButton;
    }

    private void actualizeButtons() {
        for (CommandPanel commandPanel : commandPanels.values())
            commandPanel.actualize();

        for (CommandPanel commandPanel : hiddenCommandPanels.values())
            commandPanel.actualize();
    }

}
