/// This is the tic-tac-toe applet
import java.applet.*;
import java.awt.*;
import java.awt.event.*;
import java.net.*;
import java.io.*;


// Just a simple button with an integer tag
// could have used the ActionCommand, but that's a string
class TagBtn extends Button {
    public int tag;
    TagBtn(String label, int tag)  {
        super(label);
       this.tag=tag;
    }
}


// The applet
public class TicTacToe extends Applet implements ActionListener {
    // arrays for buttons
    public TagBtn [][] btns = new TagBtn[3][3];
    // status message
    public Label lbl;
    // X or O
    public String player;
    // no moves allowed unless this is true
    public volatile boolean mymove=false;
    // my move
    volatile int move;
    int xosize=20;  // size of X and O
    String server;  // remote game host

    public void init() {
        int x;
        int y;
        String tmp;
        // Set X or O size
        tmp=getParameter("XOSize");
        try {
            xosize=Integer.parseInt(tmp);
            if (xosize==0) xosize=20;
        } catch (Exception e) { xosize=20; }
        // Get host name
        server=getParameter("Server");
        // set up GUI
        // The GUI has a border layout that contains a grid layout
        // The status window is south and the grid is north
        BorderLayout main = new BorderLayout();
        setLayout(main);
        Panel tictac = new Panel();
        tictac.setBackground(new Color(0,0,0));
        lbl = new Label("Tic Tac Toe by Al Williams");
        add(tictac,BorderLayout.CENTER);
        // gap of 5 makes the grid show up nicely
        GridLayout ly = new GridLayout(3,3,5,5);
        tictac.setLayout(ly);
        // Init buttons
        for (x=0;x<3;x++) {
            for (y=0;y<3;y++) {
                btns[x][y]=new TagBtn(" ",y*3+x+'0');
                btns[x][y].addActionListener(this);
                btns[x][y].setFont(new Font("Helvtica",Font.BOLD,xosize));
                tictac.add(btns[x][y]);
            }
        }
        add(lbl,BorderLayout.SOUTH);
        // start a thread to do all the network stuff
        new PlayThread(this).start();
    }

    // button press?
    public synchronized void actionPerformed(ActionEvent e) {
        TagBtn b = (TagBtn)e.getSource();
        // no move if not your turn or button has X or O in it already
        if (!mymove || !b.getLabel().equals(" ")) return;
        move=b.tag; // tell the thread
        notify();
        b.setLabel(player);
    }

    // This routine gets the next move... it won't return
    // until the actionPerformed function calls notify
    public synchronized int getMove() throws InterruptedException {
        wait();
        return move;
    }
}


// This is the network thread
class PlayThread extends Thread {
    private TicTacToe host;

    PlayThread(TicTacToe host) { this.host = host; }
    public void run() {
        int c;
        // connect to host
        Socket sock;
        InputStream in;
        OutputStream out;
        try {
            sock=new Socket(host.server,9001);  // port # could be a param
            in = sock.getInputStream();
            out=sock.getOutputStream();
            // this loop waits for our partner to connect
            while (true) {
                c=in.read();
                if (c=='Q') {
                    host.lbl.setText(
                       "Other player quit. Press Refresh for a new game.");
                    return;
                }
                if (c=='X' || c=='O') {
                    host.player=c=='X'?"X":"O";
                    // small flaw... player X hardly gets a
                    // chance to see this message
                    host.lbl.setText("You are " + host.player);
                    break;
                }
                if (c=='W') host.lbl.setText("Waiting....");
            }
            // both players ready to go!
            while (true) {
                c=in.read();
                if (c==-1) continue;  // no input
                if (c=='G') {
                    host.lbl.setText("Game over! Press Refresh.");
                    return;
                }
                if (c=='W') {
                     host.lbl.setText("You win! Press Refresh.");
                     return;
                }
                if (c=='L') {
                     host.lbl.setText("You lose! Press Refresh.");
                     return;
                }
                if (c=='Q') {
                     host.lbl.setText("Other player quit. Press Refresh.");
                     return;
                }
                // My turn?
                if (c=='M') {
                     host.mymove=true;  // enable UI
                     host.lbl.setText("Your turn");
                     int m=host.getMove();  // wait for user to respond
                     host.lbl.setText("");  // disable UI
                     host.mymove=false;
                     // send it
                     out.write(m);
                     continue;
                }
                // hmmm must be a move for opposite player
                c=c-'0';
                host.btns[c%3][c/3].setLabel(
                             host.player.equals("X")?"O":"X");
                } // end while(true);

           } catch (Exception e) { e.printStackTrace(); }
     }
}

