package de.renew.lola2.gui;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Collections;
import java.util.Comparator;
import java.util.Vector;
import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.DefaultTableModel;

import CH.ifa.draw.figures.TextFigure;
import de.renew.lola2.LolaFileCreator;
import de.renew.lola2.LolaTask;
import de.renew.lola2.analysis.DirectLolaResult;
import de.renew.lola2.analysis.IndirectLolaResult;
import de.renew.lola2.analysis.LolaAnalyzer;
import de.renew.lola2.analysis.LolaResult;
import de.renew.lola2.analysis.LolaResultStatus;


public class TasksPanel extends JPanel {
    /**
     * This field holds the reference to the Lola GUI instance.
     */
    private LolaGUI _lolaGUI;
    private static org.apache.log4j.Logger _logger =
        org.apache.log4j.Logger.getLogger(TasksPanel.class);
    /**
     * This field holds the JTable that displays the tasks.
     */
    private JTable _taskTable;
    /**
     * This field holds the text of the new task to be added.
     * It is updated whenever the text in the input field changes.
     */
    protected String _newTaskText = "";

    /**
     * Fields for the general panel needed globally
     */
    private static final Vector<String> TASK_COLUMN_NAMES = new Vector<String>();

    {
        TASK_COLUMN_NAMES.add("Result");
        TASK_COLUMN_NAMES.add("Verification Task");
    }

    public TasksPanel(LolaGUI lolaGUI) {
        super();
        this._lolaGUI = lolaGUI;
        setVisible(true);
        setup();
    }


    /**
     * Setup the general tab of the Lola GUI.
     * It offers the lola commands {@link de.renew.lola2.commands} to the user.
     */
    private void setup() {
        // A JTable, which can't be edited
        _taskTable = new JTable() {
            @Override
            public boolean isCellEditable(int row, int column) {
                return false;
            }
        };
        setupTaskTable();
        JScrollPane scrollPane = new JScrollPane(_taskTable);
        scrollPane.setBorder(BorderFactory.createEmptyBorder(10, 5, 5, 5));

        // Adding new Tasks
        final JTextField newTask = new JTextField(20);
        newTask.getDocument().addDocumentListener(new DocumentListener() {
            @Override
            public void removeUpdate(DocumentEvent e) {
                _newTaskText = newTask.getText();
            }

            @Override
            public void insertUpdate(DocumentEvent e) {
                _newTaskText = newTask.getText();
            }

            @Override
            public void changedUpdate(DocumentEvent e) {}
        });
        newTask.setToolTipText(
            "<html>Input new verification task here and click the add button.<br>"
                + "(some pointer on syntax should go here) <br>"
                + "<i>There is no syntax check so far.</i></html> ");
        JButton addButton = new JButton("Add task");
        addButton.setToolTipText("Add the entered task to the list");
        addButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                if (_newTaskText != "") {
                    _logger.info("[Lola GUI] Adding Task: " + _newTaskText);
                    if (!_newTaskText.toLowerCase().startsWith("formula")) {
                        _newTaskText = "FORMULA " + _newTaskText;
                    }
                    TextFigure tmpFig = new TextFigure(false);
                    tmpFig.setText(_newTaskText);
                    _lolaGUI._drawing.add(tmpFig);
                    _lolaGUI._drawing.checkDamage();
                    LolaTask tmpTask = new LolaTask(tmpFig, _lolaGUI._drawing);
                    Vector<Object> newRow = new Vector<Object>();
                    newRow.add(new IndirectLolaResult(LolaResultStatus.UNCHECKED));
                    newRow.add(tmpTask);
                    ((DefaultTableModel) _taskTable.getModel()).addRow(newRow);
                } else {
                    _logger.error("[Lola GUI] No text, no task to add.");
                }
            }
        });

        JPanel addPanel = new JPanel();
        addPanel.setLayout(new BoxLayout(addPanel, BoxLayout.X_AXIS));
        addPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 0, 5));
        addPanel.add(newTask);
        addPanel.add(Box.createHorizontalStrut(5));
        addPanel.add(addButton);

        /*
         * The button Panel includes buttons for updating and checking tasks
         */
        JButton updateButton = new JButton("Update Tasks");
        updateButton.setAlignmentX(CENTER_ALIGNMENT);
        updateButton.setToolTipText(
            "Parses the tasks in the current net drawing and displays them in the table.");
        updateButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                LolaFileCreator creator = new LolaFileCreator();
                Vector<LolaTask> tasks = creator.parseTasks(_lolaGUI._drawing);
                DefaultTableModel model = new DefaultTableModel();
                model.addColumn("task", tasks);
                model.addColumn("result", new Vector<LolaResult>());
                model.setColumnIdentifiers(TASK_COLUMN_NAMES);
                _taskTable.setModel(model);
                setupTaskTable();
            }
        });

        /*
         * Button and ActionListener for "check button"
         * Gets all LolaTask and call their check method.
         */
        JButton checkButton = new JButton("Check Tasks");
        checkButton.setAlignmentX(CENTER_ALIGNMENT);
        checkButton.setToolTipText("Checks the selected tasks and displays the result.");
        checkButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                for (int i = 0; i < _taskTable.getRowCount(); i++) {
                    LolaTask tmpTask = (LolaTask) _taskTable.getValueAt(i, 1);
                    _logger.info("[Lola TaskCheck] checking task " + tmpTask.toString());
                    LolaResult lolaResult = tmpTask.check(new LolaAnalyzer(_lolaGUI._lolaPath));
                    tmpTask.colorFigure();
                    _taskTable.setValueAt(lolaResult, i, 0);
                }
                _lolaGUI._drawing.checkDamage();
            }
        });

        JPanel buttonPanel = new JPanel();
        buttonPanel.setBorder(BorderFactory.createEmptyBorder(0, 5, 5, 5));
        buttonPanel.setLayout(new BoxLayout(buttonPanel, BoxLayout.X_AXIS));
        buttonPanel.add(Box.createHorizontalGlue());
        buttonPanel.add(updateButton);
        buttonPanel.add(Box.createHorizontalStrut(10));
        buttonPanel.add(checkButton);

        /*
             * Layouting the general Panel
             */
        setLayout(new BorderLayout());
        add(scrollPane, BorderLayout.CENTER);
        add(addPanel, BorderLayout.PAGE_START);
        add(buttonPanel, BorderLayout.PAGE_END);
    }

    /**
     * Do the setup of the taskTable:
     * <ul>
     * <li> parse the tasks from the current net drawing
     * <li> construct a new table model
     * <li> set this as the model of taskTable
     * <li> set width of columns, height of rows
     * <li> set Renderer for result column
     * </ul>
     * <p> This is done initially and everytime the "update tasks" button is clicked
     */
    private void setupTaskTable() {
        LolaFileCreator creator = new LolaFileCreator();
        if (_lolaGUI._drawing == null) {
            System.out.println("DRAWING IS NULL");
        }
        Vector<LolaTask> initialTasks = creator.parseTasks(_lolaGUI._drawing);

        // sort tasks by their position in the drawing (or by the string ordering of the text if the position is identical) 
        Collections.sort(initialTasks, new Comparator<LolaTask>() {
            @Override
            public int compare(LolaTask o1, LolaTask o2) {
                Rectangle r1 = o1.getFigure().displayBox();
                Rectangle r2 = o2.getFigure().displayBox();
                int result;
                if (r1.x == r2.x && r1.y == r2.y) {
                    // same position, sort by text ordering
                    result = o1.toString().compareTo(o2.toString());
                } else if (r1.y > r2.y || (r1.y == r2.y && r1.x > r2.x)) {
                    result = 1;
                } else {
                    result = -1;
                }
                return result;
            }
        });

        Vector<LolaResult> initialResults = new Vector<LolaResult>();
        for (int i = 0; i < initialTasks.size(); i++) {
            initialResults.add(new IndirectLolaResult(LolaResultStatus.UNCHECKED));
        }

        DefaultTableModel model = new DefaultTableModel();
        model.addColumn("result", initialResults);
        model.addColumn("task", initialTasks);
        model.setColumnIdentifiers(TASK_COLUMN_NAMES);

        _taskTable.setModel(model);
        _taskTable.setFillsViewportHeight(true);
        _taskTable.setRowHeight(20);
        _taskTable.setIntercellSpacing(new Dimension(4, 4));
        _taskTable.getColumnModel().getColumn(1).setPreferredWidth(350);
        _taskTable.getColumnModel().getColumn(1).setMinWidth(350);
        _taskTable.getColumnModel().getColumn(1).setCellRenderer(new DefaultTableCellRenderer());
        _taskTable.getColumnModel().getColumn(0).setMaxWidth(20);
        _taskTable.getColumnModel().getColumn(0).setMinWidth(20);
        _taskTable.getColumnModel().getColumn(0).setCellRenderer(new DefaultTableCellRenderer() {
            @Override
            public void setValue(Object o) {
                if (o instanceof LolaResult) {
                    LolaResult result = (LolaResult) o;
                    LolaResultStatus status = result.getStatus();
                    //                                    logger.info("[Lola GUI] Rendering result column, "
                    //                                                    + o + "!");
                    setBorder(BorderFactory.createLineBorder(Color.BLACK, 2));
                    setText(status.toString().substring(0, 1));

                    if (result instanceof DirectLolaResult) {
                        StringBuffer tip = new StringBuffer("<html>");
                        DirectLolaResult lolaResult = (DirectLolaResult) result;
                        String output = lolaResult.getError();
                        tip.append(output.replaceAll("\n", "\n<br>"));
                        tip.append("</html>");
                        setToolTipText(tip.toString());
                    } else {
                        setToolTipText("No Output available.");
                    }
                    Color color = LolaGUIHelper.getStatusColor(status);
                    setBackground(color);
                } else {
                    _logger.error("[Lola GUI] This should use other renderer.");
                    super.setValue(o);
                }
            }
        });
    }
}