//Ali Soleimani
//This program 1)runs as an applet OR application, and 2) uses custom board graphics 

import java.awt.*;
import java.awt.event.*;
import java.applet.Applet;

public class tic extends Applet {     //A class just to startup the main window.

  public static void main(String[] args) {   //When an application
    System.out.println("This program also 1)runs as an applet, and 2)uses custom board graphics");
    MyWindow m=new MyWindow();
    m.show();
  }

  public void init() {   //We're in an applet

    setLayout(new BorderLayout());
    Image a,b,c;
    a=getImage(getCodeBase(), "x.gif");
    b=getImage(getCodeBase(), "o.gif");
    c=getImage(getCodeBase(), "grid.gif");
    TicTac game=new TicTac(a, b, c);           //Make panel & tictactoe canvas
    Panel bottom=new Panel();
    add("Center", game);
    add("South", bottom);
    
    bottom.setLayout(new BorderLayout());   //Our button panel.
    Button b1=new Button("Restart");
    Label label1=new Label(""); 
    label1.setAlignment(Label.CENTER);
    b1.addActionListener(new AppletListener(game));       //this window will handle button events
    game.addMouseListener(new AppletGameListener(label1));  //Add a mouse listener for the game.

    bottom.add("West",b1);
    bottom.add("Center", label1);
    repaint();
  }
  
  //This class handles events for the main window:
  class AppletListener implements  ActionListener {
    TicTac game;
    AppletListener(TicTac g) {
      game=g;
    }
    public void actionPerformed(ActionEvent e) {
      String cmd = e.getActionCommand();
      if(cmd=="Restart") game.reset();
    } 
  } 

  //This class handles clicks, etc. for the game, generating the appropriate function calls.
  //It catches win/lose/etc. 
  class AppletGameListener extends MouseAdapter implements MouseListener {
    Label label1;
    AppletGameListener(Label l) {
      super();
      label1=l;
    }
    public void mouseClicked(MouseEvent e) {
      TicTac t = (TicTac)e.getComponent();
      Dimension d = t.getSize();   //Get the dim of the board.

      try {t.gameEvent(e.getX()*3/d.width, e.getY()*3/d.height);}

      catch (GameException err) {
      if (err.getMessage()=="turn") label1.setText("Illegal move");
      if (err.getMessage()=="draw") label1.setText("Draw");
      if (err.getMessage()=="1") label1.setText("O wins");
      if (err.getMessage()=="2") label1.setText("X wins");
      repaint();
      }
    }
  }
  
}    

class MyWindow extends Frame {  //The main program window.

  TicTac game;                 //Our data members--the two subframes.
  Panel bottom;
  MainListener L;
  Label label1;

  public MyWindow() {
    setTitle("TicTacToe");           //Do basic inits
    setLocation(200,200);
    setLayout(new BorderLayout());
    MainListener L=new MainListener();
    addWindowListener(L);
    
    game=new TicTac();           //Make panel & tictactoe canvas
    bottom=new Panel();
    add("Center", game);
    add("South", bottom);

    game.addMouseListener(new GameListener());  //Add a mouse listener for the game.
    
    bottom.setLayout(new BorderLayout());   //Our button panel.
    Button b1=new Button("Restart");
    Button b2=new Button("Quit");
    label1=new Label("");
    label1.setAlignment(Label.CENTER);
    b1.addActionListener(L);       //this window will handle button events
    b2.addActionListener(L);
    bottom.add("West",b1);
    bottom.add("Center", label1);
    bottom.add("East",b2);
    pack();
  }

  //This class handles events for the main window:
  class MainListener extends WindowAdapter implements WindowListener, ActionListener {
    public void actionPerformed(ActionEvent e) {
      String cmd = e.getActionCommand();
      if(cmd=="Quit") System.exit(1);
      if(cmd=="Restart") game.reset();
    }
    public void windowClosing(WindowEvent e) {
      System.exit(1);
    } 
  } 

  //This class handles clicks, etc. for the game, generating the appropriate function calls.
  //It catches win/lose/etc. 
  class GameListener extends MouseAdapter implements MouseListener {
    public void mouseClicked(MouseEvent e) {
      TicTac t = (TicTac)e.getComponent();
      Dimension d = t.getSize();   //Get the dim of the board.

      try {t.gameEvent(e.getX()*3/d.width, e.getY()*3/d.height);}

      catch (GameException err) {
      if (err.getMessage()=="turn") label1.setText("Illegal move");
      if (err.getMessage()=="draw") label1.setText("Draw");
      if (err.getMessage()=="1") label1.setText("O wins");
      if (err.getMessage()=="2") label1.setText("X wins");
      repaint();
      }
    }
  }

}

class TicTac extends Canvas {          //This is the main TicTacToe board.
  Image grid, x, o;
  int turn;                          //Whose turn it is
  int finished;                      //The victory flag
  int Board[][];                     //The board

  public TicTac() {
    Toolkit kit = Toolkit.getDefaultToolkit();   //Get the images from disk...
    x = kit.getImage("x.gif");
    o = kit.getImage("o.gif");
    grid=kit.getImage("grid.gif");
    turn=1;                             //Random init stuff
    finished=0;
    Board=new int[3][3];
    for(int i=0;i<=2;i++)
      for(int j=0; j<=2;j++)
	Board[i][j]=0;
  }
  public TicTac(Image a, Image b, Image c) {  //Used in applet
    x=a;
    o=b;
    grid=c;
    turn=1;                             //Random init stuff
    finished=0;
    Board=new int[3][3];
    for(int i=0;i<=2;i++)
      for(int j=0; j<=2;j++)
	Board[i][j]=0;
  }

  public void paint(Graphics g) {
    int dx = getSize().width;
    int dy = getSize().height;
    g.drawImage(grid, 0,0, dx-1, dy-1,this);
    for(int i=0;i<=2;i++)
      for(int j=0; j<=2;j++)
	if(Board[i][j]==1)
	  g.drawImage(o, i*103*dx/300, j*103*dy/300, 30*dx/100, 30*dy/100, this);
	else if(Board[i][j]==2)
	  g.drawImage(x, i*103*dx/300, j*103*dy/300, 30*dx/100, 30*dy/100, this);
  }

  public Dimension getPreferredSize() {
    return new Dimension(200,200);
  }

  public Dimension getMinimumSize() {
    return new Dimension(10,10);
  }

  public void gameEvent(int a, int b) throws GameException { //Do the appropriate event
    if (Board[a][b]==0 && finished==0) {               //A legal move.
      Board[a][b]=turn;                 //Mark the space

      int win=0;                        //Victory flag
      boolean utility=true;             //Used in victory checking

      for(int i=0; i<=2; i++)           //Check row victory
	if(Board[i][b]!=turn) utility=false;
      if(utility) finished=turn;

      utility=true;                     //Check column victory
      for(int j=0; j<=2; j++)
	if (Board[a][j]!=turn) utility=false;
      if(utility) finished=turn;
      
      utility=true;                     //Check forward diagonal victory
      if(a==b) {
	for(int i=0; i<=2; i++)
	  if (Board[i][i]!=turn) utility=false;
	if(utility) finished=turn;
      }

      utility=true;                     //Check backward diagonal victory
      if(a==2-b || b==2-a) {
	for(int i=0; i<=2; i++)
	  if (Board[i][2-i]!=turn) utility=false;
	if(utility) finished=turn;
      }

      utility=true;
      if(finished==0) {                //Now we check for stalemate
	for(int i=0;i<=2;i++)
	  for(int j=0; j<=2;j++)
	    if(Board[i][j]==0) utility=false;
	if(utility) throw new GameException("draw");
      }
      repaint();
      if (finished==1) throw new GameException("1");
      if (finished==2) throw new GameException("2");
      if(turn==1) turn=2; else turn=1;  //Switch turns
    }
    else throw new GameException("turn");  //Throws a turn exception.
  }
  
  void reset() {
    finished=0;
    turn=1;
    for(int i=0;i<=2;i++)
      for(int j=0; j<=2;j++)
	Board[i][j]=0;
    repaint();
  }
  
}

class GameException extends Throwable {   //Our game exceptions
  public GameException(String s) {super(s);}
}

