import java.awt.*;
import java.awt.event.*;
import java.net.*;
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
    
    if (args.length==0) parseError();
    if(args[0].equals("-server"))
      if(args.length!=1) parseError();
      else serverStart();
    
    int s=4;
    MyWindow m=new MyWindow(s);
    m.show();
  }
  
  static void parseError() {
    System.out.println("Usage: TicTacToe -server OR TicTacToe host port [-size s]\n"+
		       "See the README for more documentation.");
    System.exit(1);
  }

  static void serverStart() {
    try { ServerSocket ssocket=new ServerSocket(4444);}
    catch (IOException e) { ServerSocket ssocket=new ServerSocket(0);
    println("Error: could not use port 4444; using port "+ssocket.getLocalPort()+" instead."; }

}    

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

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

  public MyWindow(int s) {
    setTitle("TicTacToe");           //Do basic inits
    setLocation(200,200);
    setLayout(new BorderLayout());
    MainListener L=new MainListener();
    addWindowListener(L);
    
    game=new TicTac(s);           //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(); label1.setText(""); }
    }
    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.
      
      String outcome = t.gameEvent(e.getX()/(float)d.width, e.getY()/(float)d.height);
      
      if (outcome=="turn") label1.setText("Illegal move");
      if (outcome=="draw") label1.setText("Draw");
      if (outcome=="1") label1.setText("O wins");
      if (outcome=="2") label1.setText("X wins");
      if (outcome=="ok") label1.setText("");
      repaint();
    }
  }
  
}

class TicTac extends Canvas {         //This is the main TicTacToe board.
  Image grid, x, o;
  int size;                           //The size of the board
  int turn;                           //Whose turn it is
  int finished;                       //The victory flag
  int Board[][];                      //The board
  int lastChangedx;                   //Keeps track of board area needing update.
  int lastChangedy;

  public TicTac(int s) {
    size=s;
    setBackground(Color.white);
    lastChangedx=-1;
    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[size][size];
    for(int i=0;i<size;i++)
      for(int j=0; j<size;j++)
	Board[i][j]=0;
  }

  public void paint(Graphics g) {
    int dx = getSize().width;
    int dy = getSize().height;
    g.setColor(getBackground());
    g.fillRect(0,0,dx-1,dy-1);
    g.setColor(new Color(248,0,248));
    for(int i=0;i<size;i++) {
      g.drawLine(i*dx/size,0,i*dx/size,dy-1);
      g.drawLine(0,i*dy/size,dx-1,i*dy/size);
      for(int j=0; j<size;j++) {
	if(Board[i][j]==1)
	  g.drawImage(o, i*dx/size+2, j*dy/size+2, dx/size-4, dy/size-4, this);
	else if(Board[i][j]==2)
	  g.drawImage(x, i*dx/size+2, j*dy/size+2, dx/size-4, dy/size-4, this);
      }
    }
  }

  public void update(Graphics g) {
    if(lastChangedx==-1) paint(g);
    else {
      int dx = getSize().width;
      int dy = getSize().height;
      if(Board[lastChangedx][lastChangedy]==1)
	g.drawImage(o, lastChangedx*dx/size+2, lastChangedy*dy/size+2, dx/size-4, dy/size-4, this);
      else if(Board[lastChangedx][lastChangedy]==2)
	g.drawImage(x, lastChangedx*dx/size+2, lastChangedy*dy/size+2, dx/size-4, dy/size-4, this);
    } 
  }

  public Dimension getPreferredSize() {
    return new Dimension(60*size,60*size);
  }

  public Dimension getMinimumSize() {
    return new Dimension(5*size,5*size);
  }

  public String gameEvent(float c, float d) { //Do the appropriate event

    int a=(int)(c*size);      //Take coordinates to cell #s
    int b=(int)(d*size);

    if (Board[a][b]==0 && finished==0) {               //A legal move.
      Board[a][b]=turn;                 //Mark the space
      lastChangedx=a;lastChangedy=b;

      int win=0;                        //Victory flag
      boolean utility=true;             //Used in victory checking
      
      for(int i=0; i<size; 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<size; 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<size; i++)
	  if (Board[i][i]!=turn) utility=false;
	if(utility) finished=turn;
      }

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

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

