package gameoflife;

// importazione delle classi di libreria necessarie
import java.applet.Applet;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.event.ActionListener;
import java.awt.event.*;
import java.awt.*;

public class GameOfLifeApplet extends Applet implements MouseListener, MouseMotionListener, ActionListener, Runnable {
    //////////////////////////////////////////////
    //VARIABILI DI DISEGNO DEL CONTESTO GRAFICO///

    Image imgOffScreen;
    Graphics gOffScreen;
    
    Thread thAgg = new Thread(this);
    private int coorX = 0, coorY = 0;		//
    private int rigClick = 0, colClick = 0;	//
    private int lato = 0;			//
    private int w = 0;				//
    private int h = 0;				//
    //////////////////////////////////////////////
    Button bAvanti;
    public static int numRighe = 440; //numero di colonne della griglia
    public static int numColonne = 400; //numero di righe
    private Cellula[][] griglia = new Cellula[numRighe][numColonne];
    private Button bRandomFill1, bRandomFill2, bRandomFill3, bRandomFill4, bRandomFill5;

    //istanzio un oggetto Griglia
    @Override
    public void init() {
        this.setSize(800, 900);
        this.setBackground(Color.BLUE);
        
        this.addMouseListener(this);
        this.addMouseMotionListener(this);

        bAvanti = new Button("Play/Pause"); // assegno la label Avanti al pulsante avanti
        bAvanti.addActionListener(this); // assegno l action listener al pulsante bAvanti
        this.add(bAvanti);              //aggiungo il pulsante al contesto grafico
        
        bRandomFill1 = new Button("Fill Random 1 su 2");
        bRandomFill1.addActionListener(this); 
        this.add(bRandomFill1);             
        
        bRandomFill2 = new Button("Fill Random 1 su 3");
        bRandomFill2.addActionListener(this); 
        this.add(bRandomFill2); 
        
        bRandomFill3 = new Button("Fill Random 1 su 5");
        bRandomFill3.addActionListener(this); 
        this.add(bRandomFill3); 
        
        bRandomFill4 = new Button("Fill Random 1 su 10");
        bRandomFill4.addActionListener(this); 
        this.add(bRandomFill4);
        
        bRandomFill5 = new Button("Fill Random 1 su 20");
        bRandomFill5.addActionListener(this); 
        this.add(bRandomFill5);
        
        imgOffScreen = createImage(this.getWidth(), this.getHeight());
        gOffScreen = imgOffScreen.getGraphics();

        for (int m = 0; m < numRighe; m++) {
            for (int n = 0; n < numColonne; n++) {
                griglia[m][n] = new Cellula(false, false);
                
                if((m>60 && n>60) && (n < numColonne - 60 && m < numRighe - 60) && (m == 220 || n == 200)){
                    griglia[m][n].vivi();
                    griglia[m][n].vivrai();
                }
            }
        }
    }

    @Override
    public void update(Graphics g){
        paint(g);
    }
    
    @Override
    public void paint(Graphics g) {
        w = this.getWidth(); //larghezza
        h = this.getHeight(); //altezza

        bAvanti.setLocation(10, (int) (h/10 * 0.6)); //riposiziono i pulsatni
        bRandomFill1.setLocation(10, h/10); //riposiziono i pulsatni
        bRandomFill2.setLocation(10,(int) (h/10 * 1.4)); //riposiziono i pulsatni
        bRandomFill3.setLocation(10, (int) (h/10 * 1.8)); //riposiziono i pulsatni
        bRandomFill4.setLocation(10, (int) (h/10 * 2.2)); //riposiziono i pulsatni
        bRandomFill5.setLocation(10, (int) (h/10 * 2.6)); //riposiziono i pulsatni        
        
        //se ho piu rige che colonne
        lato = w / numColonne;
          
        
        gOffScreen.clearRect(0, 0, w, h);
        
        gOffScreen.setColor(Color.BLACK);
        
        //ciclo per la stampa della tabella
        for (int m = 0; m < numRighe; m++) {
            for (int n = 0; n < numColonne; n++) {
                
                gOffScreen.fillRect(lato * n,lato * m, lato, lato);
                
                if (griglia[m][n].diagnosi() == true) {
                    //in le il prossimo stato della cellula sara viva la colo ro verdo se no rossa
                    if(griglia[m][n].destino == true){
                        gOffScreen.setColor(Color.GREEN);
                    }
                    else if(griglia[m][n].destino == false){
                        gOffScreen.setColor(Color.RED);
                    }
                    
                    gOffScreen.fillOval(lato * n, lato * m, lato, lato);
                    
                    gOffScreen.setColor(Color.BLACK);
                }
            }
        }
 
        g.drawImage(imgOffScreen, 0, 0, bAvanti);
    }

    public void mouseClicked(MouseEvent e) {
        //System.out.println(e.getButton());
        if (e.getButton() == MouseEvent.BUTTON1) {
            coorX = e.getX();
            coorY = e.getY();
                
            //trova in quale quadrato si e cliccato
            trovaQuadratoCliccato();

            griglia[rigClick][colClick].toggleVita();

        } else if (e.getButton() == MouseEvent.BUTTON2) {
            for (int rig = 0; rig < numRighe; rig++) {
                for (int col = 0; col < numColonne; col++) {
                    griglia[rig][col].muori();
                }
            }
        }
        calcolaDestinoCellule();
        
        repaint();
    }

    public void mouseDragged(MouseEvent e) {
        coorX = e.getX();
        coorY = e.getY();

        if (e.getModifiers() == MouseEvent.BUTTON1_MASK) { //esegue solo se si preme il tasto sx del mouse che corrisponde al valore 1
            trovaQuadratoCliccato();
            griglia[rigClick][colClick].vivi();
        } else if (e.getModifiers() == MouseEvent.BUTTON3_MASK) { //esegue solo se si preme il tasto dx del mouse che corrisponde al valore 3
            trovaQuadratoCliccato();
            griglia[rigClick][colClick].muori();
        } else {
        }

        calcolaDestinoCellule();

        repaint();
    }

    //questo metodo, conoscendo le coordinate x e y del clic setta la riga e la colonna in cui si trova la cellula cliccata
    public void trovaQuadratoCliccato() {
        //Trovo la colonna 
        for (int i = 0; i < numColonne; i++) {
            if (coorX > i * lato) {
                colClick = i;
            }
        }
        //Trovo la riga
        for (int i = 0; i < numRighe; i++) {
            if (coorY > i * lato) {
                rigClick = i;
            }
        }
    }

    //Quasto è il metodo di action Listener che viene attivato quando si preme il pulsante
    @Override
    public void actionPerformed(ActionEvent e) {
        if (e.getSource() == bAvanti) {
            if(!thAgg.isAlive()){
                thAgg.start();
                //System.out.println("start");
            }
            else if(!thAgg.isInterrupted()){
                thAgg.interrupt();
                thAgg = new Thread(this);
                //System.out.println("interr");
            }
        }
        else if (e.getSource() == bRandomFill1) {
            randomFill(2);
        }
        else if (e.getSource() == bRandomFill2) {
            randomFill(3);
        }
        else if (e.getSource() == bRandomFill3) {
            randomFill(5);
        }
        else if (e.getSource() == bRandomFill4) {
            randomFill(10);
        }
        else if (e.getSource() == bRandomFill5) {
            randomFill(20);
        }
    }

    public void randomFill(int value){
        
        for (int rig = 0; rig < numRighe; rig++) {
            for (int col = 0; col < numColonne; col++) {
                //genero un valore intero da 0 al param passato, 
                // se random ritorna un val <= 1 allora la setta viva se no morta
                if(Math.rint(Math.random()*value) <= 1) griglia[rig][col].vivi();
                else griglia[rig][col].muori();
            }
        }
        calcolaDestinoCellule();
        
        repaint();
    }
    
    //con questo metodo calcolo il destino delle cellule, ovvero lo stato successivo che devono avere
    public void calcolaDestinoCellule() {
        int vicini = 0; //serve per calolare le cellule vicine
        for (int rig = 0; rig < numRighe; rig++) {
            for (int col = 0; col < numColonne; col++) {
                // conto le cellule vive vicino a questa
                if (col > 0 && rig < numRighe - 1) {
                    if (griglia[rig + 1][col - 1].diagnosi()) {
                        vicini++;
                    }
                }
                if (rig < numRighe - 1) {
                    if (griglia[rig + 1][col].diagnosi()) {
                        vicini++;
                    }
                }
                if (col < numColonne - 1 && rig < numRighe - 1) {
                    if (griglia[rig + 1][col + 1].diagnosi()) {
                        vicini++;
                    }
                }
                if (col > 0) {
                    if (griglia[rig][col - 1].diagnosi()) {
                        vicini++;
                    }
                }
                if (col < numColonne - 1) {
                    if (griglia[rig][col + 1].diagnosi()) {
                        vicini++;
                    }
                }
                if (col > 0 && rig > 0) {
                    if (griglia[rig - 1][col - 1].diagnosi()) {
                        vicini++;
                    }
                }
                if (rig > 0) {
                    if (griglia[rig - 1][col].diagnosi()) {
                        vicini++;
                    }
                }
                if (rig > 0 && col < numColonne - 1) {
                    if (griglia[rig - 1][col + 1].diagnosi()) {
                        vicini++;
                    }
                }

                //se la cellula è viva e ha 2 o 3 vicini allora rimane viva, altrimenti muore
                if ((griglia[rig][col].diagnosi() == true && vicini == 2) || (griglia[rig][col].diagnosi() == true && vicini == 3)) {
                    griglia[rig][col].vivrai();
                } else {
                    griglia[rig][col].morirai();
                }

                //se la cellula è morta e ha 3 vicini allora vive
                if (griglia[rig][col].diagnosi() == false && vicini == 3) {
                    griglia[rig][col].vivrai();
                } else if (griglia[rig][col].diagnosi() == false) {
                    griglia[rig][col].morirai();
                } else {
                }

                vicini = 0; // resetto il contatore
            }
        }
    }

    public void eseguiDestino() {
        for (int rig = 0; rig < numRighe; rig++) {
            for (int col = 0; col < numColonne; col++) {
                griglia[rig][col].impostaDestino();
            }
        }
    }

    public void mouseMoved(MouseEvent e) {
    }

    public void mousePressed(MouseEvent e) {
    }

    public void mouseReleased(MouseEvent e) {
    }

    public void mouseEntered(MouseEvent e) {
    }

    public void mouseExited(MouseEvent e) {
    }

    @Override
    public void run() {
        boolean flag = true;
        while (flag) {
            try {
                Thread.sleep(80);
                
                eseguiDestino();
                
                calcolaDestinoCellule();
                
                repaint();
            } catch (InterruptedException ex) {
                flag = false;
            }
        }
    }
}
