package vismon.gui;

import info.clearthought.layout.TableLayout;
import info.clearthought.layout.TableLayoutConstants;
import vismon.data.Scenario;
import vismon.data.Session;
import vismon.util.Constants;

import javax.swing.*;
import javax.swing.border.Border;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;

public class ScenariosPanel extends JPanel {

    private JPanel mainPanel;
    private JPanel tablePanel;
    private JPanel buttonPanel;

    private final int showColNum = 0;           // show column
    private final int nameColNum = 1;           // name column
    private final int colorColNum = 4;              // mainColor column
    private final int addDelColNum = 5;             // mainColor column

    private JTable table;
    private ScenarioTableModel tableModel;
    private final Object[] headers = {"Show", "Name", "Mng1", "Mng2", "Colour", "Add/Delete"};
    private Object[] tableLastRow;


    ScenariosPanel() {
        super();
        tableLastRow = getLastRow(0);

        init();
    }

    private void init() {
        mainPanel = new JPanel();
        double[][] mainLayout = new double[][]{{TableLayoutConstants.FILL},
                {TableLayoutConstants.FILL, 30}};
        mainPanel.setLayout(new TableLayout(mainLayout));

        tablePanel = new JPanel();
        mainPanel.add(tablePanel, "0,0");

        addScenarioTable();

        buttonPanel = new JPanel();
        mainPanel.add(buttonPanel, "0,1");

        addButtons();

        this.setLayout(new BorderLayout());
        this.add(mainPanel);
    }

    class ScenarioTableModel extends DefaultTableModel {

        private int lastRowNum;

        public ScenarioTableModel() {
            lastRowNum = 0;
        }

        public void addLastRowNum(int value) {
            lastRowNum += value;
        }

        @Override
        public boolean isCellEditable(int row, int col) {
            if (row == lastRowNum)
                return true;
            if (col == nameColNum || col == showColNum ||
                    col == colorColNum || col == addDelColNum)
                return true;
            return false;
        }
    }


    private TableCellRenderer decorateRenderer(final TableCellRenderer renderer) {
        if (renderer == null)
            return decorateRenderer(new DefaultTableCellRenderer());
        return new TableCellRenderer() {
            public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
                Component component = renderer.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);

                if (isSelected || hasFocus)
                    return component;

                if (column != showColNum && column != colorColNum)
                    component.setBackground(row != (table.getRowCount()-1) && Session.getScenario(row).isFiltered()?
                                                Color.lightGray : Color.WHITE);

                return component;
            }
        };
    }

    private void decorateColumns() {
        for (int i = 0; i < table.getColumnCount(); ++i) {
            TableColumn column = table.getColumnModel().getColumn(i);
            column.setCellRenderer(decorateRenderer(column.getCellRenderer()));
        }
    }

    private void addScenarioTable() {
        tableModel = new ScenarioTableModel();
        tableModel.setDataVector(new Object[][]{getLastRow(0)}, headers);

        table = new JTable(tableModel);
        table.setShowGrid(true);
        table.setGridColor(Color.LIGHT_GRAY);

        TableColumn showColumn = table.getColumnModel().getColumn(showColNum);
        showColumn.setCellRenderer(new MyCheckBoxRenderer());
        showColumn.setCellEditor(new MyCheckBoxEditor());

        TableColumn colorColumn = table.getColumnModel().getColumn(colorColNum);
        colorColumn.setCellRenderer(new MyColorRenderer());
        colorColumn.setCellEditor(new MyColorEditor());

        TableColumn addDelColumn = table.getColumnModel().getColumn(addDelColNum);
        addDelColumn.setCellRenderer(new MyButtonRenderer());
        addDelColumn.setCellEditor(new MyButtonEditor(new JCheckBox()));

        table.setRowHeight(20);
        table.setAutoCreateRowSorter(true);

        table.addKeyListener(new KeyListener() {
            public void keyTyped(KeyEvent keyEvent) {
                int row = table.getSelectedRow();
                int col = table.getSelectedColumn();

                if ((row == (table.getRowCount()-1) && (col == 1 || col == 2 || col == 3)) || col == 1) {
                    if (keyEvent.getKeyCode() == 0)
                        table.setValueAt("", row, col);
                    else
                        table.setValueAt(KeyEvent.getKeyText(keyEvent.getKeyCode()), row, col);
                }/* else {
                    System.out.println("Cannot enter the typed chars.");
                }*/
            }

            public void keyPressed(KeyEvent keyEvent) {
                int row = table.getSelectedRow();
                int col = table.getSelectedColumn();

                if (row == (table.getRowCount()-1) && col == 5 && keyEvent.getKeyCode() == KeyEvent.VK_ENTER)
                    createScenario(row);

            }

            public void keyReleased(KeyEvent keyEvent) {
            }
        });

        tableModel.addTableModelListener(new TableModelListener() {
            public void tableChanged(TableModelEvent tableModelEvent) {
                int row = tableModelEvent.getFirstRow();
                int col = tableModelEvent.getColumn();

                // do nothing in the last row
                if (row == table.getRowCount()-1)
                    return;

                if (col == showColNum) {
                    Session.getScenario(row).setVisible((Boolean) table.getValueAt(row, col));
                } else if (col == nameColNum) {
                    Session.getScenario(row).setName((String) table.getValueAt(row, col));
                } else if (col == colorColNum) {
                    Session.getScenario(row).setColor((Color) table.getValueAt(row, col));
                }
                Vismon.getVismonInstance().updatePlots();
            }
        });

        ListSelectionModel tableListSelectionModel = table.getSelectionModel();
        tableListSelectionModel.addListSelectionListener(new ListSelectionListener() {
            public void valueChanged(ListSelectionEvent listSelectionEvent) {
                int row = table.getSelectedRow();
                if (row == table.getRowCount()-1 || row < 0)
                    return;

                Session.setSelectedScenario(Session.getScenario(row));
                Vismon.getVismonInstance().updatePlots();
            }
        });

        JScrollPane tableScrollPane = new JScrollPane(table);

        double[][] tableLayout = new double[][]{{TableLayoutConstants.FILL},
                {TableLayoutConstants.FILL}};
        tablePanel.setLayout(new TableLayout(tableLayout));
        tablePanel.add(tableScrollPane, "0,0");
        decorateColumns();
    }

    private void addButtons() {
        double[][] buttonLayout = new double[][]{{0.5, 0.5},
                {TableLayoutConstants.FILL}};
        buttonPanel.setLayout(new TableLayout(buttonLayout));

        /*JButton viewScenarioValuesButton = new JButton("View Scenario Values");
        viewScenarioValuesButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent actionEvent) {
                ScenarioDetailsDialog scenarioDetailsDialog = new ScenarioDetailsDialog();
                scenarioDetailsDialog.run();
            }
        });
        buttonPanel.add(viewScenarioValuesButton, "0,0");*/

        JButton exportValuesButton = new JButton("Export Values");
        buttonPanel.add(exportValuesButton, "0,0");

        JButton deleteAllButton = new JButton("Delete all Scenarios");
        deleteAllButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent actionEvent) {
                removeAllScenarios();
            }
        });
        buttonPanel.add(deleteAllButton, "1,0");
    }

    private Object[] getLastRow(int i) {
        return new Object[]{Boolean.FALSE, "Scn" + Scenario.scenarioCounter, "", "", Constants.getScenarioColor(), ""};
    }

    public void addRow(Scenario scn) {
        String name = scn.getName();
        String value1 = scn.getMngAction().getMngValue(Session.getMngOption(0)) + "";
        String value2 = scn.getMngAction().getMngValue(Session.getMngOption(1)) + "";
        tableModel.addRow(new Object[]{new Boolean(scn.isVisible()),
                name,
                value1,
                value2,
                scn.getColor(),
                " "});
        tableModel.addRow(getLastRow(Session.getScenarios().size()));
        tableModel.removeRow(table.getRowCount() - 3);
        tableModel.addLastRowNum(1);
    }

    private void createScenario(int rowNum) {
        String name = (String) table.getValueAt(rowNum, 1);
        double xMngOption = Double.parseDouble((String) table.getValueAt(rowNum, 2));
        double yMngOption = Double.parseDouble((String) table.getValueAt(rowNum, 3));
        Color color = (Color) table.getValueAt(rowNum, 4);

        Session.createScenario(name, xMngOption, yMngOption, color);
    }

    public void removeRow(int row) {
        tableModel.removeRow(row);
        tableModel.addLastRowNum(-1);
    }

    private void removeScenario(int row) {
        Session.removeScenario(row);
    }

    public void removeAllScenarios() {
        while (table.getRowCount() > 1)
            removeScenario(0);
        Vismon.getVismonInstance().haveScenarios(false);
        Scenario.resetScenarioNum();
    }

    public void highlightSelectedScenario() {
        if (Session.getSelectedScenario() != null) {
            int rank = Session.getScenarioRank(Session.getSelectedScenario());
            table.setRowSelectionInterval(rank, rank);
        } else {
            table.clearSelection();
        }
    }

    private void addDelRow(int rowNum) {
        boolean isLastRow = rowNum == (table.getRowCount()-1);
        if (isLastRow)
            createScenario(rowNum);
        else
            removeScenario(rowNum);
        Vismon.getVismonInstance().updatePlots();
    }


    /**
     * ***********************************************************************
     */

    private class MyCheckBoxRenderer extends JCheckBox implements TableCellRenderer {
        public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
            setSelected((Boolean) value);
            return this;
        }
    }

    private class MyCheckBoxEditor extends DefaultCellEditor {
        public MyCheckBoxEditor() {
            super(new JCheckBox());
        }
    }

    private class MyColorRenderer extends JLabel implements TableCellRenderer {
        private Border border = null;

        public MyColorRenderer() {
            setOpaque(true);                        // MUST do this for background to show up.
        }

        public Component getTableCellRendererComponent(JTable table, Object color, boolean isSelected, boolean hasFocus, int row, int column) {
            Color newColor = (Color) color;
            setBackground(newColor);

            if (border == null)
                border = BorderFactory.createMatteBorder(2, 10, 2, 10, table.getBackground());
            setBorder(border);

            setToolTipText("RGB value: <" + newColor.getRed() + ", "
                    + newColor.getGreen() + ", "
                    + newColor.getBlue() + ">");
            return this;
        }
    }

    private class MyColorEditor extends AbstractCellEditor implements TableCellEditor, ActionListener {
        protected static final String EDIT = "edit";

        Border border;

        private Color currentColor;
        private JButton button;
        private JColorChooser colorChooser;
        private JDialog dialog;

        public MyColorEditor() {
            border = BorderFactory.createMatteBorder(2, 10, 2, 10, Color.WHITE);

            button = new JButton();
            button.setActionCommand(EDIT);
            button.addActionListener(this);
            button.setBorderPainted(false);

            colorChooser = new JColorChooser();
            dialog = JColorChooser.createDialog(button,
                    "Pick a Color",
                    true,  //modal
                    colorChooser,
                    this,  //OK button handler
                    null); //no CANCEL button handler
        }

        /**
         * Handles events from the editor button and from
         * the dialog's OK button.
         */
        public void actionPerformed(ActionEvent e) {
            if (EDIT.equals(e.getActionCommand())) {
                button.setBackground(currentColor);
                button.setBorder(border);
                button.setOpaque(true);

                colorChooser.setColor(currentColor);
                dialog.setVisible(true);

                //Make the renderer reappear.
                fireEditingStopped();
            } else {
                currentColor = colorChooser.getColor();
            }
        }

        public Object getCellEditorValue() {
            return currentColor;
        }

        public Component getTableCellEditorComponent(JTable table,
                                                     Object value,
                                                     boolean isSelected,
                                                     int row,
                                                     int column) {
            currentColor = (Color) value;
            return button;
        }
    }

    private class MyButtonRenderer implements TableCellRenderer {

        private JButton button;

        public MyButtonRenderer() {
            super();
            button = new JButton("");
            button.setBorder(BorderFactory.createEmptyBorder());
        }

        public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
            if (row == (table.getRowCount() - 1))
                button.setIcon(new ImageIcon("images/add.png"));
            else
                button.setIcon(new ImageIcon("images/remove.png"));
            return button;
        }
    }

    private class MyButtonEditor extends DefaultCellEditor {
        protected JButton button;
        private boolean isPushed;
        private boolean isLastRow;
        private int rowNum;

        public MyButtonEditor(JCheckBox checkBox) {
            super(checkBox);
            button = new JButton();
            button.setOpaque(true);
            button.setBorder(BorderFactory.createEmptyBorder());
            button.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    fireEditingStopped();
                }
            });
        }

        public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
            rowNum = row;
            if (row == (table.getRowCount() - 1))
                button.setIcon(new ImageIcon("images/add.png"));
            else
                button.setIcon(new ImageIcon("images/remove.png"));

            isPushed = true;
            if (row == (table.getRowCount() - 1))
                isLastRow = true;
            else
                isLastRow = false;
            return button;
        }

        public Object getCellEditorValue() {
            if (isPushed)
                addDelRow(rowNum);

            isPushed = false;

            return new String("");
        }

        public boolean stopCellEditing() {
            isPushed = false;
            return super.stopCellEditing();
        }

        protected void fireEditingStopped() {
            super.fireEditingStopped();
        }
    }

}
