// (C) Copyright Jack Culpepper 1997
// This code may not be distributed without permission.
package gestalt;

import java.net.*;
import java.io.*;
import java.util.*;
import gestalt.Acceptor;
import gestalt.ThreadLister;
import gestalt.Status;
import gestalt.Coordinator;

public class Server extends Thread {
  static int coupling_number = 0;
  protected ClientAcceptor clientAcceptor;
  protected SlaveAcceptor slaveAcceptor;
  protected StatusAcceptor statusAcceptor;
  protected Coordinator coord;
  protected Vector clients;
  protected Vector slaves;
  protected Vector stati;
  protected Vector servers;
  protected Vector serverNames;
  protected int last_num_slaves;
  protected int last_tasks_pending;

  // exit with an error message when an exception occurs
  public static void fail( String msg ) {
    report( msg );
    System.exit( 1 );
  }

  public static void report( String str ) {
    System.out.println( "Server: " + str );
  }

  // self starting thread
  public Server() {
    // name our thread
    super( "Server" );

    // create vectors
    clients = new Vector();
    slaves = new Vector();
    stati = new Vector();
    servers = new Vector();
    serverNames = new Vector();

    // start listening for status, processors, and task connections
    try {
      clientAcceptor =
        new ClientAcceptor( Constants.clientPort, clients, this );
      slaveAcceptor =
        new SlaveAcceptor( Constants.slavePort, slaves, this );
      statusAcceptor =
        new StatusAcceptor( Constants.statusPort, stati, this );
    }
    catch ( IOException e ) {
      fail( "IOException creating a ServerSocket:" + e );
    }

    // create the coordinator
    coord = new Coordinator( this );

    this.start();
  }

  public void run() {
    while ( true ) {
      report( "Updating the servers we are coupled to..." );
      updateServers();
//      report( "Yawn...  I am going to sleep." );
      try {
        sleep( 60000 );
//        report( "Ahhh...  That was a peaceful slumber." );
      }
      catch ( InterruptedException e ) {
        report( "My!  That was a rude interruption: " + e );
      }
    }
  }

  public void couple( String hostname ) {
    // create a socket to the server
    try {
      report( "Attempting to couple to server: " + hostname );
      Socket s = new Socket( hostname, Constants.clientPort );

      // make a connection out of the socket
      try {
        ThreadGroup threadgroup = new ThreadGroup( "Server-" +
          coupling_number++ );
        Connection c = new Connection( s, threadgroup );

        ServerRecord rec = new ServerRecord( hostname, c );
        servers.addElement( rec );
        report( "New server: " + rec );
      }
      catch ( IOException e ) {
        report( "Coupling failed: IOException creating Connection: " + e );
      }
    }
    catch ( UnknownHostException e ) {
      report( "Coupling failed: Exception: " + e );
    }
    catch ( IOException e2 ) {
      report( "Coupling failed: Exception: " + e2 );
    }
  }

  public void updateServers() {
    synchronized ( serverNames ) {
      for ( int i = 0 ; i < serverNames.size() ; i++ ) {
        String hostname = ( String )serverNames.elementAt( i );
        boolean found = false;
        synchronized ( servers ) {
          for ( int j = 0 ; j < servers.size() ; j++ ) {
            ServerRecord rec = ( ServerRecord )servers.elementAt( j );
            if ( hostname.equals( rec.hostname ) ) {
              found = true;
              break;
            }
          }
        }
        if ( ! found ) couple( hostname );
      }
    }
  }

  public int totalTasksPending() {
    int tasks_pending = 0;

    for ( int i = 0 ; i < clients.size() ; i++ ) {
      ClientRecord rec = ( ClientRecord )clients.elementAt( i );
      tasks_pending += rec.pending.size();
    }

    return tasks_pending;
  }

  public static void main(String[] args) {
    // Start the server up
    if ( args.length != 0  ) {
      System.out.println( "Usage: java Server" );
    }
    else {
      Server s = new Server();
    }
  }
}

