package ttaomae.connectn.network.client;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Scanner;

import ttaomae.connectn.Board;
import ttaomae.connectn.Piece;
import ttaomae.connectn.Player;
import ttaomae.connectn.network.ConnectNProtocol;

// TODO: add constructor with board parameters
public class Client implements Runnable
{
    private Socket socket;
    private PrintWriter socketOut;
    private BufferedReader socketIn;

    private Player player;
    /** This client's copy of the board */
    private Board board;

    public Client(String hostname, int portNumber, Player player, Board board)
            throws UnknownHostException, IOException
    {
        this.socket = new Socket(hostname, portNumber);
        this.socketOut = new PrintWriter(socket.getOutputStream(), true);
        this.socketIn = new BufferedReader(new InputStreamReader(socket.getInputStream()));

        this.player = player;
        this.board = board;
    }

    @Override
    public void run()
    {
        boolean rematch = true;
        while (rematch) {
            try {
                // expecting start message from server
                // if not, something went wrong so quit
                if (!socketIn.readLine().equals(ConnectNProtocol.START)) {
                    break;
                }

                // make sure the board is empty by undoing everything
                // TODO: kind of hack-y. must ensure that the panel and client have the same board
                while (this.board.undoPlay());


                System.out.println("CLIENT: Starting game");
                playGame();

                String message = socketIn.readLine();
                if (message.equals(ConnectNProtocol.REMATCH)) {
                    rematch = getRematch();
                }

                // expecting rematch message from server
                // if not, something went wrong so quit
                else {
                    break;
                }
            } catch (IOException e) {
                System.err.println("Error reading from socket.");
                break;
            }
        }
        System.out.println("CLIENT: Done!");
    }

    private void playGame() throws IOException
    {
        while (this.board.getWinner() == Piece.NONE) {
            // get message from server
            String message = this.socketIn.readLine();

            // server is waiting for move
            if (message.equals(ConnectNProtocol.READY)) {
                // get a move and play it
                int move = -1;
                while (!this.board.isValidMove(move)) {
                    move = player.getMove(this.board.copy());
                }
                this.board.play(move);

                this.socketOut.println(ConnectNProtocol.constructMove(move));
            }
            // server sent opponent move
            else if (ConnectNProtocol.verifyMove(message)) {
                // play opponent's move
                this.board.play(ConnectNProtocol.parseMove(message));
            }
        }

        System.out.println(this.board.getWinner() + " wins!");
    }

    private boolean getRematch() throws IOException
    {
        // get input from user
        // TODO: very hack-y
        System.out.println("Type 'y' for a rematch.");
        if (new Scanner(System.in).nextLine().equals("y")) {
            socketOut.println(ConnectNProtocol.YES);
            // wait for server response; rematch if opponent agrees
            return socketIn.readLine().equals(ConnectNProtocol.YES);

        }
        else {
            socketOut.println(ConnectNProtocol.NO);
            return false;
        }
    }
}

@@ -210,32 +210,83 @@
 nHostException;%0A
+import java.util.ArrayList;%0Aimport java.util.List;%0A
 import java.util
@@ -726,16 +726,61 @@
 board;%0A%0A
+    private List%3CClientListener%3E listeners;%0A%0A
     publ
@@ -1189,16 +1189,61 @@
 = board;
+%0A%0A        this.listeners = new ArrayList%3C%3E();
 %0A    %7D%0A%0A
@@ -1492,33 +1492,41 @@
    if (!
-socketIn.readLine
+this.getMessageFromServer
 ().equal
@@ -1941,33 +1941,41 @@
 ssage = 
-socketIn.readLine
+this.getMessageFromServer
 ();%0A    
@@ -2662,33 +2662,36 @@
  = this.
-socketIn.readLine
+getMessageFromServer
 ();%0A%0A   
@@ -3058,32 +3058,34 @@
   this.s
-ocketOut.println
+endMessageToServer
 (Connect
@@ -3683,33 +3683,40 @@
         
-socketOut.println
+this.sendMessageToServer
 (Connect
@@ -3822,25 +3822,33 @@
 urn 
-socketIn.readLine
+this.getMessageFromServer
 ().e
@@ -3876,17 +3876,16 @@
 l.YES);%0A
-%0A
         
@@ -3917,60 +3917,616 @@
     
-socketOut.println(ConnectNProtocol.NO);
+this.sendMessageToServer(ConnectNProtocol.NO);%0A            return false;%0A        %7D%0A    %7D%0A%0A    private String getMessageFromServer() throws IOException%0A    %7B%0A        String result = this.socketIn.readLine();%0A        this.notifyListeners(true, result);%0A%0A        return result;%0A    %7D%0A%0A    private void sendMessageToServer(String message)%0A    %7B%0A        this.socketOut.println(message);%0A        this.notifyListeners(false, message);%0A    %7D%0A%0A    public void addListener(ClientListener cl)%0A    %7B%0A        this.listeners.add(cl);%0A    %7D%0A%0A    private void notifyListeners(boolean received, String message)
 %0A    
+%7B%0A
         
 retu
@@ -4517,37 +4517,307 @@
   %7B%0A        
-return false;
+for (ClientListener cl : this.listeners) %7B%0A            if (cl != null) %7B%0A                if (received) %7B%0A                    cl.clientReceivedMessage(message);%0A                %7D%0A                else %7B%0A                    cl.clientSentMessage(message);%0A                %7D%0A            %7D
 %0A        %7D%0A 

update Client to notify listeners