//     $Id: ServerEngine.java,v 3.8 1998/12/11 17:09:53 smg9c Exp $     /////////////////////////////////////////////////////////////////////
 //
 // File: ServerEngine.java
 //
 // Purpose: The ServerEngine class is responsible for manipulating the
 //          master map and sending it out to the clients.
 //
 // Authors: Steve Geist smg9c@cs.virginia.edu
 // 
 // Modifications:
 //
 //
 //   11-DEC-1998 smg  Added shut down method
 //
 //   08-DEC-1998 smg  Modified to take port on command line
 //
 //   08-DEC-1998 smg  Changed to work with one thread per stabilization loop.
 //
 //   04-DEC-1998 smg  Changes made to run with auto and manual modes.
 //
 //   01-DEC-1998 smg  Added automatic destabilization option
 //
 //   19-NOV-1998 smg  Added Error method to pass exceptions up to Server for
 //                    a stack trace
 //
 //   17-NOV-1998 smg  Added second thread to send initial map, added delay
 //                    and propagation_method variables, added functionality
 //                    to deal with demon engine and updating of new variables
 //
 //   09-NOV-1998 smg  Code review changes made
 //
 //   09-NOV-1998 smg  Cleaned up for use with ServerThread
 //
 //   06-NOV-1998 rgb  Added version control header info
 //
 //   05-NOV-1998 smg  Made program structure more event driven
 //
 //   04-NOV-1998 smg  Added comments, FileMgr renaming
 //
 //   01-NOV-1998 smg  Initial creation
 //
 /////////////////////////////////////////////////////////////////////
 import java.io.*;
 import java.lang.*;
 public class ServerEngine {
   private int num_clients;                // Number of clients
   private Map map;                        // Server's master copy of the map
   private Server server;                  // Gives access to output
   private ServerRMI server_rmi;           // Access to RMI
   private static final int BUFFER_SIZE = 2048;  // Buffer size used for the
                                                 // DataOutputStream
   private DataInputStream dis;            // Used to read in the map
   private long delay;                     // Indicates the delay in 
                                           // milliseconds for sending out
                                           // modified maps  
   private int propagation_method;         // Indicates the method to be used
                                           // for propagation of unstable nodes
   private boolean all_clients_reported;   // Indicates whether all clients have
                                           // reported their changes for the
                                           // current iteration
   private boolean demon_reported;         // Indicates whether the demon has
                                           // reported the delay and prop. 
                                           // method for the current iteration
   private ServerThread compute_engine;    // Thread that does all stabilization
                                           // computations
   private int mode;                       // Indicates auto or manual mode
   private int iterations;                 // Indicates how many iterations to
                                           // run in auto mode 
   private final int automatic_mode = 0;   // Auto mode
   private final int manual_mode = 1;      // Manual mode
   private boolean thread_running;         // Inidicates whether the computation
                                           // thread is currently running
   ///////////////////////////////////////////////////////////////////
   //
   // Method:  ServerEngine  [constructor]
   //
   // Purpose: Creates a new ServerEngine and reads the file indicated by
   //          file_name into a Map.  The Server is necessary for callbacks.
   // 
   ///////////////////////////////////////////////////////////////////
   public ServerEngine(Server s, String file_name, int port) {
     server = s;
     try {
       ReadMap(file_name);
     }
     catch (Exception e) {
       Error(e);
       return;
     }
     num_clients = map.GetNumModules();
     try {
       server_rmi = new ServerRMI(this, port, num_clients);
     }
     catch(Exception e) {
       Error(e);
     }
     delay = 5000;                     // Default value
     propagation_method = 1;           // Default value
     all_clients_reported = false;
     demon_reported = false;
     compute_engine = new ServerThread(server_rmi, this);
   }
   ///////////////////////////////////////////////////////////////////
   //
   // Method:  ReadMap
   //
   // Purpose: Reads in the file named with the String file_name and
   //          converts it to a map.
   //
   ///////////////////////////////////////////////////////////////////
   public void ReadMap(String file_name)
   throws MapReadException {
     if(file_name.length() == 0) {
       PrintMessage("Input file name is invalid");
       return;
     }
     try {
       dis = new DataInputStream(
         new BufferedInputStream(
             new FileInputStream(file_name)));
     }
     catch (Exception e) {
       throw new MapReadException();
     }
     try {
       String data = dis.readLine();
       map = new Map(data);
       map.Validate();
       map.SetFinal(true);
       map.SetEditable(false);
     }
     catch (Exception e) {
       throw new MapReadException();
     }
   }
   ///////////////////////////////////////////////////////////////////
   //
   // Method:  UpdateMap
   //
   // Invoker: ServerRMI
   //
   // Purpose: UpdateMap copies the values in the module passed in to the 
   //          corresponding module in the server's copy of the map. 
   //   
   ///////////////////////////////////////////////////////////////////
   public void UpdateMap(Module m, int client_id) {
     if(! thread_running) {
       try {
     Module old_module = map.GetModule(client_id);
     int num_nodes = m.GetNumNodes();
     Node new_node, old_node;
     for(int i=0; i<num_nodes; i++) {
       new_node = m.GetNode(i);
       old_node = old_module.GetNode(i);
       old_node.SetStable(new_node.IsStable());
       old_node.SetRecovery(new_node.GetRecovery());
     }
       }
       catch (Exception e) {
     Error(e);
       }
     }
   }
   ///////////////////////////////////////////////////////////////////
   //
   // Method:  BeginSimulation
   //
   // Invoker: ServerRMI
   //
   // Purpose: BeginSimulation copies the passed values for propagation 
   //          method and delay into the corresponding member variables
   //          and then starts the thread that propagates the instabilities.
   //   
   ///////////////////////////////////////////////////////////////////
   public void BeginSimulation(int p, long d) {
     delay = d;
     propagation_method = p;
     map.SetEditable(false);
     map.SetFinal(false);
     thread_running = true;
     compute_engine = new ServerThread(server_rmi, this);
     compute_engine.start();
   }
   ///////////////////////////////////////////////////////////////////
   //
   // Method:  SubmitMode
   //
   // Invoker: ServerRMI
   //
   // Purpose: SubmitMode sets the mode and iterations variables to the
   //          passed values.  If the mode is manual, the iterations variable
   //          is set to 1 by default.
   //   
   ///////////////////////////////////////////////////////////////////
   public boolean SubmitMode(int m, int runs) {
     mode = m;
     if(mode == manual_mode) {
       iterations = 1;
       map.SetEditable(true);
     }
     else {
       iterations = runs;
     }
     return true;
   }
   ///////////////////////////////////////////////////////////////////
   //
   // Method:  PrintMessage
   //
   // Invoker: ServerRMI, ServerThread
   //
   // Purpose: PrintMessage prints a message to the screen via the server.
   //   
   ///////////////////////////////////////////////////////////////////
   public void PrintMessage(String s) {
     server.PrintMessage(s);
   }
   ///////////////////////////////////////////////////////////////////
   //
   // Method:  GetMap
   //
   // Invoker: ServerRMI, ServerThread
   //
   // Purpose: GetMap returns the current map.
   //   
   ///////////////////////////////////////////////////////////////////
   public Map GetMap() {
     return map;
   }
   ///////////////////////////////////////////////////////////////////
   //
   // Method:  GetNumClients
   //
   // Invoker: ServerThread
   //
   // Purpose: GetNumClients returns the current number of clients.
   //   
   ///////////////////////////////////////////////////////////////////
   public int GetNumClients() {
     return num_clients;
   }
   ///////////////////////////////////////////////////////////////////
   //
   // Method:  GetDelay
   //
   // Invoker: ServerThread
   //
   // Purpose: GetDelay returns the current delay.
   //   
   ///////////////////////////////////////////////////////////////////
   public long GetDelay() {
     return delay;
   }
   ///////////////////////////////////////////////////////////////////
   //
   // Method:  GetPropagationMethod
   //
   // Invoker: ServerThread
   //
   // Purpose: GetPropagationMethod returns the current propagation method.
   //   
   ///////////////////////////////////////////////////////////////////
   public int GetPropagationMethod() {
     return propagation_method;
   }
   ///////////////////////////////////////////////////////////////////
   //
   // Method:  Error
   //
   // Invoker: ServerRMI, ServerThread
   //
   // Purpose: Error passes exceptions along to the Server for a stack
   //          dump.
   //   
   ///////////////////////////////////////////////////////////////////
    public void Error (Exception e) {
     server.Error(e);
   }
   ///////////////////////////////////////////////////////////////////
   //
   // Method:  Abort
   //
   // Invoker: ServerRMI
   //
   // Purpose: Abort stops the currently executing thread, stabilizes
   //          the map, and makes the map final and non-editable.
   //   
   ///////////////////////////////////////////////////////////////////
   public boolean Abort() {
     try {
       compute_engine.stop();
       map.SetStable(true);
       map.SetFinal(true);
       map.SetEditable(false);
       server_rmi.RunEnded();
     }
     catch (Exception e) {
       Error(e);
     }
     return true;
   }
   ///////////////////////////////////////////////////////////////////
   //
   // Method:  GetMode
   //
   // Invoker: ServerThread
   //
   // Purpose: GetMode returns the current mode (auto or manual).
   //   
   ///////////////////////////////////////////////////////////////////
   public int GetMode() {
     return mode;
   }
   ///////////////////////////////////////////////////////////////////
   //
   // Method:  GetIterations
   //
   // Invoker: ServerThread
   //
   // Purpose: Returns the current number of iterations.
   //   
   ///////////////////////////////////////////////////////////////////
   public int GetIterations() {
     return iterations;
   }
   ///////////////////////////////////////////////////////////////////
   //
   // Method:  SetThreadRunning
   //
   // Invoker: ServerThread
   //
   // Purpose: SetThreadRunning sets the variable thread_running to the
   //          passed boolean.
   //   
   ///////////////////////////////////////////////////////////////////
   public void SetThreadRunning(boolean b) {
     thread_running = b;
   }
   public void ShutDown() {
     server.ShutDown();
   }
 }