import java.awt.event.*;
import java.util.*;
import java.awt.*;
import java.io.*;
import java.net.*;

/**
 *
 * CommServer
 * <BR><BR>
 * Uniwersalny serwer komunikacyjny dla Flasha.  Wszystkie wysylane i nadsylane wiadomosci
 * sa (musza byc) zakonczone znakiem null ('\0') — w ten sposob komunikuje się obiekt XMLSocket
 * Flasha.  Dowolny inny klient korzystajacy z takiego protokolu rowniez powinien dzialac.
 * <BR><BR>
 * Serwer przyjmuje wiadomosci od podlaczonych klientow i rozsyla je (w niezmienionej postaci)
 * do wszystkich podlaczonych klientow. Gdy klienci podlaczaja sie lub rozłaczaja
 * serwer wysyla rowniez liczbe klientow wewnatrz elementu NUMCLIENTS.
 *
 * Skladnia: java CommServer [port]
 *
 * @author  Derek Clayton   derek_clayton@iceinc.com
 * @version 1.0.1
 */

public class CommServer {
    private Vector clients = new Vector();  // lista wszystkich klientow podlaczonych
    ServerSocket server;                    // do serwera

    /**
     * Konstruktor obiektu CommServer.  Rozpoczyna proces uruchamiania serwera.
     * @param   port   Numer portu, na ktorym serwer powinien nasluchiwac polaczen.
    */
    public CommServer(int port) {
        startServer(port);
    }

    /**
     * Uruchomienie serwera i nasluchiwanie polaczen.
     * @param   port   Numer portu, na ktorym serwer powinien nasluchiwac polaczen.
    */
    private void startServer(int port) {
        writeActivity("Attempting to Start Server");

        try {
            // --- utworz nowy serwer
            server = new ServerSocket(port);
            writeActivity("Server Started on Port: " + port);
            // --- gdy serwer jest aktywny...
            while(true) {
                // --- ...nasluchuj polaczen nowych klientow
                Socket socket = server.accept();
                CSClient client = new CSClient(this, socket);
                writeActivity(client.getIP() + " connected to the server.");
                // --- dodaj nowego klienta do listy klientow
                clients.addElement(client);
                // --- rozpocznij watek klienta
                client.start();
                // --- rozeslij wiadomosc o nowej liczbie klientow
                broadcastMessage("<NUMCLIENTS>" + clients.size()
                               + "</NUMCLIENTS>");
            }
        } catch(IOException ioe) {
            writeActivity("Server Error...Stopping Server");
            // zakoncz dzialanie serwera
            killServer();
        }
    }

    /**
     * Rozsylanie wiadomosci do wszystkich podlaczonych klientow.  Wiadomosci są zakonczone
     * znakiem null.
     * @param   message    Rozsylana wiadomosc.
    */
    public synchronized void broadcastMessage(String message) {
        // --- umiesc znak null na koncu wiadomosci
        message += '\0';

        // --- przejdz wszystkich klientow i kazdemu wyslij wiadomosc
        Enumeration enum = clients.elements();
        while (enum.hasMoreElements()) {
            CSClient client = (CSClient)enum.nextElement();
            client.send(message);
        }

    }

    /**
     * Usuwanie klientow z listy klientow.
     * @param   client    CSClient przeznaczony do usuniecia.
    */
    public void removeClient(CSClient client) {
        writeActivity(client.getIP() + " has left the server.");

        // --- usun klienta z listy
        clients.removeElement(client);

        // --- rozeslij nowa liczbe klientow
        broadcastMessage("<NUMCLIENTS>" + clients.size() + "</NUMCLIENTS>");
    }

    /**
     * Zapisanie wiadomosci w System.out.println w formacie
     * [mm/dd/yy hh:mm:ss] wiadomosc.
     * @param   activity    Wiadomosc.
    */
    public void writeActivity(String activity) {
        // --- odczytaj aktualna date i czas
        Calendar cal = Calendar.getInstance();
        activity = "[" + cal.get(Calendar.MONTH)
                 + "/" + cal.get(Calendar.DAY_OF_MONTH)
                 + "/" + cal.get(Calendar.YEAR)
                 + " "
                 + cal.get(Calendar.HOUR_OF_DAY)
                 + ":" + cal.get(Calendar.MINUTE)
                 + ":" + cal.get(Calendar.SECOND)
                 + "] " + activity + "\n";

        // --- wyswietl wartosc activity
        System.out.print(activity);
    }

    /**
     * Zatrzymanie serwera.
    */
    private void killServer() {
        try {
            // --- zatrzymaj serwer
            server.close();
            writeActivity("Server Stopped");
        } catch (IOException ioe) {
            writeActivity("Error while stopping Server");
        }
    }

    public static void main(String args[]) {
        // --- gdy prawidlowa liczba argumentow
        if(args.length == 1) {
            CommServer myCS = new CommServer(Integer.parseInt(args[0]));
        } else {
        // w przeciwnym razie wyswietl informacje o skladni
            System.out.println("Skladnia: java CommServer [port]");
        }
    }
}
