////////////////////////////////////////////////////////////////////////////
 //
 // File: Stats.java
 //
 // Purpose: Statistics data structure.    This contains the stats    for
 //        the    entire Map.
 //
 //        This is a base class, and can used by several modules.
 //        For    that reason, we    don't bother specifying    the
 //        invoking modules.
 //
 // Authors:
 //   txe  Travis Emmitt     emmitt@virginia.edu
 //
 // Modifications:
 //   13-NOV-1998  txe  (v2) Initial creation
 //   15-NOV-1998  txe  Improved    Exception, Comments
 //   04-DEC-1998  smg  Added ResetTurn function
 //   14-DEC-1998  txe  Fixed comments, spacing in output, format of code
 //
 ////////////////////////////////////////////////////////////////////////////
 public class Stats implements java.io.Serializable {
   protected int num_modules;           // number of modules in map
   protected int turn_recoveries[];       // # recoveries this turn
   protected int turn_destabilizations[];   // # destabilizations this turn
   protected int turn_unstable_nodes[];       // # unstable nodes   this turn
   protected int total_recoveries[];       // # recoveries       over time
   protected int total_destabilizations[];  // # destabilizations over time
   protected int total_unstable_nodes[];       // # unstable nodes   over time
   protected int turn;                     // current turn number
   /////////////////////////////////////////////////////////////////////////
   //
   // Method:  Stats  [constructor]
   //
   // Purpose: This creates a Statistics object for handling the
   //          specified    number of modules.
   //
   /////////////////////////////////////////////////////////////////////////
   public Stats (int new_num_modules)
   throws BoundsException, IndexException, NewException {
     if (new_num_modules < 0) {
       throw new BoundsException ("new_num_modules", new_num_modules, 0);
     }
     num_modules = new_num_modules;
     try {
       turn_recoveries           = new int[num_modules];
       turn_destabilizations  = new int[num_modules];
       turn_unstable_nodes    = new int[num_modules];
       total_recoveries       = new int[num_modules];
       total_destabilizations = new int[num_modules];
       total_unstable_nodes   = new int[num_modules];
       Reset ();
     }
     catch (IndexException e) {
       throw e;
     }
     catch (Exception e) {
       throw new NewException ("one of    the arrays", num_modules);
     }
   }
   /////////////////////////////////////////////////////////////////////////
   //
   // Method:  GetTotalDestabilizations
   //
   // Purpose: Returns the total number of destabilizations in all modules.
   //
   /////////////////////////////////////////////////////////////////////////
   public int GetTotalDestabilizations ()
   throws BoundsException, IndexException  {
     int total = 0;
     for (int i = 0; i < num_modules; i++) {
       total += GetTotalDestabilizations (i);
     }
     return total;
   }
   /////////////////////////////////////////////////////////////////////////
   //
   // Method:  GetTotalDestabilizations
   //
   // Purpose: Returns the total number of destabilizations in the specified
   //          module.
   //
   /////////////////////////////////////////////////////////////////////////
   public int GetTotalDestabilizations (int module_id)
   throws BoundsException, IndexException {
     if (module_id < 0 || module_id >= num_modules) {
       throw new BoundsException ("module_id",    module_id, 0, num_modules - 1);
     }
     try {
       return total_destabilizations[module_id];
     }
     catch (Exception e) {
       throw new IndexException ("total_destabilizations", module_id);
     }
   }
   /////////////////////////////////////////////////////////////////////////
   //
   // Method:  GetTotalRecoveries
   //
   // Purpose: Returns the total number of recoveries in all modules.
   //
   /////////////////////////////////////////////////////////////////////////
   public int GetTotalRecoveries ()
   throws BoundsException, IndexException {
     int total = 0;
     for (int i = 0; i < num_modules; i++) {
       total += GetTotalRecoveries (i);
     }
     return total;
   }
   /////////////////////////////////////////////////////////////////////////
   //
   // Method:  GetTotalRecoveries
   //
   // Purpose: Returns the total number of recoveries in the specified
   //          module.
   //
   /////////////////////////////////////////////////////////////////////////
   public int GetTotalRecoveries (int module_id)
   throws BoundsException, IndexException {
     if (module_id < 0 || module_id >= num_modules) {
       throw new BoundsException ("module_id",    module_id, 0, num_modules - 1);
     }
     try {
       return total_recoveries[module_id];
     }
     catch (Exception e) {
       throw new IndexException ("total_recoveries", module_id);
     }
   }
   /////////////////////////////////////////////////////////////////////////
   //
   // Method:  GetTotalUnstableNodes
   //
   // Purpose: Returns the total number of unstable nodes in all modules.
   //
   /////////////////////////////////////////////////////////////////////////
   public int GetTotalUnstableNodes ()
   throws BoundsException, IndexException {
     int total = 0;
     for (int i = 0; i < num_modules; i++) {
       total += GetTotalUnstableNodes (i);
     }
     return total;
   }
   /////////////////////////////////////////////////////////////////////////
   //
   // Method:  GetTotalUnstableNodes
   //
   // Purpose: Returns the total number of unstable nodes in the specified
   //          module.
   //
   /////////////////////////////////////////////////////////////////////////
   public int GetTotalUnstableNodes (int module_id)
   throws BoundsException, IndexException {
     if (module_id < 0 || module_id >= num_modules) {
       throw new BoundsException ("module_id",    module_id, 0, num_modules - 1);
     }
     try {
       return total_unstable_nodes[module_id];
     }
     catch (Exception e) {
       throw new IndexException ("total_unstable_nodes", module_id);
     }
   }
   /////////////////////////////////////////////////////////////////////////
   //
   // Method:  GetTurn
   //
   // Purpose: Returns the current turn number.
   //
   /////////////////////////////////////////////////////////////////////////
   public int GetTurn ()    {
     return turn;
   }
   /////////////////////////////////////////////////////////////////////////
   //
   // Method:  GetTurnDestabilizations
   //
   // Purpose: Returns the number of destabilizations in all modules for
   //          this turn.
   //
   /////////////////////////////////////////////////////////////////////////
   public int GetTurnDestabilizations ()
   throws BoundsException, IndexException {
     int total = 0;
     for (int i = 0; i < num_modules; i++) {
       total += GetTurnDestabilizations (i);
     }
     return total;
   }
   /////////////////////////////////////////////////////////////////////////
   //
   // Method:  GetTurnDestabilizations
   //
   // Purpose: Returns the number of destabilizations in the specified
   //          module for this turn.
   //
   /////////////////////////////////////////////////////////////////////////
   public int GetTurnDestabilizations (int module_id)
   throws BoundsException, IndexException {
     if (module_id < 0 || module_id >= num_modules) {
       throw new BoundsException ("module_id",    module_id, 0, num_modules - 1);
     }
     try {
       return turn_destabilizations[module_id];
     }
     catch (Exception e) {
       throw new IndexException ("turn_destabilizations", module_id);
     }
   }
   /////////////////////////////////////////////////////////////////////////
   //
   // Method:  GetTurnRecoveries
   //
   // Purpose: Returns the number of recoveries in all modules for this
   //          turn.
   //
   /////////////////////////////////////////////////////////////////////////
   public int GetTurnRecoveries ()
   throws BoundsException, IndexException {
     int total = 0;
     for (int i = 0; i < num_modules; i++) {
       total += GetTurnRecoveries (i);
     }
     return total;
   }
   /////////////////////////////////////////////////////////////////////////
   //
   // Method:  GetTurnRecoveries
   //
   // Purpose: Returns the number of recoveries in the specified module
   //          for this turn.
   //
   /////////////////////////////////////////////////////////////////////////
   public int GetTurnRecoveries (int module_id)
   throws BoundsException, IndexException {
     if (module_id < 0 || module_id >= num_modules) {
       throw new BoundsException ("module_id",    module_id, 0, num_modules - 1);
     }
     try {
       return turn_recoveries[module_id];
     }
     catch (Exception e) {
       throw new IndexException ("turn_recoveries", module_id);
     }
   }
   /////////////////////////////////////////////////////////////////////////
   //
   // Method:  GetTurnUnstableNodes
   //
   // Purpose: Returns the number of unstable nodes in all modules for
   //          this turn.
   //
   /////////////////////////////////////////////////////////////////////////
   public int GetTurnUnstableNodes ()
   throws BoundsException, IndexException {
     int total = 0;
     for (int i = 0; i < num_modules; i++) {
       total += GetTurnUnstableNodes (i);
     }
     return total;
   }
   /////////////////////////////////////////////////////////////////////////
   //
   // Method:  GetTurnUnstableNodes
   //
   // Purpose: Returns the number of unstable nodes in the specified
   //          module for this turn.
   //
   /////////////////////////////////////////////////////////////////////////
   public int GetTurnUnstableNodes (int module_id)
   throws BoundsException, IndexException {
     if (module_id < 0 || module_id >= num_modules) {
       throw new BoundsException ("module_id",    module_id, 0, num_modules - 1);
     }
     try {
       return turn_unstable_nodes[module_id];
     }
     catch (Exception e) {
       throw new IndexException ("turn_unstable_nodes", module_id);
     }
   }
   /////////////////////////////////////////////////////////////////////////
   //
   // Method:  LogTick
   //
   // Purpose: This characterizes the current "clock tick" for the
   //          specified module; it stores the current conditions for
   //          that module and updates the associated counts.
   //
   /////////////////////////////////////////////////////////////////////////
   public void LogTick (int module_id, int recoveries, int destabilizations,
                int unstable_nodes)
   throws BoundsException, IndexException {
     if (module_id < 0 || module_id >= num_modules) {
       throw new BoundsException ("module_id",    module_id, 0, num_modules - 1);
     }
     try {
       turn_recoveries         [module_id]  = recoveries;
       turn_destabilizations  [module_id]  = destabilizations;
       turn_unstable_nodes    [module_id]  = unstable_nodes;
       total_recoveries       [module_id] += recoveries;
       total_destabilizations [module_id] += destabilizations;
       total_unstable_nodes   [module_id] += unstable_nodes;
     }
     catch (Exception e) {
       throw new IndexException ("one of the arrays", module_id);
     }
     if (module_id == 0) {
       turn++;
     }
   }
   /////////////////////////////////////////////////////////////////////////
   //
   // Method:  Reset
   //
   // Purpose:    This resets all    counts to 0.
   //
   /////////////////////////////////////////////////////////////////////////
   public void Reset ()
   throws IndexException {
     turn = 0;
     for (int i = 0; i < num_modules; i++) {
       try {
     turn_recoveries           [i] = 0;
     turn_destabilizations  [i] = 0;
     turn_unstable_nodes    [i] = 0;
     total_recoveries       [i] = 0;
     total_destabilizations [i] = 0;
     total_unstable_nodes   [i] = 0;
       }
       catch (Exception e) {
     throw new IndexException ("one of the arrays", i);
       }
     }
   }
   /////////////////////////////////////////////////////////////////////////
   //
   // Method:  Verbose
   //
   // Purpose: Returns the human-readable representation of the
   //          current statistics for all the Modules, plus the Map.
   //
   /////////////////////////////////////////////////////////////////////////
   public String Verbose () {
     try {
       String line0 = "STATS for turn " + GetTurn() + ": ";
       String line1 = "  Recoveries       ";
       String line2 = "  Destabilizations ";
       String line3 = "  Unstable Nodes   ";
       for (int i = 0;    i < num_modules; i++) {
     line0 += "\t  "    + i + "     ";
     line1 += "\t" +    GetTurnRecoveries    (i) + "/" + GetTotalRecoveries         (i);
     line2 += "\t" +    GetTurnDestabilizations    (i) + "/" + GetTotalDestabilizations (i);
     line3 += "\t" +    GetTurnUnstableNodes    (i) + "/" + GetTotalUnstableNodes    (i);
       }
       line0 += "\t MAP";
       line1 += "\t" +    GetTurnRecoveries    () + "/" + GetTotalRecoveries        ();
       line2 += "\t" +    GetTurnDestabilizations    () + "/" + GetTotalDestabilizations ();
       line3 += "\t" +    GetTurnUnstableNodes    () + "/" + GetTotalUnstableNodes    ();
       return line0 + "\n" + line1 + "\n" + line2 + "\n" + line3 + "\n\n";
     }
     catch (Exception e) {
       return "Stats are invalid.  Reason:\n" + e.getMessage()    + "\n";
     }
   }
   /////////////////////////////////////////////////////////////////////////
   //
   // Method:  Verbose
   //
   // Purpose: Returns the human-readable representation of the
   //          current statistics for the specified module, plus the Map.
   //
   /////////////////////////////////////////////////////////////////////////
   public String Verbose (int module_id) {
     try {
       String line0 = "STATS for turn " + GetTurn() + ": ";
       String line1 = "  Recoveries       ";
       String line2 = "  Destabilizations ";
       String line3 = "  Unstable Nodes   ";
       int i = module_id;
       line0 += "\t  " + i + "  ";
       line1 += "\t" +    GetTurnRecoveries    (i) + "/" + GetTotalRecoveries         (i);
       line2 += "\t" +    GetTurnDestabilizations    (i) + "/" + GetTotalDestabilizations (i);
       line3 += "\t" +    GetTurnUnstableNodes    (i) + "/" + GetTotalUnstableNodes    (i);
       line0 += "\t MAP";
       line1 += "\t" +    GetTurnRecoveries    () + "/" + GetTotalRecoveries        ();
       line2 += "\t" +    GetTurnDestabilizations    () + "/" + GetTotalDestabilizations ();
       line3 += "\t" +    GetTurnUnstableNodes    () + "/" + GetTotalUnstableNodes    ();
       return line0 + "\n" + line1 + "\n" + line2 + "\n" + line3 + "\n\n";
     }
     catch (Exception e) {
       return "Stats are invalid.  Reason:\n" + e.getMessage()    + "\n";
     }
   }
   /////////////////////////////////////////////////////////////////////////
   //
   // Method:  ResetTurn
   //
   // Purpose: Resets the turn counter to 0
   //
   /////////////////////////////////////////////////////////////////////////
   public void ResetTurn() {
     turn = 0;
   }
 }
 ///////////////////////////////////////////////////////////////////////////