/*
FooLife - A simple Conway's game of life with periodic boundaries
 
Copyright (C) 2003 Andrea Sottoriva

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
*/

import java.applet.*;
import java.util.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.font.*;

public class FooLife extends java.applet.Applet implements MouseListener, Runnable
{
    // computing thread
    private Thread life_thread = null;

    // lattice dimension
    private int L;

    // lattice itself
    private int lattice[][];

    // temp lattice
    private int temp[][];

    // flags
    private boolean start = false;
    private boolean first = true;

    public void start()
    {
	if(life_thread == null) {
	    life_thread = new Thread(this);
	    life_thread.start();
	    life_thread.suspend();
	}
    }

    public void stop()
    {
	life_thread = null;
    }

    // constructor creates and initialises LGA
    public void init() 
    {
	addMouseListener(this);

	L = 75;
	resize(L * 2, L * 2);
	lattice = new int[L][L];	
	temp = new int[L][L];

	lattice[(int)(L / 2) - 1][(int)(L / 2)] = 
            lattice[(int)(L / 2) - 1][(int)(L / 2) + 1] =
	    lattice[(int)(L / 2)][(int)(L / 2) - 1] = 
	    lattice[(int)(L / 2)][(int)(L / 2)] = 
	    lattice[(int)(L / 2 + 1)][(int)(L / 2)] = 1;
    } 

    public void destroy() {
        removeMouseListener(this);
    }

    /*
      Iterate through all lattice sites (curPos[i]) calculating new particle
      positions. Then iterate through new positions (newPos[]) to check for and
      take action if collisons have occurred. Loop.
    */
    public void run()
    {
	int neighs;

        while(life_thread != null) {
	    
            for(int i = 0; i < L; ++i) {
                for(int j = 0; j < L; ++j) {
                    neighs = lattice[(i - 1 + L) % L][(j - 1 + L) % L] + lattice[i][(j - 1 + L) % L] +
                        lattice[(i + 1) % L][(j - 1 + L) % L] + lattice[(i - 1 + L) % L][j] + 
                        lattice[(i + 1) % L][j] + lattice[(i - 1 + L) % L][(j + 1) % L] + 
                        lattice[i][(j + 1) % L] + lattice[(i + 1) % L][(j + 1) % L];
		    
                    if(neighs == 3)
                        temp[i][j] = 1;
                    else if(neighs > 3 || neighs < 2)
                        temp[i][j] = 0;
                    else
                        temp[i][j] = lattice[i][j];
                }
            }
        
            for(int i = 0; i < L; ++i) 
                for(int j = 0; j < L; ++j) 
                    lattice[i][j] = temp[i][j];
	
	    repaint();
	    
	    try {
		Thread.sleep(100);
	    } catch(InterruptedException e) {}	    
	}
    }
    
    /*
      Uses curPos particle positions (curPos[]) to draw lattice.
      Is called by intRandom() and at the end of each full iteration of run()
    */
    public void paint(Graphics g)
    {
        g.setColor(Color.black);
        g.fillRect(0, 0, L * 2, L * 2);
        g.setColor(Color.white);
        
        //iterate through lattice sites
        for(int i = 0; i < L; i++){
            for(int j = 0; j < L; ++j) {
                if(lattice[i][j] == 1) {
                    g.fillRect(j * 2, i * 2, 2, 2);
                }
            }
        }

	if(first) {
	    String click = "Click to start/stop";
	    Font font = new Font("Courier", Font.PLAIN, 10);
	    Graphics2D g2d = (Graphics2D)g;
	    
	    g.setFont(font);
	    g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
	    g2d.drawString(click, 19, 50);
	}

        
        g.dispose();
    }

    public void mousePressed(MouseEvent e)
    {
    }

    public void mouseReleased(MouseEvent e)
    {
    }

    public void mouseClicked(MouseEvent e)
    {
	first = false;
	start = !start;

	if(!start)
	    life_thread.suspend();
	else
	    life_thread.resume();
	
	repaint();
    }

    public void mouseEntered(MouseEvent e)
    {
    }

    public void mouseExited(MouseEvent e)
    {
    }
}

