/* IMPORTS */
import java.io.*;
import java.net.*;
import java.util.*;
import ServerConnection;
import ServerListener;
import Message;

public class ServerServer extends Thread implements ServerListener
{
    /* CONSTANTS */
    // NONE

    /* CLASS MEMBERS */
    ServerSocket SrvSock;     // Server Server's ServerSocket
    ThreadGroup servers;      // Server Server's ThreadGroup
    RoomListener r_listener;  // Server Server's RoomListener
    Set server_set            // Collection of Server Servers
     = Collections.synchronizedSet( new HashSet() );
    int srv_count = 0;        // Count of Server Servers
    // => PROTECTED VARIABLES
    protected String local_server_name;  // Local Server's Name
    protected int local_server_ID;       // Local Server's ID

    public ServerServer(int port, String local_server_name, int local_server_ID )
    {
        this.local_server_name = local_server_name;
        this.local_server_ID = local_server_ID;
        
        try
        {
            SrvSock = new ServerSocket(port);
        } // try
        catch(IOException e)
        {
            System.err.println("IOException has occurred.  The exception was:\n"+
                               e+"\n");
            e.printStackTrace(System.err);
        } // catch exception        
        
        setDaemon(true); // Make this thread a daemon thread

        start(); // Calls run method
    } // constructor

    public void run()
    {
        /* LOCAL VARIABLES */
        Socket s = null;  // Working Socket variable

        servers = new ThreadGroup("ServerConnections");

        while(true)
        {
            try
            {
                s = SrvSock.accept();
                System.out.println("Server socket accepted: "+s);
                add(s);
            } // try
            catch(IOException e1)
            {
                System.err.println("IOException has occurred.  The exception was:\n"+
                                   e1+"\n");
                e1.printStackTrace(System.err);
                try
                {
                    if(s != null)
                        s.close();
                } // try
                catch(IOException e2)
                {
                    System.err.println("IOException has occurred.  The exception was:\n"+
                                       e2+"\n");
                    e2.printStackTrace(System.err);
                } // catch exception               
            } // catch exception
        } // while  
    } // method run

    public synchronized void add(Socket s) throws IOException
    {
        /* LOCAL VARIABLES */
        ServerConnection new_srv; // New ServerConnection
        
        new_srv = new ServerConnection(servers, "port"+srv_count, local_server_name, local_server_ID, s);

        new_srv.addServerListener(this);
        server_set.add(new_srv);

        srv_count+=1;
        System.out.println("ServerConnection '"+new_srv+"' added to list.\n");        
    } // method add

    public void send(int room_id, String msg)
    {
        /* LOCAL VARIABLES */
        // NONE
        
        System.out.println("ServerServer sent a message '"+msg+"' to everyone.\n");
        send( -1, new Message( -1, local_server_ID, room_id, msg) );
    } // method send
     
    public void send(int server_ID, Message msg)
    {
        /* LOCAL VARIABLES */
        Iterator s_list = server_set.iterator(); // Iterator for list of Servers Servers
        ServerConnection temp;                   // Temporary ServerConnection
        
        while( s_list.hasNext() )
        {        
            try
            {
                temp = (ServerConnection) s_list.next();
                if( temp != null && temp.knowServerID(server_ID) )
                {
                    temp.sendMessage(msg);
                } // if
            } // try
            catch(IOException e)
            {
                System.err.println("IOException has occurred.  The exception was:\n"+
                                   e+"\n");
                e.printStackTrace(System.err);
            } // catch exception
        } // while
    } // method send
    
    public void handle(Message msg)
    {
        /* LOCAL VARIABLES */
        // NONE

        if(r_listener != null)
            r_listener.talk( msg.getRoomID(), msg.getMessage() );
        else
            System.out.println("No RoomListener registered, so message ('"+msg+"') was lost.\n");
    } // method handle
   
    public void handle(String cmd)
    {
        /* LOCAL VARIABLES */
        // NONE
        
        System.out.println("Command '"+cmd+"' was sent, but not interpreted.\n");
    } // method handle

    public void addRoomListener(RoomListener listener)
    {
        r_listener = listener;
    } // method addRoomListener
    
    public void removeRoomListener(RoomListener listener)
    {
        if(r_listener == listener);
            r_listener = null;
    } // method removeRoomListener
    
    public void status()
    {
        /* LOCAL VARIABLES */
        Iterator s_list;  // Iterator for list of Servers Servers

        System.out.println("Status of Server Server:\n"+
                           " -> There are "+servers.activeCount()+" Servers that are connected and alive.\n"+
                           " -> There are "+server_set.size()+" ServerConnections in the list.");
        
        s_list = server_set.iterator();
        while( s_list.hasNext() )
        {
            System.out.println("    * "+s_list.next());
        } // while
        
        System.out.println();
    } // method status
    
    public void cleanup()
    {
        /* LOCAL VARIABLES */
        Iterator s_list;        // Iterator for list of Servers Servers
        ServerConnection temp;  // Temporary ServerConnection
        
        s_list = server_set.iterator();
        
        while( s_list.hasNext() )
        {
             temp = (ServerConnection) s_list.next();
             if( temp != null && !temp.isAlive() )
                 s_list.remove();
        } // while
    } // method cleanup
} // class ServerServer
