package ui.view;

import classes.TrackedDataSet;
import ui.controller.Control;
import ui.model.Model;

import javax.imageio.ImageIO;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.Hashtable;

public class StatisticGraphPanel extends JSplitPane {

    private static final long serialVersionUID = 1L;

    private final JLabel maximumLabel = new JLabel("0");
    private final JPanel legendPanel = new JPanel();
    private String[] backgroundColors = {"White", "Dark", "Red", "Blue"};
    // Variables
    private String graphName;
    // Components
    private StatisticGraph sGraph;
    private JToggleButton toggleGridButton = new JToggleButton("Hide Grid");
    private JComboBox backgroundColorSelector = new JComboBox(backgroundColors);
    private JSplitPane that;
    private Hashtable<String, StatisticGraphPanel> graphHashtable;

    /**
     * Constructor.
     *
     * @param mod  the Model
     * @param cont the Controller
     */
    StatisticGraphPanel(Model mod, Control cont, String name, Hashtable<String, StatisticGraphPanel> gHt) {
        super();
        setDividerSize(0);
        setPreferredSize(new Dimension(600, 300));
        setContinuousLayout(true);
        setMinimumSize(new Dimension(600, 300));
        setOrientation(JSplitPane.VERTICAL_SPLIT);
        setBorder(new EmptyBorder(0, 0, 0, 0));
//        this.model = mod;
//        this.controller = cont;
        this.sGraph = new StatisticGraph(mod, cont);
        this.graphName = name;
        this.graphHashtable = gHt;
        JPanel topContainer = new JPanel();
        topContainer.setLayout(new BorderLayout(0, 0));
        JPanel buttomContainer = new JPanel();
        buttomContainer.setPreferredSize(new Dimension(0, 0));
        buttomContainer.setMinimumSize(new Dimension(0, 0));
        buttomContainer.setAlignmentX(Component.LEFT_ALIGNMENT);
        buttomContainer.setAlignmentY(Component.TOP_ALIGNMENT);
        buttomContainer.setLayout(new BorderLayout(0, 0));
        this.setTopComponent(topContainer);
        this.setBottomComponent(buttomContainer);

        // ******************** Component Propertys ***************//
        // Graph
        sGraph.setPreferredSize(new Dimension(200, 200));
        sGraph.setMinimumSize(new Dimension(100, 150));

        // Graph Name
        JLabel graphNameLabel = new JLabel(graphName);
        graphNameLabel.setHorizontalTextPosition(JLabel.CENTER);
        // set font bold and font size slightly bigger than the rest
        graphNameLabel.setFont(new Font(graphNameLabel.getFont().getName(), Font.BOLD, 14));

        toggleGridButton.addActionListener(actionEvent -> {
            boolean currentState = toggleGridButton.isSelected();
            if (currentState) {
                sGraph.hideGrid();
                toggleGridButton.setText("Show Grid");
            } else {
                sGraph.showGrid();
                toggleGridButton.setText("Hide Grid");
            }
        });

        // Panel on top (Name and Close Button)
        JPanel topPanel = new JPanel();
        topPanel.setLayout(new BorderLayout(0, 0));
        JPanel topPanelHelp = new JPanel(new BorderLayout(0, 0));
        topPanelHelp.add(graphNameLabel, BorderLayout.CENTER);
        // graph options
        JPanel graphOptionsContainer = new JPanel();
        graphOptionsContainer.add(toggleGridButton);
        graphOptionsContainer.add(new JLabel("  "));    // spacer
        JLabel backgroundColorLabel = new JLabel("Background: ");
        graphOptionsContainer.add(backgroundColorLabel);
        graphOptionsContainer.add(backgroundColorSelector);
        graphOptionsContainer.add(new JLabel("  "));    // spacer
        JButton savImgButton = new JButton("Save as Image");
        graphOptionsContainer.add(savImgButton);
        topPanelHelp.add(graphOptionsContainer, BorderLayout.EAST);
        //
        topPanel.add(topPanelHelp, BorderLayout.CENTER);
        JButton closeButton = new JButton("X");
        topPanel.add(closeButton, BorderLayout.EAST);
        savImgButton.addActionListener(actionEvent -> {
            BufferedImage img = new BufferedImage(that.getWidth(), that.getHeight(), BufferedImage.TYPE_INT_RGB);
            that.print(img.getGraphics());
            try {
                JFileChooser fileChooser = new JFileChooser();
                if (fileChooser.showSaveDialog(new JFrame()) == JFileChooser.APPROVE_OPTION) {
                    String file = fileChooser.getSelectedFile().getPath();
                    ImageIO.write(img, "jpg", new File(file + ".jpg"));
                }
            } catch (IOException e1) {
                e1.printStackTrace();
            }

        });
        topPanel.setBorder(null);

        // background-color selector
        backgroundColorSelector.addActionListener(actionEvent -> {
            String selectedBackgroundString = (String) backgroundColorSelector.getSelectedItem();
            switch (selectedBackgroundString) {
                case "White":
                    sGraph.setBackground(Color.WHITE);
                    break;
                case "Dark":
                    sGraph.setBackground(Color.DARK_GRAY);
                    break;
                case "Red":
                    sGraph.setBackground(Color.RED);
                    break;
                case "Blue":
                    sGraph.setBackground(Color.BLUE);
                    break;
            }
        });

        // Maximum Label
        maximumLabel.setVerticalAlignment(SwingConstants.TOP);
        maximumLabel.setMinimumSize(new Dimension(30, 10));
        legendPanel.setAlignmentY(Component.BOTTOM_ALIGNMENT);

        // Legend Panel
        legendPanel.setLayout(new GridLayout(0, 5, 0, 0));

        // ******************** Component Listener ****************//

        that = this;
        closeButton.addActionListener(actionEvent -> {
            JPanel parent = (JPanel) that.getParent();
            for (int i = 0; i < parent.getComponentCount(); i++) {
                if (parent.getComponent(i).equals(that)) {
                    if (parent.getComponentCount() > i + 1) {
                        parent.remove(parent.getComponent(i + 1));
                    }
                    break;
                }
            }
            graphHashtable.remove(graphName);
            parent.remove(that);
            parent.updateUI();
        });

        // ******************** add everything ********************//
        topContainer.add(sGraph);
        topContainer.add(topPanel, BorderLayout.NORTH);
        topContainer.add(maximumLabel, BorderLayout.WEST);
        buttomContainer.add(legendPanel, BorderLayout.NORTH);
        this.setEnabled(false);

    }

    /**
     * Adds the Set to the Graph.
     */

    public void addObject(TrackedDataSet set) {
        if (legendPanel.getComponentCount() >= 20) {
            JOptionPane.showMessageDialog(null, "You can not add more than 20 Properties to a Graph");
            return;
        }
        sGraph.addObject(set);
        String property;
        switch (set.getProperty()) {
            case TrackedDataSet.CONSUMPTION:
            case TrackedDataSet.GROUP_CONSUMPTION:
                property = "consumption";
                break;
            case TrackedDataSet.PRODUCTION:
            case TrackedDataSet.WASTED_ENERGY:
                property = "wasted energy";
                break;
            case TrackedDataSet.GROUP_PRODUCTION:
                property = "production";
                break;
            case TrackedDataSet.ACTIVATED_ELEMENTS:
                property = "active elements";
                break;
            case TrackedDataSet.ON_OFF:
                property = "on//off";
                break;
            case TrackedDataSet.TOTAL_PRODUCTION:
                property = "total production";
                break;
            case TrackedDataSet.TOTAL_CONSUMPTION:
                property = "total consumption";
                break;
            case TrackedDataSet.PERCENT_SUPPLIED:
                property = "Percentage of supplied";
                break;
            case TrackedDataSet.PERCENT_NOT_SUPPLIED:
                property = "Percentage of not supplied";
                break;
            case TrackedDataSet.PERCENT_PARTIAL_SUPPLIED:
                property = "Percentage of partial supplied";
                break;
            case TrackedDataSet.AMOUNT_HOLONS:
                property = "Amount of holons";
                break;
            case TrackedDataSet.AMOUNT_CLOSED_SWITCHES:
                property = "Amount of Closed Switches";
                break;
            case TrackedDataSet.AVG_AMOUNT_OBJECTS_IN_HOLONS:
                property = "Avg. Amount of Objects in Holons";
                break;
            case TrackedDataSet.AVG_AMOUNT_ELEMENTS_IN_HOLONS:
                property = "Avg. Amount of Elements in Holons";
                break;
            case TrackedDataSet.AVG_AMOUNT_PRODUCERS_IN_HOLONS:
                property = "Avg. Amount Producers in Holons";
                break;
            case TrackedDataSet.AVG_CONSUMED_ENERGY_IN_HOLONS:
                property = "Avg. Consumed Energy in Holons";
                break;
            case TrackedDataSet.AVG_WASTED_ENERGY_IN_HOLONS:
                property = "Avg. Wasted Energy in Holons";
                break;
            case TrackedDataSet.AMOUNT_BROKEN_EDGES:
                property = "Amount of Broken Edged";
                break;
            case TrackedDataSet.RATIO_PRODUCERS_CONSUMERS:
                property = "Ratio Producers:Consumers";
                break;
            case TrackedDataSet.AVG_AMOUNT_CLOSED_SWITCHES_IN_HOLONS:
                property = "Avg. Amount of Closed Switches in Holons";
                break;
            case TrackedDataSet.AVG_AMOUNT_ACTIVE_ELEMENTS_IN_HOLONS:
                property = "Avg. Amount of Active Elements in Holons";
                break;
            case TrackedDataSet.AVG_AMOUNT_INACTIVE_ELEMENTS_IN_HOLONS:
                property = "Avg. Amount of Inactive Elements in Holons";
                break;
            case TrackedDataSet.AVG_PRODUCED_ENERGY_IN_HOLONS:
                property = "Avg. Produced Energy in Holons";
                break;
            default:
                property = "null";
                break;
        }
        JLabel b;
        if (set.getCpsObject() != null) {
            b = new JLabel(set.getCpsObject().getId() + ", " + set.getCpsObject().getName() + ": " + property);
        } else {
            b = new JLabel(property);
        }
        // b.setBackground(set.getColor());
        b.setBorder(BorderFactory.createLineBorder(set.getColor(), 2));
        b.setHorizontalAlignment(SwingConstants.CENTER);
//        int color = Math.max(Math.max(set.getColor().getRed(), set.getColor().getGreen()), set.getColor().getBlue());

        b.setOpaque(true);
        b.addMouseListener(new MouseAdapter() {

            @Override
            public void mousePressed(MouseEvent e) {
                if (MouseEvent.BUTTON3 == e.getButton()) {
                    for (int i = 0; i < legendPanel.getComponentCount(); i++) {
                        if (legendPanel.getComponent(i).equals(e.getComponent())) {
                            legendPanel.remove(i);
                            sGraph.removeObject(i);
                            that.updateUI();
                        }
                    }
                }
            }
        });
        legendPanel.add(b);
        sGraph.calcMaximum();
        that.updateUI();
    }

    /**
     * Set the Maximum Label
     */
    void setMaximumLabel(double max) {
        maximumLabel.setText(Double.toString(max));
    }

//    /**
//     * Get the name of the Graph.
//     *
//     * @return the name of the Graph
//     */
//    public String getGraphName() {
//        return this.graphName;
//    }

    /**
     * Calls the addValue function of the sGraph
     */
    void addValues() {
        sGraph.addValues();
    }

    /**
     * Calls the calcMaximum function of the sGraph
     */
    void calcMaximum() {
        sGraph.calcMaximum();
    }

    public StatisticGraph getStatGraph() {
        return sGraph;
    }

//    public void setStatisticGraph(StatisticGraph sG) {
//        this.sGraph = sG;
//    }

    /**
     * Reset the Graph. Delete all calculated values.
     */
    public void resetGraph() {
        sGraph.resetGraph();
    }

    /**
     * Returns the Legend Panel.
     *
     * @return legendPanel
     */
    public JPanel getLegendPanel() {
        return legendPanel;
    }

}
