/**
 * @author Haile Eyob
 *	@file   SquareRuleApplet.java 
 * @date	  05-14-2003
*/

import java.awt.*;
import java.awt.event.*;
import java.applet.Applet;

/**
<applet code="SquareRuleApplet.class" width=600 height=400>
</applet>
*/

public class SquareRuleApplet extends Applet
		implements ActionListener, Runnable {
	SquareRulePanel squarePanel;
	Panel controlPanel;
	Thread runner;
	TextField text;
	Button resume, pause, random;
	Button clear, start;
	
	boolean on = false;

	int input;
	static final String verNumber = "1.2";

	public void init() {
		controlPanel = new Panel();
		squarePanel  = new SquareRulePanel();

		text   = new TextField("10" , 3);
		text.setBounds(0, 0, 50, 50);
		
		text.addKeyListener(new KeyAdapter() {  
		      	public void keyTyped(KeyEvent event) {
		         	char ch = event.getKeyChar();
		            if(ch < '0' || ch > '9') {
		         		event.consume();
		           	}
		         }
       });		
		resume  = new Button("Resume");
		pause   = new Button("Pause");
		random  = new Button("Random");
		clear  = new Button("Clear");
		start  = new Button("Start");
	
		controlPanel.add(new Label("Input (integer) = "));
		controlPanel.add(text);
		controlPanel.add(start);
		controlPanel.add(resume);
		controlPanel.add(pause);
		controlPanel.add(random);
		controlPanel.add(clear);
		
		text.addActionListener(this);
		resume.addActionListener(this);
		pause.addActionListener(this);
		random.addActionListener(this);
		clear.addActionListener(this);
		start.addActionListener(this);

		setLayout(new BorderLayout());
		add(squarePanel, "Center");
		add(controlPanel, "South");
		resume.setEnabled(false);
		pause.setEnabled(true);
	}

	public void run() {
      for(;;) {
         squarePanel.update();
         try {
				Thread.sleep(10);
         }
         catch(InterruptedException e) {
			}
      }
   }

   public void start() {
      runner = new Thread(this);
      runner.start();
   }
   public void stop() {
	   runner.stop();
   }
   
   public void actionPerformed(ActionEvent e) {
		String action = (String)e.getActionCommand();
		if(action.equals("Pause")) {
			pause.setEnabled(false);
			resume.setEnabled(true);
			clear.setEnabled(false);
			start.setEnabled(false);
			random.setEnabled(false);

			stop();
		}
		else if(action.equals("Resume")) {
			clear.setEnabled(true);
			start.setEnabled(true);
			resume.setEnabled(false);
			pause.setEnabled(true);
			random.setEnabled(true);
			start();
		}
		else if(action.equals("Random")) {
			clear.setEnabled(true);
			start.setEnabled(true);
			resume.setEnabled(false);
			pause.setEnabled(true);
			squarePanel.initRandom();
		}
		else if(action.equals("Start")) {
			resume.setEnabled(false);
			pause.setEnabled(true);
			squarePanel.clear();
			if(on) {
				squarePanel.initRandom();
			}
			else {
				processInput();
			}
		}
		else if(action.equals("Clear")) {
			start.setEnabled(true);
			pause.setEnabled(false);
			squarePanel.clear();
		}
		else {
			processInput(); 
		}
	}
	
	public void processInput() {
		int input = Integer.parseInt(text.getText());
		squarePanel.getInput(input);
	}

	public String getAppletVersion() {
  		return verNumber;
  	}

	public String getAppletName() {
	    return "Squaring rule CA ver" + getAppletVersion();
  	}

	public String getAppletInfo() {
    	return getAppletName() + "\n" +
           "Copyright (C) Haile Eyob, 2003\n" +
           "e-mail: h_eyob@yahoo.com\n" +
           "This applet uses 5 colors.\n";
  }
}


class SquareRulePanel extends Canvas {
	SquareRule rule;
	Image buffer;

	int r  = 15;
	int b  = 15;
	int y  = 15;
	int bl = 15;

	int cellSize;
	int width;
	int height;
	int root;
	int lineCount;
	int startPosition;

	int 	oldState[] = null;
	int   newState[] = null;
	Color colors[]   = null;

	boolean done = false;

	Color white	 = Color.white;
	Color black  = Color.black;
	Color yellow = Color.yellow;
	Color blue   = Color.blue;
	Color red    = Color.red;
	Color gray   = Color.gray;

	public SquareRulePanel() {
		root = 10;
		startPosition = 500;
		initParams();
		init();
	}

	public  void initParams() {
		lineCount = 0;
		cellSize  = 1;
		height    = 600;
		width     = 600;
		rule 		 = new SquareRule();
		oldState  = new int[width];
		newState  = new int[width];
		colors    = new Color [width];
	}

	public  void getInput(int number) {
		done= false;
		if(number < 0)
			root = -number;
		else
			root = number;
		initParams();
		init();
	}

	public   int getRoot() {
		return root;
	}
	
	public  int getStartPosition() {
		return startPosition;
	}
	public void setStartPosition(int pos) {
		startPosition = pos;
	}
	
	public  void initFirstRow() {
		int next = getStartPosition();		
		for(int i = 0; i < getRoot(); i++) {
			oldState[next] = 1;
			colors[next] 	= black;
			next = (next + 1) % width;
		}
		oldState[next] = 4;
		colors[next] 	= blue;
		next++;
		oldState[next] = 3;
		colors[next] 	= yellow;
	}

	public  void initRandom() {
		clear();
		initParams();

		for(int i = 0; i < width; i++) {
			int random  = (int) (Math.random() * 6);
			if(random == 2 && random == 0) {
				i--;
			}
			else {
				oldState[i] = random;
				colors[i] 	= rule.getColor(random);
			}
		}			
	}
	
	public  void init() {
		clear();
		initFirstRow();
	}

	public  void clear() {
		done= false;
		for(int x = 0; x < width; x++) {
			colors[x]   = white;
			oldState[x] = 0;
			newState[x] = 0;				
		}
	}

	public  void drawGrid(Graphics g) {
		int x, y;
		g.setColor(white);
		g.fillRect( 0, 0, cellSize * width, cellSize * height );

		// draw grid
		g.setColor(white);

		for(x = 1; x < height; x++ ) {
			g.drawLine(x * cellSize, 0, x * cellSize, cellSize * width);
		}
		for(y = 1; y < width; y++ ) {
			g.drawLine( 0, y * cellSize, cellSize * height, y * cellSize);
		}

		for(x = 0; x < height; x++ ) {
			     if(oldState[x] == 1) g.setColor(black);
			else if(oldState[x] == 3) g.setColor(yellow);
			else if(oldState[x] == 4) g.setColor(blue);
			else  	                 g.setColor(white);
			
			g.fillRect(x * cellSize, y * cellSize, cellSize, cellSize);
		}
	}

	public  void processRow(Graphics g, int y) {
		int x;
		int [] v = new int[3];
		
		for( x = 0; x < width; x++ ) {
			if(x == 0) {
				v[0] = oldState[width - 1];
				v[1] = oldState[0];
				v[2] = oldState[1];
			}
			else if(x == width - 1) {
				v[0] = oldState[width - 2];
				v[1] = oldState[width - 1];
				v[2] = oldState[0];				
			}		
			else {
				for(int k = -1; k <= 1; k++ )
				v[k+1] = oldState[x + k];
			}				
			int cNumber = rule.getColorNumber(v);
			newState[x] = cNumber;
			Color color = rule.getColor(cNumber);
			colors[x]   = color;
			g.setColor(color);
			g.fillRect( x * cellSize,  y * cellSize, cellSize, cellSize );
		}	
		for(x = 0; x < width; x++)
			oldState[x] = newState[x];		
	}

   public  void update()
   {
      if (buffer == null)
         buffer = createImage(height, width);
      Graphics g = buffer.getGraphics();
		
		if(!done) {
			drawGrid(g);
			done = true;
		}
      processRow(g, lineCount);
            
	   if (lineCount < height - 2*cellSize + 1)
	   	lineCount++;
      else {			
			g.copyArea(0, cellSize, width, height - cellSize, 0, -cellSize);
			g.clearRect(0, height - cellSize, width , cellSize);
		}
      g.dispose();
      repaint();
   }

   public void paint(Graphics g) {
      if (buffer != null)
        g.drawImage(buffer, 0, 0, null);
   }

   public void update(Graphics g) {
      paint(g);
   }
}

/*	The transition rules */

class SquareRule {
	public Color getColor(int number) {
		Color c = Color.white;
		switch(number)	{
			case 0: c = Color.white; break;
			case 1: c = Color.black; break;
			case 3: c = Color.yellow;break;
			case 4: c = Color.blue;  break;
			case 5: c = Color.red;   break;
		}
		return c;
	}

	public int getColorNumber(int v[]) {
		int v0 = v[0];
		int v1 = v[1];
		int v2 = v[2];
		int c  = 0;

		if(v0 == 0) {
			if(v1 == 0) {
				if(v2 == 0) 	  c = 0;
				else if(v2 == 1) c = 4;
				else if(v2 == 3) c = 5;
				else if(v2 == 4) c = 0;
				else if(v2 == 5) c = 0;
			}
			else if(v1 == 1) {
				if(v2 == 1)      c = 1;
				else if(v2 == 4) c = 1;
			}
			else if(v1 == 3) {
				if(v2 == 1)      c = 5;
				else if(v2 == 5) c = 5;
			}
			else if(v1 == 4) {
				if(v2 == 0) 	  c = 0;
				else if(v2 == 1) c = 5;
				else if(v2 == 3) c = 0;
				else if(v2 == 4) c = 0;
				else if(v2 == 5) c = 0;
			}
			else if(v1 == 5) {
				if(v2 == 0) 	  c = 5;
				else if(v2 == 1) c = 3;
				else if(v2 == 3) c = 3;
				else if(v2 == 4) c = 4;
				else if(v2 == 5) c = 5;
			}
		}

		else if(v0 == 1) {
			if(v1 == 1) {
				if(v2 == 1)      c = 1;
				else if(v2 == 3) c = 1;
				else if(v2 == 4) c = 1;
				else if(v2 == 5) c = 4;
			}
			else if(v1 == 3) {
				if(v2 == 4)      c = 5;
			}
			else if(v1 == 4) {
				if(v2 == 3)      c = 3;
				else if(v2 == 4) c = 4;
			}
			else if(v1 == 5) {
				if(v2 == 4)      c = 4;
			}
		}
		else if(v0 == 3) {
			if(v1 == 0) {
				if(v2 == 0)      c = 4;
			}
			else if(v1 == 1) {
				if(v2 == 1)      c = 1;
				else if(v2 == 3) c = 0;
				else if(v2 == 4) c = 1;
			}
			else if(v1 == 4) {
				if(v2 == 0)      c = 4;
				else if(v2 == 4) c = 4;
			}
			else if(v1 == 5) {
				if(v2 == 1)      c = 3;
				else if(v2 == 0) c = 5;
				else if(v2 == 3) c = 3;
				else if(v2 == 5) c = 5;
			}
		}
		else if(v0 == 4) {
			if(v1 == 0) {
				if(v2 == 0)      c = 0;
			}
			else if(v1 == 1) {
				if(v2 == 1)      c = 1;
			}
			else if(v1 == 3) 	{
				if(v2 == 0)      c = 4;
				else if(v2 == 4) c = 4;
			}
			else if(v1 == 4) {
				if(v2 == 0)      c = 4;
				else if(v2 == 3) c = 3;
				else if(v2 == 4) c = 4;
				else if(v2 == 5) c = 4;
			}
			else if (v1 == 5) {
				if(v2 == 4)      c = 4;
			}
		}
		else if(v0 == 5) {
			if(v1 == 0) {
				if(v2 == 0)      c = 0;
				else if(v2 == 3) c = 0;
				else if(v2 == 4) c = 0;
				else if(v2 == 5) c = 0;
			}
			else if(v1 == 1) {
				if(v2 == 1)      c = 1;
				else if(v2 == 4) c = 1;
			}
			else if(v1 == 3) {
				if(v2 == 1) 	  c = 5;
				else if(v2 == 5) c = 5;
			}
			else if(v1 == 4) {
				if(v2 == 0) 	  c = 3;
				else if(v2 == 4) c = 5;
			}
			else if(v1 == 5) {
				if(v2 == 0) 	  c = 5;
				else if(v2 == 1) c = 3;
				else if(v2 == 3) c = 3;
				else if(v2 == 5) c = 5;
			}
		}
		return c;
	}
}


