//     $Id: Module.java,v 3.2 1998/12/14 22:23:03 te3d Exp $    
 ////////////////////////////////////////////////////////////////////////////
 //
 // File: Module.java
 //
 // Purpose: A Module consists of a number of Nodes, which represent
 //          design parameters (DPs) or functional requirements (FRs).
 //          The "boss" Module (e.g., modules[0]) contains the FRs,
 //          while the other, "developer" Modules contain DPs.
 //          Modules also have names.
 //
 //          This is a base class, and can used by several modules.
 //          For that reason, we don't specify the invoking modules.
 //
 // Authors:
 //   txe  Travis Emmitt  emmitt@virginia.edu
 //   jpg  James P. Gunderson gunders@virginia.edu
 //
 // Modifications:
 //   28-OCT-1998  txe  (v1) Initial creation
 //   03-NOV-1998  txe  Added comments, removed unused methods.
 //   04-NOV-1998  jpg  Added Serialization methods
 //   06-NOV-1998  rgb  Added version control header info
 //   06-NOV-1998  txe  Added SetStable(), Valid(), Verbose(), debugging
 //   06-NOV-1998  jpg  implements Serialiizable
 //   09-NOV-1998  jpg  cleaned up style
 //
 //   13-NOV-1998  txe  (v2) Removed Die, added name, exceptions
 //   15-NOV-1998  txe  Improved Exceptions, comments, add version, paranoid
 //   19-NOV-1998  txe  Added random constructor
 //
 //   30-NOV-1998  txe  (v3) SetStable(false) now uses destab, improved look,
 //                     removed version
 //   14-DEC-1998  txe  Disabled paranoid test
 //
 ////////////////////////////////////////////////////////////////////////////
 import java.util.*;
 public class Module implements java.io.Serializable {
   protected int num_nodes;          // number of Nodes in module
   protected Node nodes[];           // set of Nodes (DPs and FRs)
   protected String name;            // name of the module
   private String delim = "|";        // token deliminator for serialization
   private boolean paranoid = false; // if true, check against ToSerial()
   ///////////////////////////////////////////////////////////////////
   //
   // Method:  Module  [constructor]
   //
   // Purpose: Default constructor, you shouldn't use it.
   //          
   ///////////////////////////////////////////////////////////////////
   public Module () {}
   ///////////////////////////////////////////////////////////////////
   //
   // Method:  Module  [constructor]
   //
   // Purpose: This creates a new Module which is a copy of the
   //          specified Module.
   //
   ///////////////////////////////////////////////////////////////////
   public Module (Module new_module)
   throws BoundsException, IndexException, NewException, NullException {
     Copy (new_module);
   }
   ///////////////////////////////////////////////////////////////////
   //
   // Method:  Module  [constructor]
   //   
   // Purpose: This creates a new Module containing the specified
   //          Nodes.  Note that the Nodes must have been created
   //          prior to the creation of this Module.
   //
   // Note:    Please use the constructor with the name instead.
   //
   ///////////////////////////////////////////////////////////////////
   public Module (int new_num_nodes, Node new_nodes[])
   throws BoundsException, IndexException, NewException, NullException {
     this (new_num_nodes, new_nodes, "NO_NAME");
   }
   ///////////////////////////////////////////////////////////////////
   //
   // Method:  Module  [constructor]
   //   
   // Purpose: This creates a new Module with the specified name,
   //          containing the specified Nodes.  Note that the Nodes
   //          must have been created prior to the creation of this
   //          Module.
   //
   ///////////////////////////////////////////////////////////////////
   public Module (int new_num_nodes, Node new_nodes[], String new_name)
   throws BoundsException, IndexException, NewException, NullException {
     if (new_num_nodes < 0) {
       throw new BoundsException ("new_num_nodes", new_num_nodes, 0);
     }
     if (new_num_nodes > 0 && new_nodes == null) {
       throw new NullException ("new_nodes");
     }
     num_nodes = 0;
     try {
       nodes = new Node [new_num_nodes];
     }
     catch (Exception e) {
       throw new NewException ("nodes", new_num_nodes);
     }
     SetName (new_name);
     for (int i = 0; i < new_num_nodes; i++) {
       AddNode (new_nodes[i]);
     }
     Validate ();
   }
   ///////////////////////////////////////////////////////////////////
   //
   // Method:  Module  [constructor]
   //
   // Purpose: This creates a new Module from the specified String
   //         
   ///////////////////////////////////////////////////////////////////
   public Module (String source)
   throws BoundsException, EqualityException, IndexException,
          NullException, ParsingException {
     if (source == null) {
       throw new NullException ("source");
     }
     try {
       StringTokenizer st = new StringTokenizer (source, delim);
       SetName (st.nextToken ());
       int count = new Integer (st.nextToken()).intValue();
       nodes     = new Node [count];
       for (int i = 0; i < count; i++) {
     AddNode (new Node (st.nextToken()));
       }
     }
     catch (BoundsException e) {
       throw e;
     }
     catch (IndexException e) {
       throw e;
     }
     catch (NullException e) {
       throw e;
     }
     catch (Exception e) {
       throw new ParsingException ("Module string", source);
     }
     // check that output format is consistent with input format:
     if (paranoid) {
       String output = ToSerial ();
       if (!source.equalsIgnoreCase (output)) {
     throw new EqualityException ("Module string", source, output);
       }
     }
     Validate ();
   }
   ///////////////////////////////////////////////////////////////////
   //
   // Method:  Module  [constructor]
   //   
   // Purpose: This creates a random module with the specified
   //          name and max size.
   //
   ///////////////////////////////////////////////////////////////////
   public Module (String new_name, int max_size)
   throws BoundsException, IndexException, NewException, NullException {
     if (max_size < 1) {
       throw new BoundsException ("max_size", max_size, 1);
     }
     num_nodes = 0;
     int new_num_nodes = 1 + (int) Math.min (Math.random() * max_size, max_size - 1);
     try {
       nodes = new Node [new_num_nodes];
     }
     catch (Exception e) {
       throw new NewException ("nodes", new_num_nodes);
     }
     SetName (new_name);
     for (int i = 0; i < new_num_nodes; i++) {
       int rec_int     = 1 + (int) Math.min (Math.random() * 10.0, 9.0);
       double recovery = (double) rec_int / 10.0;
       int des_int     = 1 + (int) Math.min (Math.random() * 10.0, 9.0);
       double destab   = (double) des_int / 10.0;
       AddNode (new Node (Math.random() < 0.5, recovery, destab, "Node" + i));
     }
     Validate ();
   }
   ///////////////////////////////////////////////////////////////////
   //
   // Method:  AddNode
   //
   // Purpose: This adds a Node to the Module.
   //   
   ///////////////////////////////////////////////////////////////////
   public void AddNode (Node new_node)
   throws BoundsException, IndexException, NullException {
     if (new_node == null) {
       throw new NullException ("new_node");
     }
     nodes[num_nodes] = new_node;
     num_nodes++;
     Validate ();
   }
   ///////////////////////////////////////////////////////////////////
   //
   // Method:  Copy
   //
   // Purpose: Copies the specified Module's data into this Module.
   //   
   ///////////////////////////////////////////////////////////////////
   public void Copy (Module new_module)
   throws BoundsException, IndexException, NewException, NullException {
     if (new_module == null) {
       throw new NullException ("new_module");
     }
     new_module.Validate ();
     SetName    (new_module.GetName ());
     num_nodes = new_module.GetNumNodes ();
     try {
       nodes = new Node [num_nodes];
     }
     catch (Exception e) {
       throw new NewException ("nodes", num_nodes);
     }
     for (int i = 0; i < num_nodes; i++) {
       nodes[i] = new Node (new_module.GetNode (i));
     }
     Validate ();
   }
   ///////////////////////////////////////////////////////////////////
   //
   // Method:  GetName
   //
   // Purpose: Returns the name of the Module.
   //   
   ///////////////////////////////////////////////////////////////////
   public String GetName () {
     return name;
   }
   ///////////////////////////////////////////////////////////////////
   //
   // Method:  GetNode
   //
   // Purpose: This returns a reference to the Node specified by the
   //          index.
   //   
   ///////////////////////////////////////////////////////////////////
   public Node GetNode (int node_id)
   throws BoundsException, IndexException, NullException {
     if (!NodeExists (node_id)) {
       throw new IndexException ("nodes", node_id);
     }
     return nodes[node_id];
   }
   ///////////////////////////////////////////////////////////////////
   //
   // Method:  GetNumNodes
   //
   // Purpose: This returns the current number of Nodes in the Module.
   //   
   ///////////////////////////////////////////////////////////////////
   public int GetNumNodes () {
     return num_nodes;
   }
   ///////////////////////////////////////////////////////////////////
   //
   // Method:  IsStable
   //
   // Purpose: This returns true if all the Nodes in the Module are
   //          stable, false otherwise.
   //   
   ///////////////////////////////////////////////////////////////////
   public boolean IsStable ()
   throws BoundsException, IndexException, NullException {
     for (int i = 0; i < num_nodes; i++) {
       if (!nodes[i].IsStable ()) {
     return false;
       }
     }
     return true;
   }
   ///////////////////////////////////////////////////////////////////
   //
   // Method:  NodeExists
   //
   // Purpose: This returns true if the specified Node exists in
   //          the Module, false otherwise.
   //   
   ///////////////////////////////////////////////////////////////////
   public boolean NodeExists (int node_id)
   throws BoundsException, IndexException, NullException {
     if (node_id < 0 || node_id >= num_nodes) {
       return false;
     }
     return (nodes[node_id] != null);
   }
   ///////////////////////////////////////////////////////////////////
   //
   // Method:  SetName
   //
   // Purpose: This sets the Module's name to the specified string.
   //   
   ///////////////////////////////////////////////////////////////////
   public void SetName (String new_name)
   throws NullException {
     if (new_name == null) {
       throw new NullException ("new_name");
     }
     name = new_name;
   }
   ///////////////////////////////////////////////////////////////////
   //
   // Method:  SetStable
   //
   // Purpose: Sets the stability of all the Nodes in the Module to
   //          the specified value.
   //   
   ///////////////////////////////////////////////////////////////////
   public void SetStable (boolean new_stable)
   throws BoundsException, IndexException, NullException {
     for (int i = 0; i < num_nodes; i++) {
       Node node = nodes[i];
       node.SetStable (new_stable || (Math.random() > node.GetDestab()));
     }
   }
   ///////////////////////////////////////////////////////////////////
   //
   // Method:  ToSerial
   //
   // Purpose: Returns a String representation of the Module.
   //   
   ///////////////////////////////////////////////////////////////////
   public String ToSerial ()
   throws BoundsException, IndexException, NullException {
     String temp = name + delim + num_nodes;
     for (int i = 0; i < num_nodes; i++) {
       temp += delim + nodes[i].ToSerial();
     }
     return temp;
   }
   ///////////////////////////////////////////////////////////////////
   //
   // Method:  Valid
   //
   // Purpose: Returns true if Module is valid, false otherwise.
   //   
   ///////////////////////////////////////////////////////////////////
   public boolean Valid () {
     try {
       Validate();
       return true;
     }
     catch (Exception e) {
       return false;
     }
   }
   ///////////////////////////////////////////////////////////////////
   //
   // Method:  Validate
   //
   // Purpose: Throws an exception if Module is invalid.
   //   
   ///////////////////////////////////////////////////////////////////
   public void Validate ()
   throws BoundsException, IndexException, NullException {
     if (num_nodes < 0) {
       throw new BoundsException ("num_nodes", num_nodes, 0);
     }
     for (int i = 0; i < num_nodes; i++) {
       Node node = null;
       try {
     node = nodes[i];
       }
       catch (Exception e) {
     throw new IndexException ("nodes", i);
       }
       if (node == null) {
     throw new NullException ("nodes", i);
       }
       node.Validate ();
     }
   }
   ///////////////////////////////////////////////////////////////////
   //
   // Method:  Verbose
   //
   // Purpose: Returns a human-readable String representation of Module.
   //   
   ///////////////////////////////////////////////////////////////////
   public String Verbose () {
     String temp = name + ": [" + num_nodes + " nodes]\n";
     for (int i = 0; i < num_nodes; i++) {
       temp += "  [" + i + "] ";
       try {
     temp += nodes[i].Verbose() + "\n";
       }
       catch (Exception e) {
     temp += "INVALID\n";
       }
     }
     return temp;
   }
 }
 ////////////////////////////////////////////////////////////////////////////