//
// TicTacToe.java: distributed tic tac toe game
//

import java.rmi.*;
import java.rmi.server.*; // added to support callbacks
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.io.*;

public class TicTacToe extends JFrame
   implements ActionListener, TTTClientRemote
{ 
   protected JButton[][] squares;
   protected JLabel statusLabel = new JLabel();

   protected TTTService remoteTTTBoard;

   public TicTacToe()
   {
      super("Tic Tac Toe, Distributed");
      setSize(650, 400); // larger than needed; resizing done below

      // set up the remote service
      try
      {
         System.out.println("Connecting...");
         String serverObjectName = "rmi://"
            + TTTServiceImpl.ServiceHost + ":"
            + TTTServiceImpl.ServicePort + "/"
            + TTTServiceImpl.ServiceName;
         remoteTTTBoard = (TTTService)Naming.lookup(serverObjectName);
         //
         // allow the server to call updateBoard:
         //
         UnicastRemoteObject.exportObject(this, TTTServiceImpl.ServicePort);
         remoteTTTBoard.register(this);
      }
      catch ( Exception e )
      {
         System.out.println("Exception: " + e.getMessage());
         e.printStackTrace();
         return;
      }

      // a bit of magic to halt the application if the user closes the window
      addWindowListener(
         new WindowAdapter() {
         public void windowClosing(WindowEvent event) { System.exit(0); }
         });

      // main box; everything placed in this
      JPanel box = new JPanel();
      box.setLayout(new BoxLayout(box, BoxLayout.Y_AXIS));
      getContentPane().add(box);

      box.add(statusLabel, BorderLayout.NORTH);

      // set up the x's and o's
      JPanel xs_and_os = new JPanel();
      xs_and_os.setLayout(new GridLayout(3, 3, 5, 5));
      box.add(xs_and_os);

      squares = new JButton[3][3];
      for(int row = 0; row < 3; ++row)
      {
         for(int col = 0; col < 3; ++col)
         {
            squares[row][col] = new JButton();
            xs_and_os.add(squares[row][col]);
            squares[row][col].addActionListener(this);
         }
      }

      resetBoard();
      
      // resize frame
      pack();
      setSize(300, 300);
   }

   protected void resetBoard()
   {
      for(int row = 0; row < 3; ++row)
         for(int col = 0; col < 3; ++col)
            squares[row][col].setText(" ");
      try
      {
         remoteTTTBoard.reset();
      }
      catch ( RemoteException e )
      {
         System.out.println("Exception: " + e.getMessage());
         e.printStackTrace();
         System.exit(1);
      }
      setStatus(getBoard());
   }

   protected void setStatus(TTTBoard bd)
   {
      char w = bd.winner();
      if ( w == ' ' )
         statusLabel.setText("Click on " + bd.turn() + " square");
      else
         statusLabel.setText("Winner: " + w);
   }

   protected TTTBoard getBoard()
   {
      TTTBoard res = null;
      try
      {
         res = remoteTTTBoard.getState();
      }
      catch ( RemoteException e )
      {
         System.out.println("Exception: " + e.getMessage());
         e.printStackTrace();
         System.exit(1);
      }
      return res;
   }

   protected void pickSquare(int col, int row)
   {
      try
      {
         remoteTTTBoard.pick(col, row);
      }
      catch ( RemoteException e )
      {
         System.out.println("Exception: " + e.getMessage());
         e.printStackTrace();
         System.exit(1);
      }
   }

   // method "called" by remote object to update the state of the game
   public void updateBoard(TTTBoard new_board) throws RemoteException
   {
      for(int row = 0; row < 3; ++row)
         for(int col = 0; col < 3; ++col)
            squares[row][col].setText(new_board.ownerStr(col, row));
      setStatus(new_board);
   }

   public void actionPerformed(ActionEvent event)
   {
      TTTBoard bd = getBoard();

      for(int row = 0; row < 3; ++row)
         for(int col = 0; col < 3; ++col)
            if ( event.getSource() == squares[row][col] )
            {
               if ( bd.isOpen(col, row) )
               {
                  pickSquare(col, row);
                  bd = getBoard();
                  squares[row][col].setText(bd.ownerStr(col, row));
                  setStatus(bd);
               }
               return;
            }
   }
   
   public static void main(String[] args)
   {
      TicTacToe bd = new TicTacToe();
      bd.setVisible(true);
   }
}
