package vismon.gui;

import java.awt.event.*;
import java.util.ArrayList;
import java.util.List;

import info.clearthought.layout.TableLayout;
import info.clearthought.layout.TableLayoutConstants;
import net.java.balloontip.BalloonTip;
import net.java.balloontip.styles.BalloonTipStyle;
import net.java.balloontip.styles.EdgedBalloonStyle;
import net.java.balloontip.utils.TimingUtils;
import vismon.component.DualSlider;
import vismon.component.IndicatorSlider;
import vismon.component.MonoSlider;
import vismon.data.Indicator;
import vismon.data.MngOption;
import vismon.data.Session;
import vismon.plot.IndicatorOverviewPlot;
import vismon.plot.ProbabilityPlot;
import vismon.util.Constants;
import vismon.util.Util;

import javax.swing.*;
import java.awt.*;

public class OverviewPanel extends JPanel {

    private final static int LINE_VIEW = 0;
    private final static int HIST_VIEW = 1;
    private final static int PROB_VIEW = 2;
    private final static int BOTH_VIEW = 3;

    public final static int PLUS_SIGN_WIDTH = 10;
    public final static int TEXTFIELD_WIDTH = 60;
    //public final static int SLIDER_WIDTH = 50;

    public final static int LABEL_HEIGHT = 30;
    public final static int SLIDER_HEIGHT = 30;
    public final static int HIST_PLOT_HEIGHT = 30;
    public final static int PROB_EQUA_HEIGHT = 30;
    public final static int PROB_PLOT_HEIGHT = 30;
    public final static int SLIDER_PANEL_HEIGHT = LABEL_HEIGHT + SLIDER_HEIGHT;
    public final static int PROB_PANEL_HEIGHT = PROB_PLOT_HEIGHT + SLIDER_HEIGHT;

    public final static int PDF = 0;
    public final static int CDF = 1;

    private JPanel mainPanel;
    private JPanel mngPanel;
    private JPanel indPanel;
    private JPanel indSliderPanel;
    private JScrollPane southScrollPane;
    private double southScrollBarCurrentRelativeValue;
    private boolean keepSouthScrollBarLocation;

    private List<JPanel> indMainPanelList;
    private List<JPanel> indHistPanelList;
    private List<JPanel> indEquaPanelList;
    private List<JPanel> indProbPanelList;

    private List<JTextField> indMinTextFieldList;
    private List<JTextField> indMaxTextFieldList;
    private List<JTextField> logPlotTextFieldList;
    private List<JTextField> indBoundaryTextFieldList;
    private List<JTextField> probTextFieldList;

    private List<IndicatorSlider> indSliderList;
    private List<MonoSlider> probSliderList;

    private List<ProbabilityPlot> probPlotList;

    private double[][] indLineLayout;
    private double[][] indHistLayout;
    private double[][] indProbLayout;
    private double[][] indBothLayout;

    private int sliderView = LINE_VIEW;
    private static int densityFunc = PDF;

    private List<Indicator> selectedIndicators;

    private int createPlotClickCount = 0;

    public OverviewPanel() {
        super();

        indMainPanelList = new ArrayList<JPanel>();
        indHistPanelList = new ArrayList<JPanel>();
        indEquaPanelList = new ArrayList<JPanel>();
        indProbPanelList = new ArrayList<JPanel>();

        indMinTextFieldList = new ArrayList<JTextField>();
        indMaxTextFieldList = new ArrayList<JTextField>();
        logPlotTextFieldList = new ArrayList<JTextField>();
        indBoundaryTextFieldList = new ArrayList<JTextField>();
        probTextFieldList = new ArrayList<JTextField>();


        indSliderList = new ArrayList<IndicatorSlider>();
        probSliderList = new ArrayList<MonoSlider>();

        probPlotList = new ArrayList<ProbabilityPlot>();

        selectedIndicators = new ArrayList<Indicator>();

        keepSouthScrollBarLocation = false;

        init();
    }

    protected void init() {
        mainPanel = new JPanel();
        double mainLayout[][] = {{TableLayoutConstants.FILL},           // COLUMNS
                {25, TableLayoutConstants.FILL}};       // ROWS
        mainPanel.setLayout(new TableLayout(mainLayout));

        addTopButtons();
        addTabbedPane();

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

    protected void createMngTabLayouts() {
        double mngLayout[][] = new double[2][];
        mngLayout[0] = new double[]{TableLayoutConstants.FILL};         // COLUMNS
        mngLayout[1] = new double[Session.getMngOptionNum() + 1];       // ROWS
        mngLayout[1][0] = LABEL_HEIGHT;
        for (int i = 1; i <= Session.getMngOptionNum(); ++i)
            mngLayout[1][i] = SLIDER_PANEL_HEIGHT;

        mngPanel.setLayout(new TableLayout(mngLayout));
    }

    public void createIndPanelLayouts() {
        indLineLayout = new double[2][];
        indLineLayout[0] = new double[]{TableLayoutConstants.FILL};         // COLUMNS
        indLineLayout[1] = new double[Session.getIndicatorNum() + 1];       // ROWS
        indLineLayout[1][0] = LABEL_HEIGHT;
        for (int i = 0; i < Session.getIndicatorNum(); ++i) {
            indLineLayout[1][i + 1] = SLIDER_PANEL_HEIGHT;//50;
        }

        indHistLayout = new double[2][];
        indHistLayout[0] = new double[]{TableLayoutConstants.FILL};         // COLUMNS
        indHistLayout[1] = new double[2 * Session.getIndicatorNum() + 1];   // ROWS
        indHistLayout[1][0] = LABEL_HEIGHT;
        for (int i = 0; i < Session.getIndicatorNum(); ++i) {
            indHistLayout[1][2 * i + 1] = SLIDER_PANEL_HEIGHT;
            indHistLayout[1][2 * i + 2] = HIST_PLOT_HEIGHT;
        }

        indProbLayout = new double[2][];
        indProbLayout[0] = new double[]{TableLayoutConstants.FILL};         // COLUMNS
        indProbLayout[1] = new double[3 * Session.getIndicatorNum() + 1];   // ROWS
        indProbLayout[1][0] = LABEL_HEIGHT;
        for (int i = 0; i < Session.getIndicatorNum(); ++i) {
            indProbLayout[1][3 * i + 1] = SLIDER_PANEL_HEIGHT;
            indProbLayout[1][3 * i + 2] = PROB_EQUA_HEIGHT;
            indProbLayout[1][3 * i + 3] = PROB_PANEL_HEIGHT;
        }

        indBothLayout = new double[2][];
        indBothLayout[0] = new double[]{TableLayoutConstants.FILL};         // COLUMNS
        indBothLayout[1] = new double[4 * Session.getIndicatorNum() + 1];   // ROWS
        indBothLayout[1][0] = LABEL_HEIGHT;
        for (int i = 0; i < Session.getIndicatorNum(); ++i) {
            indBothLayout[1][4 * i + 1] = SLIDER_PANEL_HEIGHT;
            indBothLayout[1][4 * i + 2] = HIST_PLOT_HEIGHT;
            indBothLayout[1][4 * i + 3] = PROB_EQUA_HEIGHT;
            indBothLayout[1][4 * i + 4] = PROB_PANEL_HEIGHT;
        }

    }

    private void setIndSliderPanelLayout() {
        if (sliderView == LINE_VIEW)
            indSliderPanel.setLayout(new TableLayout(indLineLayout));
        else if (sliderView == HIST_VIEW)
            indSliderPanel.setLayout(new TableLayout(indHistLayout));
        else if (sliderView == PROB_VIEW)
            indSliderPanel.setLayout(new TableLayout(indProbLayout));
        else
            indSliderPanel.setLayout(new TableLayout(indBothLayout));
    }

    private void addTopButtons() {
        JPanel northPanel = new JPanel();
        double northLayout[][] = {{180, 150, TableLayoutConstants.FILL, 150},           // COLUMNS
                {TableLayoutConstants.FILL}};                        // ROWS
        northPanel.setLayout(new TableLayout(northLayout));

        final JButton createPlotButton = new JButton("Create Single Plot \u25BC");     // SOLID DOWN TRIANGLE
        createPlotButton.setSize(25, 20);
        /*createPlotButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent actionEvent) {
                createSingleContourPlot();
            }
        });*/

        //Create the plot type plotTypePopup menu.
        final JPopupMenu plotTypePopup = new JPopupMenu();
        JMenuItem createContourPlotMenuItem = new JMenuItem("Create a single contour plot");
        createContourPlotMenuItem.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent actionEvent) {
                createSingleContourPlot();
            }
        });
        plotTypePopup.add(createContourPlotMenuItem);
        JMenuItem createScatterPlotMenuItem = new JMenuItem("Create a single scatter plot");
        createScatterPlotMenuItem.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent actionEvent) {
                createSingleScatterPlot();
            }
        });
        plotTypePopup.add(createScatterPlotMenuItem);
        createPlotButton.addMouseListener(new MouseAdapter() {
            public void mousePressed(MouseEvent e) {
                plotTypePopup.show(e.getComponent(), 0, createPlotButton.getHeight());//e.getX(), e.getY());

                if (createPlotClickCount % 2 == 0)
                    plotTypePopup.setVisible(true);
                else
                    plotTypePopup.setVisible(false);

                ++createPlotClickCount;
            }
        });


        //createPlotButton.setToolTipText("Select an indicator, by left-clicking on its name, and press this button to create a contour plot.");
        createPlotButton.setToolTipText("Click to select the type of plot you want to create.");
        northPanel.add(createPlotButton, "0,0");

        final JButton deleteScenariosButton = new JButton("Delete Scenarios");
        deleteScenariosButton.setSize(25, 20);
        deleteScenariosButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent actionEvent) {
                //createSingleScatterPlot();
                Vismon.getVismonInstance().getScenarioPanel().removeAllScenarios();
            }
        });
        deleteScenariosButton.setToolTipText("Delete all created scenarios");
        northPanel.add(deleteScenariosButton, "1,0");

        northPanel.add(new JLabel(" "), "2,0");

        final JButton resetButton = new JButton("Clear Constraints");
        resetButton.setSize(25, 20);
        resetButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent actionEvent) {
                clearConstraints();
            }
        });
        northPanel.add(resetButton, "3,0");

        mainPanel.add(northPanel, "0,0");
    }

    private void addTabbedPane() {
        mngPanel = new JPanel();
        mngPanel.setBackground(Color.WHITE);
        JScrollPane mngScrollPane = new JScrollPane(mngPanel, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
                JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
        mngScrollPane.setBorder(BorderFactory.createEmptyBorder());

        indPanel = new JPanel();
        indPanel.setBackground(Color.WHITE);
        addIndTopGUIElements();

        JTabbedPane tabbedPane = new JTabbedPane();
        tabbedPane.addTab("Management Options", mngScrollPane);
        tabbedPane.addTab("Indicators", indPanel);
        tabbedPane.setSelectedIndex(1);

        mainPanel.add(tabbedPane, "0,1");
    }

    private void addIndTopGUIElements() {
        double indLayout[][] = {{TableLayoutConstants.FILL},           // COLUMNS
                {LABEL_HEIGHT, TableLayoutConstants.FILL}};                        // ROWS
        indPanel.setLayout(new TableLayout(indLayout));

        // NORTH PANEL AND ITS LABELS AND COMBOBOXES
        JPanel northPanel = new JPanel();
        northPanel.setSize(new Dimension(indPanel.getWidth(), indPanel.getHeight()));
        indPanel.add(northPanel, "0,0");

        double northLayout[][] = {{80, TableLayoutConstants.FILL, 120, TableLayoutConstants.FILL},           // COLUMNS
                {TableLayoutConstants.FILL}};                        // ROWS
        northPanel.setLayout(new TableLayout(northLayout));

        JLabel sliderViweLabel = new JLabel(" Slider View ");
        northPanel.add(sliderViweLabel, "0,0");

        addSliderViewComboBox(northPanel, 1);

        JLabel densityFuncLabel = new JLabel(" Density Function ");
        northPanel.add(densityFuncLabel, "2,0");

        addDensityFuncComboBox(northPanel, 3);

        // SOUTH PANEL AND INDICATOR SLIDERS AND TEXTFIELDS
        indSliderPanel = new JPanel();
        indSliderPanel.setBackground(Color.WHITE);
        southScrollPane = new JScrollPane(indSliderPanel, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
                JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
        southScrollPane.setBorder(BorderFactory.createEmptyBorder());
        indPanel.add(southScrollPane, "0,1");

        final JScrollBar southScrollBar = southScrollPane.getVerticalScrollBar();
        southScrollBar.addAdjustmentListener(new AdjustmentListener() {
            public void adjustmentValueChanged(AdjustmentEvent adjustmentEvent) {
                if (keepSouthScrollBarLocation) {
                    southScrollBar.setValue((int) (southScrollBarCurrentRelativeValue * southScrollBar.getMaximum()));
                    keepSouthScrollBarLocation = false;
                }
            }
        });
    }

    private void addSliderViewComboBox(JPanel panel, int colNumber) {
        String[] views = new String[]{"Line", "MC Trials", "Probabilistic Objectives", "Both"};

        final JComboBox viewsComboBox = new JComboBox(views);
        viewsComboBox.setSelectedIndex(sliderView);
        viewsComboBox.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent actionEvent) {
                sliderView = viewsComboBox.getSelectedIndex();
                indSliderPanel.removeAll();
                addIndicatorGUIs();

                keepSouthScrollBarLocation();
                Vismon.getVismonInstance().repaintOverviewPanel();
            }
        });
        panel.add(viewsComboBox, colNumber + ",0");
    }

    private void addDensityFuncComboBox(JPanel panel, int colNumber) {
        String[] funcs = new String[]{"Probability", "Cumulative"};

        final JComboBox funcsComboBox = new JComboBox(funcs);
        funcsComboBox.setSelectedIndex(densityFunc);
        funcsComboBox.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent actionEvent) {
                densityFunc = funcsComboBox.getSelectedIndex();
                Vismon.getVismonInstance().repaintOverviewPanel();
            }
        });
        panel.add(funcsComboBox, colNumber + ",0");
    }

    public void addMngOptionDualSliders() {
        createMngTabLayouts();

        // HEADER
        JPanel headerPanel = new JPanel();
        headerPanel.setBackground(Color.WHITE);
        double headerLayout[][] = {{TEXTFIELD_WIDTH, TableLayoutConstants.FILL, TEXTFIELD_WIDTH},           // COLUMNS
                {TableLayoutConstants.FILL}};                  // ROWS
        headerPanel.setLayout(new TableLayout(headerLayout));

        JLabel minLabel = new JLabel("Min", SwingConstants.CENTER);
        minLabel.setFont(Constants.OVERVIEW_FONT);
        minLabel.setForeground(Constants.MAIN_COLOR);
        headerPanel.add(minLabel, "0,0");

        JLabel blankLabel = new JLabel(" ");
        headerPanel.add(blankLabel, "1,0");

        JLabel maxLabel = new JLabel("Max", SwingConstants.CENTER);
        maxLabel.setFont(Constants.OVERVIEW_FONT);
        maxLabel.setForeground(Constants.MAIN_COLOR);
        headerPanel.add(maxLabel, "2,0");

        mngPanel.add(headerPanel, "0,0");

        // MANAGEMENT OPTION GUI ELEMENTS
        for (int i = 0; i < Session.getMngOptionNum(); ++i) {
            final MngOption ithMngOption = Session.getMngOption(i);

            Color bgColor = Color.WHITE;
            if (i % 2 == 1)
                bgColor = Constants.OVERVIEW_SEPARATION_BG_COLOR;

            JPanel mainPanel = new JPanel();
            mainPanel.setBackground(bgColor);
            double mainPanelLayout[][] = {{TEXTFIELD_WIDTH, TableLayoutConstants.FILL, TEXTFIELD_WIDTH},      // COLUMNS
                    {0.5, 0.5}};                                 // ROWS
            mainPanel.setLayout(new TableLayout(mainPanelLayout));

            mainPanel.add(blankLabel, "0,0");

            JLabel nameLabel = new JLabel(ithMngOption.getName());
            nameLabel.setFont(Constants.OVERVIEW_TITLE_FONT);
            nameLabel.setForeground(Constants.MAIN_COLOR);
            mainPanel.add(nameLabel, "1,0");

            mainPanel.add(blankLabel, "2,0");

            final JTextField minTextField = new JTextField(getBestFormat(ithMngOption.getMinConstraint()));
            minTextField.setBackground(mainPanel.getBackground());
            minTextField.setFont(Constants.OVERVIEW_FONT);
            minTextField.setForeground(Constants.MAIN_COLOR);
            minTextField.setHorizontalAlignment(JTextField.CENTER);
            mainPanel.add(minTextField, "0,1");

            final DualSlider dualSlider = new DualSlider(ithMngOption.getMin(), ithMngOption.getMax(),
                    ithMngOption.getMin(), ithMngOption.getMax(),
                    /*mainPanel.getWidth() - 100*/50, 30);
            dualSlider.setMngOption(ithMngOption);
            dualSlider.setBGColor(mainPanel.getBackground());
            mainPanel.add(dualSlider, "1,1");

            final JTextField maxTextField = new JTextField(getBestFormat(ithMngOption.getMaxConstraint()));
            maxTextField.setBackground(mainPanel.getBackground());
            maxTextField.setFont(Constants.OVERVIEW_FONT);
            maxTextField.setForeground(Constants.MAIN_COLOR);
            maxTextField.setHorizontalAlignment(JTextField.CENTER);
            mainPanel.add(maxTextField, "2,1");

            mngPanel.add(mainPanel, "0," + (i + 1));

            /***************************************
             LISTENERS
             ***************************************/
            minTextField.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent actionEvent) {
                    double minConstraint = Double.parseDouble(minTextField.getText());

                    ithMngOption.setMinConstraint(minConstraint);
                    dualSlider.setLowValue(minConstraint);

                    Vismon.getVismonInstance().repaintOverviewPanel();
                    Vismon.getVismonInstance().repaintCplomPanel();
                }
            });

            maxTextField.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent actionEvent) {
                    double maxConstraint = Double.parseDouble(maxTextField.getText());

                    ithMngOption.setMaxConstraint(maxConstraint);
                    dualSlider.setHighValue(maxConstraint);

                    Vismon.getVismonInstance().repaintOverviewPanel();
                    Vismon.getVismonInstance().repaintCplomPanel();
                }
            });

            dualSlider.addMouseMotionListener(new MouseMotionListener() {
                public void mouseDragged(MouseEvent mouseEvent) {
                    ithMngOption.setMinConstraint(dualSlider.getLowValue());
                    ithMngOption.setMaxConstraint(dualSlider.getHighValue());

                    minTextField.setText(getBestFormat(ithMngOption.getMinConstraint()));
                    maxTextField.setText(getBestFormat(ithMngOption.getMaxConstraint()));

                    Vismon.getVismonInstance().repaintOverviewPanel();
                    Vismon.getVismonInstance().repaintCplomPanel();
                }

                public void mouseMoved(MouseEvent mouseEvent) {

                }
            });

            dualSlider.addMouseListener(new MouseListener() {
                public void mouseClicked(MouseEvent mouseEvent) {
                    ithMngOption.setMinConstraint(dualSlider.getLowValue());
                    ithMngOption.setMaxConstraint(dualSlider.getHighValue());

                    double minConstraint = ithMngOption.getMinConstraint();
                    double maxConstraint = ithMngOption.getMaxConstraint();

                    minTextField.setText(getBestFormat(minConstraint));
                    maxTextField.setText(getBestFormat(maxConstraint));

                    Vismon.getVismonInstance().repaintOverviewPanel();
                    Vismon.getVismonInstance().repaintCplomPanel();
                }

                public void mousePressed(MouseEvent mouseEvent) {
                }

                public void mouseReleased(MouseEvent mouseEvent) {
                }

                public void mouseEntered(MouseEvent mouseEvent) {
                }

                public void mouseExited(MouseEvent mouseEvent) {
                }
            });

        }
    }

    public void addIndicatorGUIs() {
        setIndSliderPanelLayout();

        // HEADER
        JPanel headerPanel = new JPanel();
        headerPanel.setBackground(Color.WHITE);
        double headerLayout[][] = {{PLUS_SIGN_WIDTH, TEXTFIELD_WIDTH, TableLayoutConstants.FILL, TEXTFIELD_WIDTH},       // COLUMNS
                {TableLayoutConstants.FILL}};                  // ROWS
        headerPanel.setLayout(new TableLayout(headerLayout));

        JLabel blankLabel = new JLabel(" ");
        headerPanel.add(blankLabel, "0,0");

        JLabel minLabel = new JLabel("Min", SwingConstants.CENTER);
        minLabel.setFont(Constants.OVERVIEW_FONT);
        minLabel.setForeground(Constants.MAIN_COLOR);
        headerPanel.add(minLabel, "1,0");

        headerPanel.add(blankLabel, "2,0");

        JLabel maxLabel = new JLabel("Max", SwingConstants.CENTER);
        maxLabel.setFont(Constants.OVERVIEW_FONT);
        maxLabel.setForeground(Constants.MAIN_COLOR);
        headerPanel.add(maxLabel, "3,0");

        indSliderPanel.add(headerPanel, "0,0");

        addIndSubPanels();
    }

    private void addIndSubPanels() {
        if (sliderView == LINE_VIEW) {
            for (int i = 0; i < Session.getIndicatorNum(); ++i)
                indSliderPanel.add(indMainPanelList.get(i), "0," + (i + 1));
        } else if (sliderView == HIST_VIEW) {
            for (int i = 0; i < Session.getIndicatorNum(); ++i) {
                indSliderPanel.add(indMainPanelList.get(i), "0," + (2 * i + 1));
                indSliderPanel.add(indHistPanelList.get(i), "0," + (2 * i + 2));
            }
        } else if (sliderView == PROB_VIEW) {
            for (int i = 0; i < Session.getIndicatorNum(); ++i) {
                indSliderPanel.add(indMainPanelList.get(i), "0," + (3 * i + 1));
                indSliderPanel.add(indEquaPanelList.get(i), "0," + (3 * i + 2));
                indSliderPanel.add(indProbPanelList.get(i), "0," + (3 * i + 3));
            }
        } else {
            for (int i = 0; i < Session.getIndicatorNum(); ++i) {
                indSliderPanel.add(indMainPanelList.get(i), "0," + (4 * i + 1));
                indSliderPanel.add(indHistPanelList.get(i), "0," + (4 * i + 2));
                indSliderPanel.add(indEquaPanelList.get(i), "0," + (4 * i + 3));
                indSliderPanel.add(indProbPanelList.get(i), "0," + (4 * i + 4));
            }
        }
    }

    public void createIndSubPanels() {
        JLabel blankLabel = new JLabel(" ");
        for (int i = 0; i < Session.getIndicatorNum(); ++i) {
            final Indicator ithIndicator = Session.getIndicator(i);

            Color bgColor = Color.WHITE;
            if (i % 2 == 1)
                bgColor = Constants.OVERVIEW_SEPARATION_BG_COLOR;

            final JPanel mainPanel = new JPanel();
            mainPanel.setBackground(bgColor);
            double mainPanelLayout[][] = {{PLUS_SIGN_WIDTH, TEXTFIELD_WIDTH, TableLayoutConstants.FILL, TEXTFIELD_WIDTH},      // COLUMNS
                    {0.5, 0.5}};                                 // ROWS
            mainPanel.setLayout(new TableLayout(mainPanelLayout));
            indMainPanelList.add(mainPanel);

            mainPanel.add(blankLabel, "0,0");

            mainPanel.add(blankLabel, "1,0");

            String title = ithIndicator.getName();
            if (!ithIndicator.getUnit().equals(Constants.NO_UNIT))
                title += " (" + ithIndicator.getUnit() + ")";
            JLabel titleLabel = new JLabel(title);
            titleLabel.setFont(Constants.OVERVIEW_TITLE_FONT);
            titleLabel.setForeground(Constants.MAIN_COLOR);
            mainPanel.add(titleLabel, "2,0");

            mainPanel.add(blankLabel, "3,0");

            mainPanel.add(blankLabel, "0,1");

            final JTextField minTextField = new JTextField("");
            if (ithIndicator.isMinBest()) {
                minTextField.setText("Best");
                minTextField.setBorder(BorderFactory.createEmptyBorder());
                minTextField.setEditable(false);
            } else {
                minTextField.setText(getBestFormat(ithIndicator.getConstraintValue()));
            }
            minTextField.setBackground(bgColor);
            minTextField.setFont(Constants.OVERVIEW_FONT);
            minTextField.setForeground(Constants.MAIN_COLOR);
            minTextField.setHorizontalAlignment(JTextField.CENTER);
            indMinTextFieldList.add(minTextField);
            mainPanel.add(minTextField, "1,1");

            final IndicatorSlider indSlider = new IndicatorSlider(ithIndicator.getMin(), ithIndicator.getMax(),
                    ithIndicator.isMinBest(),
                    /*mainPanel.getWidth() - 130*/50, 30);
            //TODO
            indSlider.setBGColor(bgColor);
            indSlider.setIndicator(ithIndicator);
            indSliderList.add(indSlider);
            mainPanel.add(indSlider, "2,1");

            final JTextField maxTextField = new JTextField("");
            if (ithIndicator.isMaxBest()) {
                maxTextField.setText("Best");
                maxTextField.setBorder(BorderFactory.createEmptyBorder());
                maxTextField.setEditable(false);
            } else {
                maxTextField.setText(getBestFormat(ithIndicator.getConstraintValue()));
            }
            maxTextField.setBackground(bgColor);
            maxTextField.setFont(Constants.OVERVIEW_FONT);
            maxTextField.setForeground(Constants.MAIN_COLOR);
            maxTextField.setHorizontalAlignment(JTextField.CENTER);
            indMaxTextFieldList.add(maxTextField);
            mainPanel.add(maxTextField, "3,1");

            /*
                HISTO_PANEL
             */
            JPanel histoPanel = new JPanel();
            histoPanel.setBackground(bgColor);
            double histoPanelLayout[][] = {{PLUS_SIGN_WIDTH, TEXTFIELD_WIDTH, TableLayoutConstants.FILL, TEXTFIELD_WIDTH},      // COLUMNS
                    {TableLayoutConstants.FILL}};                         // ROWS
            histoPanel.setLayout(new TableLayout(histoPanelLayout));

            histoPanel.add(blankLabel, "0,0");

            JTextField logPlotTextField = new JTextField("");
            logPlotTextField.setEditable(false);
            logPlotTextField.setBorder(BorderFactory.createEmptyBorder());
            logPlotTextField.setBackground(bgColor);
            logPlotTextField.setFont(Constants.OVERVIEW_FONT);
            logPlotTextField.setForeground(Constants.MAIN_COLOR);
            logPlotTextField.setHorizontalAlignment(JTextField.RIGHT);
            logPlotTextFieldList.add(logPlotTextField);
            histoPanel.add(logPlotTextField, "1,0");

            final IndicatorOverviewPlot histoPlotPanel = new IndicatorOverviewPlot(ithIndicator);
            histoPanel.add(histoPlotPanel, "2,0");

            histoPanel.add(blankLabel, "3,0");

            indHistPanelList.add(histoPanel);


            /*
                EQUA_PANEL
             */
            JPanel equaPanel = new JPanel();
            equaPanel.setBackground(bgColor);
            double equaPanelLayout[][] = {{80, 60, TableLayoutConstants.FILL, 10, TEXTFIELD_WIDTH},      // COLUMNS
                    {TableLayoutConstants.FILL}};                                 // ROWS
            equaPanel.setLayout(new TableLayout(equaPanelLayout));

            JLabel text1Label = new JLabel("Prob " + Constants.GR_EQUAL, SwingConstants.RIGHT);
            text1Label.setBackground(bgColor);
            text1Label.setForeground(Constants.MAIN_COLOR);
            equaPanel.add(text1Label, "0,0");

            final JTextField probTextField = new JTextField(getBestFormat(ithIndicator.getProbabilityValue()));
            probTextField.setBackground(bgColor);
            probTextField.setForeground(Constants.MAIN_COLOR);
            probTextFieldList.add(probTextField);
            equaPanel.add(probTextField, "1,0");

            JLabel text2Label = new JLabel("", SwingConstants.LEFT);
            text2Label.setText(" that \"" + ithIndicator.getShortName() + "\" is ");
            text2Label.setBackground(bgColor);
            text2Label.setForeground(Constants.MAIN_COLOR);
            equaPanel.add(text2Label, "2,0");

            JLabel signLabel = new JLabel("", SwingConstants.RIGHT);
            if (ithIndicator.isMaxBest())
                signLabel.setText(Constants.GR_EQUAL);
            else
                signLabel.setText(Constants.LS_EQUAL);
            signLabel.setBackground(bgColor);
            signLabel.setForeground(Constants.MAIN_COLOR);
            equaPanel.add(signLabel, "3,0");

            final JTextField boundaryTextField = new JTextField(getBestFormat(ithIndicator.getConstraintValue()));
            boundaryTextField.setBackground(bgColor);
            boundaryTextField.setForeground(Constants.MAIN_COLOR);
            indBoundaryTextFieldList.add(boundaryTextField);
            equaPanel.add(boundaryTextField, "4,0");

            indEquaPanelList.add(equaPanel);

            /*
                PROB_PANEL
             */
            JPanel probPanel = new JPanel();
            probPanel.setBackground(bgColor);
            double probPanelLayout[][] = {{PLUS_SIGN_WIDTH, TEXTFIELD_WIDTH, TableLayoutConstants.FILL, TEXTFIELD_WIDTH},      // COLUMNS
                    {PROB_PLOT_HEIGHT, SLIDER_HEIGHT}};                                 // ROWS
            probPanel.setLayout(new TableLayout(probPanelLayout));

            probPanel.add(blankLabel, "0,0");

            probPanel.add(blankLabel, "1,0");

            final ProbabilityPlot probPlotPanel = new ProbabilityPlot(ithIndicator);
            probPlotPanel.calcFullfilments();

            probPlotList.add(probPlotPanel);
            probPanel.add(probPlotPanel, "2,0");

            probPanel.add(blankLabel, "3,0");

            probPanel.add(blankLabel, "0,1");

            probPanel.add(blankLabel, "1,1");

            final MonoSlider probSlider = new MonoSlider(0, 1.0, false, /*probPanel.getWidth() - 130*/50, 30);
            probSlider.setBGColor(bgColor);
            probSliderList.add(probSlider);
            probPanel.add(probSlider, "2,1");

            probPanel.add(blankLabel, "3,1");

            indProbPanelList.add(probPanel);


            /*********************************************
             LISTENERS
             *********************************************/
            titleLabel.addMouseListener(new MouseListener() {
                public void mouseClicked(MouseEvent mouseEvent) {
                    if (mouseEvent.getButton() == MouseEvent.BUTTON1)
                        indicatorSelectionAction(ithIndicator);
                }

                public void mousePressed(MouseEvent mouseEvent) {
                }

                public void mouseReleased(MouseEvent mouseEvent) {
                }

                public void mouseEntered(MouseEvent mouseEvent) {
                }

                public void mouseExited(MouseEvent mouseEvent) {
                }
            });

            minTextField.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent actionEvent) {
                    if (ithIndicator.isMinBest())
                        return;

                    String text = minTextField.getText();
                    minTextFieldListenerAction(text, minTextField, mainPanel,
                            ithIndicator, indSlider, boundaryTextField, probPlotPanel);
                }
            });

            minTextField.addKeyListener(new KeyListener() {
                public void keyTyped(KeyEvent keyEvent) {
                    if (keyEvent.getKeyCode() == KeyEvent.VK_ENTER)
                        return;

                    String text = minTextField.getText() + keyEvent.getKeyChar();
                    minTextFieldListenerAction(text, minTextField, mainPanel,
                            ithIndicator, indSlider, boundaryTextField, probPlotPanel);
                }

                public void keyPressed(KeyEvent keyEvent) {
                }

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

            maxTextField.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent actionEvent) {
                    if (ithIndicator.isMaxBest())
                        return;

                    String text = maxTextField.getText();
                    maxTextFieldListenerAction(text, maxTextField, mainPanel,
                            ithIndicator, indSlider, boundaryTextField, probPlotPanel);
                }
            });

            maxTextField.addKeyListener(new KeyListener() {
                public void keyTyped(KeyEvent keyEvent) {
                    if (keyEvent.getKeyCode() == KeyEvent.VK_ENTER)
                        return;

                    String text = maxTextField.getText() + keyEvent.getKeyChar();
                    maxTextFieldListenerAction(text, maxTextField, mainPanel,
                            ithIndicator, indSlider, boundaryTextField, probPlotPanel);
                }

                public void keyPressed(KeyEvent keyEvent) {
                }

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

            indSlider.addMouseMotionListener(new MouseMotionListener() {
                public void mouseDragged(MouseEvent mouseEvent) {
                    double constraintValue = indSlider.getValue();
                    String constraintValueString = getBestFormat(constraintValue);
                    if (ithIndicator.isMinBest())
                        maxTextField.setText(constraintValueString);
                    else
                        minTextField.setText(constraintValueString);
                    boundaryTextField.setText(constraintValueString);

                    probPlotPanel.calcFullfilments();

                    Vismon.getVismonInstance().updatePlots();
                }

                public void mouseMoved(MouseEvent mouseEvent) {
                }
            });

            indSlider.addMouseListener(new MouseListener() {
                public void mouseClicked(MouseEvent mouseEvent) {
                    if (mouseEvent.getClickCount() == 2) {
                        String constraintValueString = getBestFormat(ithIndicator.getConstraintValue());
                        if (ithIndicator.isMinBest())
                            maxTextField.setText(constraintValueString);
                        else
                            minTextField.setText(constraintValueString);

                        probPlotPanel.calcFullfilments();

                        Vismon.getVismonInstance().updatePlots();
                    }
                    setLogPlotLabel();
                }

                public void mousePressed(MouseEvent mouseEvent) {
                }

                public void mouseReleased(MouseEvent mouseEvent) {
                }

                public void mouseEntered(MouseEvent mouseEvent) {
                }

                public void mouseExited(MouseEvent mouseEvent) {
                }
            });

            boundaryTextField.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent actionEvent) {
                    String text = boundaryTextField.getText();

                    boundaryTextFieldListenerAction(text, ithIndicator, boundaryTextField, mainPanel,
                                                    indSlider, minTextField, maxTextField, probPlotPanel);
                }
            });

            boundaryTextField.addKeyListener(new KeyListener() {
                public void keyTyped(KeyEvent keyEvent) {
                    if (keyEvent.getKeyCode() == KeyEvent.VK_ENTER)
                        return;

                    String text = boundaryTextField.getText() + keyEvent.getKeyChar();
                    boundaryTextFieldListenerAction(text, ithIndicator, boundaryTextField, mainPanel,
                            indSlider, minTextField, maxTextField, probPlotPanel);
                }

                public void keyPressed(KeyEvent keyEvent) {
                }

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

            probTextField.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent actionEvent) {
                    String text = probTextField.getText();
                    probTextFieldListenerAction(text, probTextField, mainPanel, ithIndicator, probSlider);
                }
            });

            probTextField.addKeyListener(new KeyListener() {
                public void keyTyped(KeyEvent keyEvent) {
                    if (keyEvent.getKeyCode() == KeyEvent.VK_ENTER)
                        return;

                    String text = probTextField.getText();
                    probTextFieldListenerAction(text, probTextField, mainPanel, ithIndicator, probSlider);
                }

                public void keyPressed(KeyEvent keyEvent) {
                }

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

            probSlider.addMouseMotionListener(new MouseMotionListener() {
                public void mouseDragged(MouseEvent mouseEvent) {
                    double probValue = probSlider.getValue();

                    probTextField.setText(getBestFormat(probValue));
                    ithIndicator.setProbabilityValue(probValue);

                    Vismon.getVismonInstance().updatePlots();
                }

                public void mouseMoved(MouseEvent mouseEvent) {
                }
            });

            histoPlotPanel.addMouseMotionListener(new MouseMotionListener() {
                public void mouseDragged(MouseEvent mouseEvent) {
                    //To change body of implemented methods use File | Settings | File Templates.
                }

                public void mouseMoved(MouseEvent mouseEvent) {
                    histoPlotPanel.mouseMove(mouseEvent.getX(), mouseEvent.getY());
                }
            });

            probPlotPanel.addMouseMotionListener(new MouseMotionListener() {
                public void mouseDragged(MouseEvent mouseEvent) {
                }

                public void mouseMoved(MouseEvent mouseEvent) {
                    probPlotPanel.mouseMove(mouseEvent.getX(), mouseEvent.getY());
                }
            });

        }
    }

    private void probTextFieldListenerAction(String text, JTextField probTextField, JPanel panel, Indicator indicator, MonoSlider probSlider) {
        double probValue;
        try {
            probValue = Double.parseDouble(text);
            probTextField.setBackground(panel.getBackground());
        } catch (NumberFormatException e) {
            probTextField.setBackground(Constants.BAD_INPUT_BG_COLOR);
            showBallonTip(probTextField, "Enter a valid number", new ImageIcon("images/remove2.png"));
            return;
        }
        if (probValue < 0 || probValue > 1) {
            probTextField.setBackground(Constants.BAD_INPUT_BG_COLOR);
            showBallonTip(probTextField, "Enter a number between 0 and 1", new ImageIcon("images/remove2.png"));
            return;
        }

        indicator.setProbabilityValue(probValue);
        probSlider.setValue(probValue);

        Vismon.getVismonInstance().updatePlots();
    }

    private void minTextFieldListenerAction(String text, JTextField minTextField, JPanel mainPanel,
                                            Indicator indicator, IndicatorSlider indSlider,
                                            JTextField boundaryTextField, ProbabilityPlot probPlotPanel) {
        double constraintValue;
        try {
            constraintValue = Double.parseDouble(text);
            minTextField.setBackground(mainPanel.getBackground());
        } catch (NumberFormatException e) {
            minTextField.setBackground(Constants.BAD_INPUT_BG_COLOR);
            showBallonTip(minTextField, "Enter a valid number", new ImageIcon("images/remove2.png"));
            return;
        }
        if (constraintValue < indicator.getMin() || constraintValue > indicator.getMax()) {
            minTextField.setBackground(Constants.BAD_INPUT_BG_COLOR);
            showBallonTip(minTextField, "Enter a number in the range", new ImageIcon("images/remove2.png"));
            return;
        }

        String constraintValueString = getBestFormat(constraintValue);

        indicator.setConstraintValue(constraintValue);
        indSlider.setValue(constraintValue);
        boundaryTextField.setText(constraintValueString);

        probPlotPanel.calcFullfilments();

        Vismon.getVismonInstance().updatePlots();
    }

    private void maxTextFieldListenerAction(String text, JTextField maxTextField, JPanel mainPanel,
                                            Indicator indicator, IndicatorSlider indSlider,
                                            JTextField boundaryTextField, ProbabilityPlot probPlotPanel) {
        double constraintValue;
        try {
            constraintValue = Double.parseDouble(text);
            maxTextField.setBackground(mainPanel.getBackground());
        } catch (NumberFormatException e) {
            maxTextField.setBackground(Constants.BAD_INPUT_BG_COLOR);
            showBallonTip(maxTextField, "Enter a valid number", new ImageIcon("images/remove2.png"));
            return;
        }
        if (constraintValue < indicator.getMin() || constraintValue > indicator.getMax()) {
            maxTextField.setBackground(Constants.BAD_INPUT_BG_COLOR);
            showBallonTip(maxTextField, "Enter a number in the range", new ImageIcon("images/remove2.png"));
            return;
        }

        String constraintValueString = getBestFormat(constraintValue);

        indicator.setConstraintValue(constraintValue);
        indSlider.setValue(constraintValue);
        boundaryTextField.setText(constraintValueString);

        probPlotPanel.calcFullfilments();

        Vismon.getVismonInstance().updatePlots();
    }

    private void boundaryTextFieldListenerAction(String text, Indicator indicator, JTextField boundaryTextField, JPanel panel,
                                                 IndicatorSlider indSlider, JTextField minTextField,
                                                 JTextField maxTextField, ProbabilityPlot probPlotPanel) {
        double constraintValue;
        try {
            constraintValue = Double.parseDouble(text);
            boundaryTextField.setBackground(panel.getBackground());
        } catch (NumberFormatException e) {
            boundaryTextField.setBackground(Constants.BAD_INPUT_BG_COLOR);
            showBallonTip(boundaryTextField, "Enter a valid number", new ImageIcon("images/remove2.png"));
            return;
        }
        if (constraintValue < indicator.getMin() || constraintValue > indicator.getMax()) {
            boundaryTextField.setBackground(Constants.BAD_INPUT_BG_COLOR);
            showBallonTip(boundaryTextField, "Enter a number in the range", new ImageIcon("images/remove2.png"));
            return;
        }

        String constraintValueString = getBestFormat(constraintValue);

        indicator.setConstraintValue(constraintValue);
        indSlider.setValue(constraintValue);
        //boundaryTextField.setText(constraintValueString);

        if (indicator.isMaxBest())
            minTextField.setText(constraintValueString);
        else
            maxTextField.setText(constraintValueString);

        probPlotPanel.calcFullfilments();

        Vismon.getVismonInstance().updatePlots();
    }

    private void showBallonTip(JComponent component, String message, ImageIcon icon) {
        JLabel messageLabel = new JLabel(message);
        messageLabel.setForeground(Constants.MAIN_COLOR);
        messageLabel.setFont(Constants.OVERVIEW_FONT);
        if (icon != null)
            messageLabel.setIcon(icon);

        BalloonTipStyle edgedLook = new EdgedBalloonStyle(Color.WHITE, Constants.MAIN_COLOR);
        BalloonTip myBalloonTip = new BalloonTip(component, messageLabel,
                edgedLook, BalloonTip.Orientation.LEFT_ABOVE,
                BalloonTip.AttachLocation.NORTH, 10, 10, true);
        TimingUtils.showTimedBalloon(myBalloonTip, 1000);
    }

    private void setLogPlotLabel() {
        String label = "";
        if (Session.getSelectedScenario() != null)
            label += "Log";

        for (int i = 0; i < indHistPanelList.size(); ++i) {
            JTextField logPlotTextField = logPlotTextFieldList.get(i);
            logPlotTextField.setText(label);
            indHistPanelList.get(i).add(logPlotTextField, "1,0");
        }
    }

    private void indicatorSelectionAction(Indicator ind) {
        int indexOfInd = Session.getIndicators().indexOf(ind);
        Color bgColor = Color.WHITE;
        if (selectedIndicators.contains(ind)) {
            selectedIndicators.remove(ind);
            if (indexOfInd % 2 == 1)
                bgColor = Constants.OVERVIEW_SEPARATION_BG_COLOR;
        } else {
            selectedIndicators.add(ind);
            bgColor = Constants.OVERVIET_SELECTION_BG_COLOR;
        }

        indMainPanelList.get(indexOfInd).setBackground(bgColor);
        indHistPanelList.get(indexOfInd).setBackground(bgColor);
        indEquaPanelList.get(indexOfInd).setBackground(bgColor);
        indProbPanelList.get(indexOfInd).setBackground(bgColor);
        if (ind.isMinBest())
            indMinTextFieldList.get(indexOfInd).setBackground(bgColor);
        else
            indMaxTextFieldList.get(indexOfInd).setBackground(bgColor);
    }

    private void clearConstraints() {
        for (MngOption mngOption : Session.getMngOptions())
            mngOption.resetConstraints();
        for (Indicator indicator : Session.getIndicators()) {
            indicator.resetConstraintValue();
            indicator.resetProbabilityValue();
        }

        for (int i = 0; i < Session.getIndicatorNum(); ++i) {
            Indicator ithIndicator = Session.getIndicator(i);
            double constraintValue = ithIndicator.getConstraintValue();
            String constraintValueString = getBestFormat(constraintValue);
            if (ithIndicator.isMaxBest())
                indMinTextFieldList.get(i).setText(constraintValueString);
            else
                indMaxTextFieldList.get(i).setText(constraintValueString);
            indBoundaryTextFieldList.get(i).setText(constraintValueString);
            indSliderList.get(i).setValue(constraintValue);

            double probValue = ithIndicator.getProbabilityValue();
            String probValueString = getBestFormat(probValue);
            probTextFieldList.get(i).setText(probValueString);
            probSliderList.get(i).setValue(probValue);

            probPlotList.get(i).calcFullfilments();
        }

        Vismon.getVismonInstance().updatePlots();
    }

    private void keepSouthScrollBarLocation() {
        JScrollBar southScrollBar = southScrollPane.getVerticalScrollBar();
        southScrollBarCurrentRelativeValue = (double) (southScrollBar.getValue()) / southScrollBar.getMaximum();
        keepSouthScrollBarLocation = true;
    }

    public String getBestFormat(double d) {
        return Util.format(d, 2);
    }

    public static int getDensityFunc() {
        return densityFunc;
    }

    private void createSingleContourPlot() {
        if (selectedIndicators.size() != 1)
            return;

        ContourPlotFrame contourPlotFrame = new ContourPlotFrame(selectedIndicators.get(0));
        contourPlotFrame.run();
    }

    private void createSingleScatterPlot() {
        if (selectedIndicators.size() != 2)
            return;

        ScatterPlotFrame scatterPlotFrame = new ScatterPlotFrame(selectedIndicators.get(0), selectedIndicators.get(1));
        scatterPlotFrame.run();
    }

    public void repaintIndicatorSliders() {
        for (IndicatorSlider indSlider : indSliderList)
            indSlider.repaint();
    }
}
