package math.stat;

import math.shapes.Arrow;
import math.utils.MathUtil;
import math.utils.Tuple2d;

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

public class LinearGraph extends JPanel {
    private static final long serialVersionUID = 5218506428064759030L;
    private static final int w = 800;
    private static final int h = 800;
    private final int[] array;
    private final float szer;
    private final String nazwaX;
    private final String nazwaY;
    private final float gapWidth;
    private final Color color;
    private final float dist;
    private float maxY;
    private float minY;
    private final Tuple2d[] klas;
    private final int len;
    private float maxX;
    private final float wys;
    private final float osYLen;
    private final int jednY;
    private final float osXLen;
    private final int szerSlupka;
    private final Font font;

    public LinearGraph(int[] array, float szer, String nazwaX, String nazwaY,
                       float gapWidth, Color color) {
        this.array = array;
        this.szer = szer;
        this.nazwaX = nazwaX;
        this.nazwaY = nazwaY;
        this.gapWidth = gapWidth;
        this.color = color;
        dist = szer * 0.06f;// odleglosc osi od brzegow wykresu
        maxY = 0f;// najwyzsza wartosc na osi Y
        minY = Float.MAX_VALUE;// najnizsza wartosc na osi Y
        klas = StatUtil.klasy(array);
        len = klas.length;
        for (int i = 0; i < len; i++) {
            maxY = (float) Math.max(maxY, klas[i].getY());// 41
            minY = (float) Math.min(minY, klas[i].getY());// 1
        }
        float minX = Float.MAX_VALUE;
        for (int ii = 0; ii < len; ii++) {
            minX = (float) Math.min(minX, klas[ii].getX());
        }
        wys = MathUtil.roundToMulti(szer / 1.618, 10);// wysokosc wykresu 120
        osYLen = wys - 2 * dist;// dlugosc osi Y = 100
        jednY = (int) ((osYLen - 0.25 * dist) / maxY);// ile pikseli
        // zajmuje jednostka
        // na osi Y = 2
        osXLen = szer - 2 * dist;// dlugosc osi X = 180
        int szerWykr = (int) (osXLen - dist);// szerokosc wykresu na osi X =170
        szerSlupka = (szerWykr / len);// 170/8=21 pikseli
        int fs = (int) (0.02 * szer + 2.0);
        font = new Font(Font.SANS_SERIF, Font.PLAIN, fs);
        setPreferredSize(new Dimension(w, h));
        setSize(w, h);
        setBackground(Color.WHITE);
    }

    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2 = (Graphics2D) g;
        g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                RenderingHints.VALUE_ANTIALIAS_ON);
        g2.drawRect(0, 0, w - 1, h - 1);
        Arrow X = new Arrow(dist, wys - dist, osXLen, 0.5f, 0f, 12f, 10f, true);// os X
        g2.draw(X);
        Arrow Y = new Arrow(dist, wys - dist, osYLen, 0.5f, 90f, 12f, 10f, true);// os Y
        g2.draw(Y);
        g2.setColor(color);
        g2.setColor(color);
        for (int jj = 0; jj < len - 1; jj++) {// rozrysowanie linii
            int x1 = (int) (dist + jj * szerSlupka + szerSlupka / 2);
            int y1 = (int) (wys - dist - klas[jj].getY() * jednY);
            int x2 = (int) (dist + (jj + 1) * szerSlupka + szerSlupka / 2);
            int y2 = (int) (wys - dist - klas[jj + 1].getY() * jednY);
            g2.drawLine(x1, y1, x2, y2);
        }
        g2.setColor(Color.BLACK);
        int x = (int) (maxY - minY);
        String y = String.valueOf(x);
        int z = y.length();
        int zz = 0;
        switch (z) {
            case 1:
                zz = 1;
                break;
            case 2:
                zz = 10;
                break;
            case 3:
                zz = 100;
                break;
            case 4:
                zz = 1000;
                break;
        }
        g2.setFont(font);
        FontMetrics fm = g2.getFontMetrics(font);
        for (int k = 1; k < (int) (maxY / zz) + 1; k++) {
            //ctx.moveTo(dist - 5, wys - dist - zz * jednY * k);
            String zzz = String.valueOf(zz * k);
            g2.drawString(zzz, (int) (dist - fm.stringWidth(zzz) - 0.7 * fm
                            .stringWidth(zzz)),
                    (int) (wys - dist - zz * jednY * k + 0.3 * fm.getHeight()));
            g2.drawLine((int) (dist - 5), (int) (wys - dist - zz * jednY * k),
                    (int) dist, (int) (wys - dist - zz * jednY * k));
        }
        for (int m = 0; m < len; m++) {
            g2.drawString("" + klas[m].getX(),
                    (int) (dist - fm.stringWidth("" + klas[m].getX()) / 2.0 + m
                            * szerSlupka + szerSlupka / 2),
                    (int) (wys - dist + 0.6 * dist));
        }
        g2.drawString(nazwaY, (int) (dist - 0.5 * dist),
                (int) (dist - 0.3 * dist));
        g2.drawString(nazwaX,
                (int) (2 * dist + osXLen - fm.stringWidth(nazwaX)), (int) (wys
                        - dist + 0.6 * dist));
    }

    public int[] getArray() {
        return array;
    }

    public float getSzer() {
        return szer;
    }

    public float getMaxX() {
        return maxX;
    }

    public float getGapWidth() {
        return gapWidth;
    }
}
