/***********************************************************************

GECCO, a platform for command and control gaming

Copyright (C) 2001 Henrik Bäärnhielm, Andreas Enblom, Niklas
Hallenfur, Karl Hasselström, Henrik Hägerström, Oskar Linde, Jing Fu
Zi and Jon Åslund

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or (at
your option) any later version.

This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
USA.

***********************************************************************/

package gecco.communication.server;
import gecco.client.Action;
import gecco.communication.messages.*;
import gecco.communication.server.*;
import gecco.server.core.ActionDefinition;
import gecco.server.core.Server;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.image.BufferedImage;

import java.io.*;
import java.util.*;

/**
 *  a class that sends messages from the server, in the send queue
 *
 * @author     Niklas Hallenfur, Henrik Hägerström, Jon Åslund
 * @created    June 27, 2001
 */
public class DataInputExchangeHandler implements Runnable {

    /**
     *  Description of the Field
     */
    private ClientConnection connection;
    /**
     *  Description of the Field
     */
    private Server server;
    /**
     *  Description of the Field
     */
    private ClientConnectionHandler i_am_working_for;
    /**
     *  Description of the Field
     */
    private boolean disconnect;
    /**
     *  Description of the Field
     */
    private DataOutputExchangeHandler DEHOutput;


    /**
     *  Constructor for the DataInputExchangeHandler object
     *
     * @param  cc         Description of Parameter
     * @param  se         Description of Parameter
     * @param  cch        Description of Parameter
     * @param  outputDEH  Description of Parameter
     */
    public DataInputExchangeHandler(ClientConnection cc,
            Server se,
            ClientConnectionHandler cch,
            DataOutputExchangeHandler outputDEH) {
        connection = cc;
        server = se;
        i_am_working_for = cch;
        disconnect = false;
        DEHOutput = outputDEH;
    }


    /**
     *  gets a message from the client that tells the server that a unit wants
     *  to perform an action with no target
     *
     * @exception  Exception  Description of Exception
     */
    public void getActionOnVoid() throws Exception {
        try {
            long id = connection.getDataInputStream().readLong();
            int piece = connection.getDataInputStream().readInt();
            String type = connection.getDataInputStream().readUTF();
            server.actionOnVoid(connection.getRole(), id, piece, type);
        } catch (Exception e) {
            throw e;
        }
    }




    /**
     *  gets a message from the client that tells the server that a unit wants
     *  to perform an action with a unit as target
     *
     * @exception  Exception  Description of Exception
     */
    public void getActionOnUnit() throws Exception {
        try {
            long id = connection.getDataInputStream().readLong();
            int piece = connection.getDataInputStream().readInt();
            String type = connection.getDataInputStream().readUTF();
            int target = connection.getDataInputStream().readInt();

            server.actionOnUnit(connection.getRole(), id, piece, type, target);
        } catch (Exception e) {
            throw e;
        }
    }


    /**
     *  gets a message from the client that tells the server that a unit wants
     *  to perform an action with a position as target
     *
     * @exception  Exception  Description of Exception
     */
    public void getActionOnPosition() throws Exception {
        try {
            long id = connection.getDataInputStream().readLong();
            int piece = connection.getDataInputStream().readInt();
            String type = connection.getDataInputStream().readUTF();
            double x = connection.getDataInputStream().readDouble();
            double y = connection.getDataInputStream().readDouble();

            server.actionOnPosition(connection.getRole(), id, piece, type, x, y);
        } catch (Exception e) {
            throw e;
        }
    }


    /**
     *  gets a message from the client that tells the server that a unit wants
     *  to abort an action
     *
     * @exception  Exception  Description of Exception
     */
    public void getAbortAction() throws Exception {
        long id = connection.getDataInputStream().readLong();
        server.abortAction(connection.getRole(), id);
    }


    /**
     *  Main processing method for the DataInputExchangeHandler object
     */
    public void run() {
        while (!disconnect) {
            try {
                /*
                 * Blocking read int
                 */
                int leadingInteger = connection.getDataInputStream().readInt();
                /*
                 * Receive the rest of the message
                 */
                receiveMessage(leadingInteger);
            } catch (Exception e) {
                i_am_working_for.connectionLost(connection.getRole(),
                        connection.getId());
                break;
            }
            // Yield to other threads!
            Thread.yield();
        }
    }



    /**
     *  called when the client says it wants to abort the game or disconnect
     */
    public void abortGame() {
        i_am_working_for.connectionLost(connection.getRole(),
                connection.getId());
    }


    /**
     *  called whenever someone wants this Thread to die
     */
    public void kill() {
        disconnect = true;
    }


    /**
     *  Gets the StartGame attribute of the DataInputExchangeHandler object
     *
     * @exception  Exception  Description of Exception
     */
    private void getStartGame() throws Exception {
        server.startGame(connection.getRole());
    }


    /**
     *  Called when there is a message to be received in the InputStream from
     *  the client
     *
     * @param  leadingInteger  Description of Parameter
     */
    private void receiveMessage(int leadingInteger) {
        try {
            int type = leadingInteger;
            switch (type) {
                case MessageType.PingReply:
                    acknowledgePingReply();
                    break;
                case MessageType.abortGame:
                    abortGame();
                    break;
                case MessageType.ActionOnVoid:
                    getActionOnVoid();
                    break;
                case MessageType.ActionOnUnit:
                    getActionOnUnit();
                    break;
                case MessageType.ActionOnPosition:
                    getActionOnPosition();
                    break;
                case MessageType.abortAction:
                    getAbortAction();
                    break;
                case MessageType.startGame:
                    getStartGame();
                    break;
            }

        } catch (Exception e) {
            i_am_working_for.connectionLost(connection.getRole(),
                    connection.getId());
        }
    }


    /**
     *  Description of the Method
     *
     * @exception  Exception  Description of Exception
     */
    private void acknowledgePingReply() throws Exception {
        synchronized (DEHOutput.pingSyncObject) {
            DEHOutput.pingSyncObject.notifyAll();
        }
    }

}
