package vismon.component;


import vismon.data.Indicator;
import vismon.data.Scenario;
import vismon.data.Session;
import vismon.gui.OptionsPanel;
import vismon.util.Constants;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.event.MouseEvent;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;


public class IndicatorSlider extends MonoSlider {

    private final int xScenarioTriangleIncrement = 6;
    private final int yScenarioTriangleIncrement = 9;
    private final int scenarioMousePositionDif = 3;

    private Indicator indicator;

    private Map<Scenario, Integer> scenarioPositions;

    public IndicatorSlider(double min, double max, boolean isMinBest, int w, int h) {
        super(min, max, isMinBest, w, h);
        scenarioPositions = new HashMap<Scenario, Integer>();
    }

    public Indicator getIndicator() {
        return indicator;
    }

    public void setIndicator(Indicator indicator) {
        this.indicator = indicator;
    }

    @Override
    public void paint(Graphics g) {
        Rectangle rect = getInBounds();

        startX = rect.x;
        startY = rect.y;
        sliderWidth = rect.width;
        sliderHeight = rect.height;

        int barTopY = startY + sliderHeight;
        int baseLineY = startY + (int)(sliderHeight * 0.5);


        g.setColor(bgColor);
        g.fillRect(rect.x, rect.y, rect.width, rect.height);

        int valueX = toScreenX(getValue());

        //DRAWING THE BASE LINE
        if (isMinBest)
            g.setColor(acceptableColor);
        else
            g.setColor(unacceptableColor);
        g.drawLine(startX, baseLineY, valueX, baseLineY);

        if (isMinBest)
            g.setColor(unacceptableColor);
        else
            g.setColor(acceptableColor);
        g.drawLine(valueX, baseLineY, startX + sliderWidth, baseLineY);

        //DRAWING THE VERTICAL LINES FOR MIN AND MAX VALUES
        g.setColor(acceptableColor);
        g.drawLine(valueX, startY, valueX, barTopY);
        g.drawLine(valueX + 1, startY, valueX + 1, barTopY);
        g.drawLine(valueX + 2, startY, valueX + 2, barTopY);

        drawMinimumValue(g, startX, startY + sliderHeight);
        drawMaximumValue(g, startX + sliderWidth, startY + sliderHeight);

        drawTickMarks(g, startX, startX + sliderWidth, startY + sliderHeight);


        // DRAWING THE SCENARIO TRIANGLES
        scenarioPositions.clear();
        for (Scenario scenario : Session.getScenarios()) {
            if (!scenario.isVisible())
                continue;

            double value = scenario.getAverageOrMedianValue(indicator, OptionsPanel.contoursBasedOn);
            int scenarioPosition = (int) (sliderWidth * (value - minimum) /(maximum - minimum));
            scenarioPositions.put(scenario, scenarioPosition);

            int xIncrement = this.xScenarioTriangleIncrement;
            int yIncrement = this.yScenarioTriangleIncrement;
            if (Session.getSelectedScenario() != null && Session.getSelectedScenario().equals(scenario)) {
                xIncrement += 4;
                yIncrement += 4;
            }

            int[] xCoordinates = new int[]{scenarioPosition, scenarioPosition- xIncrement, scenarioPosition+ xIncrement};
            int[] yCoordinates = new int[]{baseLineY, baseLineY- yIncrement, baseLineY- yIncrement};
            g.setColor(scenario.getColor());
            g.fillPolygon(xCoordinates, yCoordinates, 3);
            g.setColor(Constants.MAIN_COLOR);
            g.drawPolygon(xCoordinates, yCoordinates, 3);
        }

        try {
            if (isMinBest)
                g.drawImage(ImageIO.read(new File("images/arrow_left.png")), valueX - 4, startX, null);
            else
                g.drawImage(ImageIO.read(new File("images/arrow_right.png")), valueX + 2, startX, null);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void setRangeProperties(double value, double min, double max) {
        this.value = Math.round(value / indicator.getRoundValue()) * indicator.getRoundValue();
        minimum = min;
        maximum = max;
    }

    public void mouseDragged(MouseEvent e) {
        if (enabled == false)
            return;

        double x = toLocalX(e.getX());

        if (x < getMinimum())
            x = getMinimum();

        if (x > getMaximum())
            x = getMaximum();

        if (pick == PICK_HANDLE) {
            if (x >= getMinimum() && x <= getMaximum())
                setValue(x);
                indicator.setConstraintValue(x);
        }
        repaint();
    }

    public void mouseClicked(MouseEvent e) {
        super.mouseClicked(e);
        if (e.getClickCount() == 2)
            indicator.setConstraintValue(value);
        else {
            Scenario selectedScenario = null;
            for (Scenario scenario : Session.getScenarios()) {
                int scenarioPosition = (int) (sliderWidth * (scenario.getAverageValue(indicator) - minimum) /(maximum - minimum));
                if (e.getX() - scenarioMousePositionDif <= scenarioPosition &&
                    scenarioPosition <= e.getX() + scenarioMousePositionDif) {
                    selectedScenario = scenario;
                    break;
                }
            }
            if (selectedScenario == null)
                return;

            if (Session.getSelectedScenario() == null) {
                Session.setSelectedScenario(selectedScenario);
                return;
            }

            if (Session.getSelectedScenario().equals(selectedScenario))
                Session.setSelectedScenario(null);
            else
                Session.setSelectedScenario(selectedScenario);
        }
    }

    public void mouseMoved(MouseEvent e) {
        super.mouseMoved(e);

        String toolTipText = "";
        for (Scenario scenario : Session.getScenarios()) {
            if (!scenarioPositions.containsKey(scenario))
                continue;

            int scenarioPosition = scenarioPositions.get(scenario);

            if (e.getX() - scenarioMousePositionDif <= scenarioPosition &&
                scenarioPosition <= e.getX() + scenarioMousePositionDif) {
                toolTipText += scenario.getName();
                break;
            }
        }
        setToolTipText(toolTipText);
    }

}