package math.autos;

import javax.swing.*;
import java.awt.*;
import java.util.Timer;
import java.util.TimerTask;

class LifePanel extends JPanel {
    private static final long serialVersionUID = -5529472311997280826L;
    private static final int w = 800;
    private static final int h = 800;
    private static final int liczbaPol = 100;
    private static final int szer = 8;
    private static final int len = szer * liczbaPol;
    private boolean[][] autos1;//komorki aktualne
    private boolean[][] autos2;//komorki nastepnej generacji
    private final Color kolorKomorek;
    private final Ksztalt ksztalt;
    private final int milis;

    public LifePanel(Ksztalt ksztalt, Color kolorKomorek,
                     double prawdopodobienstwo, int milis) {
        this.kolorKomorek = kolorKomorek;
        //prawdopodobienstwo żywej komórki
        this.ksztalt = ksztalt;
        this.milis = milis;
        setPreferredSize(new Dimension(w, h));
        setSize(w, h);
        setBackground(Color.WHITE);
        autos1 = new boolean[liczbaPol][liczbaPol];
        autos2 = new boolean[liczbaPol][liczbaPol];
        for (int i = 0; i < liczbaPol; i++) {
            for (int j = 0; j < liczbaPol; j++) {
                autos1[i][j] = Math.random() < prawdopodobienstwo;
                autos2[i][j] = false;
            }
        }
        Timer timer = new Timer();
        TimerTask timerTask = new TimerTask() {
            @Override
            public void run() {
                boolean[][] cells = autos1;
                for (int i = 0; i < liczbaPol; i++) {
                    for (int j = 0; j < liczbaPol; j++) {
                        autos2[i][j] = cells[i][j];
                        int nb = liczbaSasiadow(cells, i, j);
                        if (nb == 3)
                            autos2[i][j] = true;
                        if (nb < 2 || nb > 3)
                            autos2[i][j] = false;
                    }
                }
                autos1 = autos2;
                autos2 = cells;
                repaint();
            }
        };
        timer.schedule(timerTask, 100, milis);
    }

    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2 = (Graphics2D) g;
        g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                RenderingHints.VALUE_ANTIALIAS_ON);
        g2.setColor(Color.LIGHT_GRAY);
        int z = 0;//polozenie linii
        for (int i = 0; i <= liczbaPol + 1; i++) {
            g2.drawLine(0, z, len, z);
            g2.drawLine(z, 0, z, len);
            z += szer;
        }
        g2.setColor(kolorKomorek);
        for (int i = 0; i < liczbaPol; i++) {
            for (int j = 0; j < liczbaPol; j++) {
                if (autos1[i][j]) {
                    int x = i * szer;
                    int y = j * szer;
                    switch (ksztalt) {
                        case KOLO:
                            g2.fillOval(x, y, szer, szer);
                            break;
                        case KWADRAT:
                            g2.fillOval(x, y, szer, szer);
                    }
                }
            }
        }
    }

    private int liczbaSasiadow(boolean[][] autos, int p, int q) {
        int x1 = p;
        int x2 = p;
        int y1 = q;
        int y2 = q;
        int licznik = 0;
        if (p > 0) {
            x1--;
        }
        if (p < liczbaPol - 1) {
            x2++;
        }
        if (q > 0) {
            y1--;
        }
        if (q < liczbaPol - 1) {
            y2++;
        }
        for (int i = x1; i <= x2; i++) {
            for (int j = y1; j <= y2; j++) {
                licznik += (autos[i][j]) ? 1 : 0;
            }
        }
        if (autos[p][q]) {
            licznik--;
        }
        return licznik;
    }

    public int getMilis() {
        return milis;
    }

    private void clear() {
        for (int j = 0; j < liczbaPol; j++) {
            for (int k = 0; k < liczbaPol; k++) {
                this.autos1[j][k] = false;
                this.autos2[j][k] = false;
            }
        }
    }

    public void putStructure(boolean[][] array) {
        clear();
        for (int m1 = 0; m1 < array.length; m1++) {
            for (int j1 = 0; j1 < array[0].length; j1++) {
                this.autos1[j1 + 25][m1 + 25] = array[m1][j1];
            }
        }
    }

    public void putStructure(boolean[] array, int cols) {
        clear();
        boolean[][] arr = oneToTwo(array, cols);
        for (int m1 = 0; m1 < arr.length; m1++) {
            System.arraycopy(arr[m1], 0, this.autos1[m1 + 25], 25, arr[0].length);
        }
    }

    public boolean[][] oneToTwo(boolean[] tab, int cols) {
        int rows = tab.length / cols;
        boolean[][] temparr = new boolean[rows][cols];
        for (int i = 0; i < tab.length; i++) {
            int x = (i / cols);
            int y = i % cols;
            temparr[x][y] = tab[i];
        }
        return temparr;
    }

}
