/* IMPORTS */
import java.io.*;
import java.net.*;
import ServerListener;

class ServerConnection extends Thread 
{
    /* CONSTANTS */
    // NONE

    /* MEMBER VARIABLES */
    private Socket connection = null;       // Sever's socket connection
    private boolean active = false;         // Server's active status
    private int server_ID = 0;              // Server's ID
    private String server_name = "";        // Server's name
    private ObjectOutputStream out = null;  // Server's output stream
    private ObjectInputStream in = null;    // Sever's input stream
    private ServerListener s_listener;      // Server's ServerListener
    private String local_server_name;       // Local server's name
    private int local_server_ID;            // Local server's ID

    public ServerConnection(ThreadGroup group, String thread_name, 
                            String local_server_name, 
                            int local_server_ID, Socket socket_connection)
                            throws IOException
    {
        super(group, thread_name);
        this.local_server_name = local_server_name;
        this.local_server_ID = local_server_ID;
        connection = socket_connection;
        
        start(); // Calls run method
    } // constructor
    
    void connect()
    {
        /* LOCAL VARIABLES */
        // NONE
        
        /*PRE-CONDITIONS*/
        if(connection == null || in != null || out != null)
        {
            System.err.println("Invalid conditions. connect() failed.");
            return;
        }
        
        try
        {
            System.out.print("Opening server connection . . . ");

            out = new ObjectOutputStream( connection.getOutputStream() );
            out.flush();
            in = new ObjectInputStream( connection.getInputStream() );

            out.writeObject(local_server_name);
            out.writeInt(local_server_ID);
            
            out.flush();
            
            server_name = (String) in.readObject();
            server_ID = in.readInt();
            
            active = true;
            
            System.out.println("ServerConnection now active for Server '"+server_name+"', ID '"+server_ID+"'.\n");
        } // try
        catch(ClassNotFoundException e)
        {
            System.err.println("ClassNotFoundException has occurred.  The exception was:\n"+
                               e+"\n");
            e.printStackTrace(System.err);
        } // catch exception
        catch(ConnectException e)
        {
            active = false;
            System.err.println("ConnectException has occurred.  The exception was:\n"+
                               e+"\n");
            e.printStackTrace(System.err);
        } // catch exception
        catch(IOException e)
        {
            System.err.println("IOException has occurred.  The exception was:\n"+
                               e+"\n");
            e.printStackTrace(System.err);
        } // catch exception
    } // method connect
    
    public void run()
    {
        /* LOCAL VARIABLES */
        Message received;  // The received Message

        /* INITALIZE CONNECTION */
        connect();

        System.out.println("Waiting for a messages from Server '"+server_name+"'.\n");
        
        while(active)
        {
            try
            {
                  receiveMessage();
            } // try
            catch (EOFException e)
            {
                active = false;
                System.err.println("EOFException has occurred.  The exception was:\n"+
                                   e+"\n");
                e.printStackTrace(System.err);
            } // catch exception
            catch (ClassNotFoundException e)
            {
                System.err.println("ClassNotFoundException has occurred.  The exception was:\n"+
                                   e+"\n");
                e.printStackTrace(System.err);
            } // catch exception
            catch(IOException e)
            {
                active = false;
                System.err.println("IOException has occurred.  The exception was:\n"+
                                   e+"\n");
                e.printStackTrace(System.err);
            } // catch exception
            
            yield();
        } // while
        
        System.out.println("Server '"+server_name+"' is now dead.\n");
        s_listener.cleanup();
    } // method run
    
    public void sendMessage(Message msg) throws IOException
    {
        System.out.println("Message sent to server '"+server_name+"'.");

        if(active)
            out.writeObject(msg);        
        else
            System.out.println("Server ID '"+server_ID+"' was inactive, so the Message ('"+msg+"') could not be sent.");
        
        System.out.println();
    } // method sendMessage

    public void receiveMessage() throws ClassNotFoundException, IOException
    {
        Message received = (Message) in.readObject();

        System.out.println("Message ('"+received+"') received from server '"+server_name+"'");

        if(received.getServerDestID() == -1)        
        {    
             received.setServerDestID(local_server_ID);   
        } // if
        
        if(received.getServerDestID() == local_server_ID)
        {
            /* LOCAL MESSAGE */
            if(s_listener != null) 
                s_listener.handle(received);
            else
                System.out.println("No listener registered for local server.");
        } // if
        else
        {
            /* INTER-SERVER COMMUNICATION */
            // NOTE: THIS NEEDS TO BE FIXED SO THAT IT DOESN'T CAUSE A MESSAGE LOOP!
            //s_listener.send(received.getServerDestID(), received);
        } // else

        System.out.println();
    } // method recieveMessage
    
    public boolean knowServerID(int server_ID)
    {
        // Does this server want messages for the given server_ID?
        if(server_ID == -1)
            return true;
        if(server_ID == this.server_ID)
            return true;
            
        return false;
    } // message knowServerID
    
    public void addServerListener(ServerListener listener)
    {
        s_listener = listener;
    } // method addServerListener
    
    public void removeServerListener(ServerListener listener)
    {
        if(s_listener == listener)
            s_listener = null;
    } // method removeServerListener
} // class ServerConnection
