//    $Id: Map.java,v 3.3 1998/12/14 22:23:03 te3d Exp $
 ////////////////////////////////////////////////////////////////////////////
 //
 // File: Map.java
 //
 // Purpose: The    Map represents the entire set of Modules and
 //        Dependencies in the    system.     It also contains a
 //        "finalized"    bit, which the server uses to indicate
 //        whether the    current    state is intermediate or final.
 //
 //        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
 //   jpg  James    P. Gunderson gunders@virginia.edu
 //
 // Modifications:
 //   28-OCT-1998  txe  (v1) Initial creation
 //   29-OCT-1998  txe  Added ToggleNode
 //   03-NOV-1998  txe  Added comments, removed unused methods.
 //   04-NOV-1998  jpg  Added Serialization Methods
 //   05-NOV-1998  jpg  Added Finalized to Serialization
 //   06-NOV-1998  rgb  Added version control header info
 //   06-NOV-1998  txe  Added SetStable(), Valid(), Verbose(), debugging
 //   06-NOV-1998  jpg  implements Serializable
 //
 //   12-NOV-1998  txe  (v2) Added GetDepend*IDs(), Exceptions
 //   13-NOV-1998  txe  Added more exceptions, cleaned up
 //   14-NOV-1998  txe  AddedGetDependIDs()
 //   15-NOV-1998  txe  Improved    Exceptions, comments, add version, paranoid
 //   16-NOV-1998  txe  Fixed toggle bug, increased GetDependIDs() array    size+1
 //   17-NOV-1998  txe  Copy now    copies finalized bit
 //   19-NOV-1998  txe  Added random constructor, added depend prob to verbose
 //   20-NOV-1998  txe  Added depends vectors for faster    reference
 //
 //   30-NOV-1998  txe  (v3) Improved format, removed version
 //   02-DEC-1998  txe  Added editable and related methods.
 //   14-DEC-1998  txe  Disabled paranoid test
 //
 ////////////////////////////////////////////////////////////////////////////
 import java.util.*;
 public class Map implements java.io.Serializable {
   protected int    num_modules;          // number of modules in map
   protected int    num_depends;          // number of dependencies in map
   protected Module modules[];          // array of modules
   protected Depend depends[];          // array of dependencies
   protected boolean finalized;          // true iff the state    is finalized
   protected boolean editable;             // true iff map is editable
   private String delim = "^";          // token deliminator for serialization
   private boolean paranoid = false;      // if    true, check against ToSerial()
   protected static final int ANY = -1;      // flag; match any module/node
   protected int    module_offsets[];         // used for manazing quick Node matrix
   protected int    total_nodes = 0;          // total # nodes in Map
   protected Vector depends_from_module[]; // lists of Depends...
   protected Vector depends_to_module[];   //
   protected Vector depends_from_node[];   //
   protected Vector depends_to_node[];     //
   ///////////////////////////////////////////////////////////////////
   //
   // Method:  Map  [constructor]
   //
   // Purpose: This is the default constructor; don't use it.
   //
   ///////////////////////////////////////////////////////////////////
   public Map ()    {}
   ///////////////////////////////////////////////////////////////////
   //
   // Method:  Map  [constructor]
   //
   // Purpose: This creates a new Map which is a    copy of    the
   //          specified    Map.
   //
   ///////////////////////////////////////////////////////////////////
   public Map (Map new_map)
   throws BoundsException, IndexException, NewException,    NullException {
     Copy (new_map);
   }
   ///////////////////////////////////////////////////////////////////
   //
   // Method:  Map  [constructor]
   //
   // Purpose: This creates a new Map containing    the specified
   //          Modules and Depends.  Note that the Modules and
   //          Depends must have    been created prior to creation
   //          of this Map.
   //
   ///////////////////////////////////////////////////////////////////
   public Map (int new_num_modules, Module new_modules[],
           int new_num_depends, Depend new_depends[])
   throws BoundsException, IndexException, NewException,    NullException {
     Init (new_modules, new_depends, true, true);
   }
   ///////////////////////////////////////////////////////////////////
   //
   // Method:  Map  [constructor]
   //
   // Purpose: This creates a new Map containing    the specified
   //          Modules and Depends.  Note that the Modules and
   //          Depends must have    been created prior to creation
   //          of this Map.
   //          The map is built from a String Representation
   //
   ///////////////////////////////////////////////////////////////////
   public Map (String source)
   throws BoundsException, EqualityException, IndexException,
      NewException, NullException, ParsingException {
     if (source == null)    {
       throw new    NullException ("source");
     }
     num_modules    = 0;
     num_depends    = 0;
     try    {
       StringTokenizer st   = new StringTokenizer (source, delim);
       int new_num_modules  = new Integer (st.nextToken()).intValue();
       Module new_modules[] = new Module    [new_num_modules];
       for (int i = 0; i    < new_num_modules; i++)    {
     new_modules[i]       = new Module    (st.nextToken());
       }
       int new_num_depends  = new Integer (st.nextToken()).intValue();
       Depend new_depends[] = new Depend    [new_num_depends];
       for (int i = 0; i    < new_num_depends; i++)    {
     new_depends[i]       = new Depend    (st.nextToken());
       }
       boolean new_finalized = st.nextToken().equalsIgnoreCase ("t");
       boolean new_editable  = st.nextToken().equalsIgnoreCase ("t");
       Init (new_modules, new_depends, new_finalized, new_editable);
     }
     catch (Exception e)    {
       throw new    ParsingException ("Map string",    source);
     }
     // check that output format    is consistent with input format:
     if (paranoid) {
       String output = ToSerial ();
       if (!source.equalsIgnoreCase (output)) {
     throw new EqualityException ("Map string", source, output);
       }
     }
     Validate ();
   }
   ///////////////////////////////////////////////////////////////////
   //
   // Method:  Map  [constructor]
   //
   // Purpose: This creates a random map    of the specified max size.
   //
   ///////////////////////////////////////////////////////////////////
   public Map (int max_size)
   throws BoundsException, IndexException, NewException,    NullException {
     if (max_size < 1) {
       throw new    BoundsException    ("max_size", max_size, 1);
     }
     num_modules    = 0;
     num_depends    = 0;
     int    new_num_modules     = max_size;
     int    new_num_depends     = 1 + (int) (Math.random() * max_size * max_size);
     Module new_modules[] = new Module [new_num_modules];
     Depend new_depends[] = new Depend [new_num_depends];
     for    (int i = 0; i <    new_num_modules; i++) {
       new_modules[i] = new Module ("Module" + i, max_size);
     }
     for    (int i = 0; i <    new_num_depends; i++) {
       int smi =    (int) Math.min (Math.random() *    new_num_modules, new_num_modules - 1);
       int num_nodes = new_modules[smi].GetNumNodes();
       int sni =    (int) Math.min (Math.random() *    num_nodes,     num_nodes     - 1);
       int dmi =    (int) Math.min (Math.random() *    new_num_modules, new_num_modules - 1);
       num_nodes    = new_modules[dmi].GetNumNodes();
       int dni =    (int) Math.min (Math.random() *    num_nodes,     num_nodes     - 1);
       if (smi != dmi ||    sni != dni) {  // don't    allow self-dependency
     int prob_int   = 1 + (int) Math.min (Math.random() * 10.0, 9.0);
     double prob    = (double) prob_int / 10.0;
     new_depends[i] = new Depend (smi, sni, dmi, dni, prob);
       }
       else {
     i--;  // try again
       }
     }
     Init (new_modules, new_depends, true, true);
   }
   ///////////////////////////////////////////////////////////////////
   //
   // Method:  AddDepend
   //
   // Purpose: This adds    a Depend to the    Map.
   //
   ///////////////////////////////////////////////////////////////////
   public void AddDepend    (Depend    new_depend)
   throws BoundsException, IndexException, NullException    {
     if (new_depend == null) {
       throw new    NullException ("new_depend");
     }
     if (num_depends >= depends.length) {
       throw new    IndexException ("depends", num_depends);
     }
     depends[num_depends] = new_depend;
     int    source_module_id = new_depend.GetSourceModuleID    ();
     int    source_node_id     = new_depend.GetSourceNodeID    ();
     int    dest_module_id     = new_depend.GetDestModuleID    ();
     int    dest_node_id     = new_depend.GetDestNodeID    ();
     int    source_id     = module_offsets[source_module_id] + source_node_id;
     int    dest_id         = module_offsets[dest_module_id]   + dest_node_id;
     if (source_id != dest_id) {
       depends_from_node   [source_id]        .addElement (new_depend);
       depends_to_node     [dest_id]          .addElement (new_depend);
     }
     if (source_module_id != dest_module_id) {
       depends_from_module [source_module_id] .addElement (new_depend);
       depends_to_module   [dest_module_id]   .addElement (new_depend);
     }
     num_depends++;
   }
   ///////////////////////////////////////////////////////////////////
   //
   // Method:  AddModule
   //
   // Purpose: This adds    a Module to the    Map.
   //
   ///////////////////////////////////////////////////////////////////
   public void AddModule    (Module    new_module)
   throws BoundsException, IndexException, NullException    {
     if (new_module == null) {
       throw new    NullException ("new_module");
     }
     if (num_modules >= modules.length) {
       throw new    IndexException ("modules", num_modules);
     }
     modules       [num_modules] = new_module;
     module_offsets [num_modules] = total_nodes;
     total_nodes    += new_module.GetNumNodes();
     num_modules++;
   }
   ///////////////////////////////////////////////////////////////////
   //
   // Method:  Copy
   //
   // Purpose: This copies the specified    Map's data into    this Map.
   //
   ///////////////////////////////////////////////////////////////////
   public void Copy (Map    new_map)
   throws BoundsException, IndexException, NewException,    NullException {
     if (new_map    == null) {
       throw new    NullException ("new_map");
     }
     new_map.Validate ();
     int    new_num_modules      = new_map.GetNumModules ();
     int    new_num_depends      = new_map.GetNumDepends ();
     Module new_modules[]  = new Module [new_num_modules];
     Depend new_depends[]  = new Depend [new_num_depends];
     for    (int i = 0; i <    new_num_modules; i++) {
       new_modules[i] = new Module (new_map.GetModule (i));
     }
     for    (int i = 0; i <    new_num_depends; i++) {
       new_depends[i] = new Depend (new_map.GetDepend (i));
     }
     boolean new_finalized = new_map.IsFinal();
     boolean new_editable  = new_map.IsEditable();
     Init (new_modules, new_depends, new_finalized, new_editable);
   }
   ///////////////////////////////////////////////////////////////////
   //
   // Method:  DependExists
   //
   // Purpose: This returns true    if the Depend specified    by the index
   //          exists, false otherwise.
   //
   ///////////////////////////////////////////////////////////////////
   public boolean DependExists (int depend_id)
   throws BoundsException, IndexException, NullException {
     return (depend_id >= 0 && depend_id < num_depends);
   }
   ///////////////////////////////////////////////////////////////////
   //
   // Method:  GetDepend
   //
   // Purpose: This returns a reference to the Depend specified by
   //          the index.
   //
   ///////////////////////////////////////////////////////////////////
   public Depend    GetDepend (int depend_id)
   throws BoundsException, IndexException, NullException {
     if (!DependExists (depend_id)) {
       throw new IndexException ("depends", depend_id);
     }
     return depends[depend_id];
   }
   //////////////////////////////////////////////////////////////////////////
   //
   // Method:  GetDependeeModuleIDs
   //
   // Purpose: This returns a list    of IDs of Modules upon which our Node
   //        depends.
   //
   //////////////////////////////////////////////////////////////////////////
   public int [] GetDependeeModuleIDs (int    our_module_id, int our_node_id)
        throws BoundsException,    IndexException,    NewException, NullException {
      return GetDependIDs (our_module_id, our_node_id, ANY, false);
   }
   //////////////////////////////////////////////////////////////////////////
   //
   // Method:  GetDependeeModuleIDs
   //
   // Purpose: This returns a list    of IDs of Modules upon which any
   //        Nodes in our Module    depend.
   //
   //////////////////////////////////////////////////////////////////////////
   public int []    GetDependeeModuleIDs (int our_module_id)
        throws BoundsException,    IndexException,    NewException, NullException {
      return GetDependIDs (our_module_id, ANY, ANY, false);
   }
   //////////////////////////////////////////////////////////////////////////
   //
   // Method:  GetDependeeNodeIDs
   //
   // Purpose: This returns a list    of IDs of Nodes    in the specified Module
   //        upon which our Node    depends.
   //
   //////////////////////////////////////////////////////////////////////////
   public int [] GetDependeeNodeIDs (int our_module_id, int our_node_id, int his_module_id)
        throws BoundsException,    IndexException,    NewException, NullException {
      return GetDependIDs (our_module_id, our_node_id, his_module_id,    false);
   }
   //////////////////////////////////////////////////////////////////////////
   //
   // Method:  GetDependeeNodeIDs
   //
   // Purpose: This returns a list    of IDs of Nodes    in the specified Module
   //        upon which any Nodes in our    Module depend.
   //
   //////////////////////////////////////////////////////////////////////////
   public int []    GetDependeeNodeIDs (int    our_module_id, int his_module_id)
        throws BoundsException,    IndexException,    NewException, NullException {
      return GetDependIDs (our_module_id, ANY, his_module_id,    false);
   }
   //////////////////////////////////////////////////////////////////////////
   //
   // Method:  GetDependerModuleIDs
   //
   // Purpose: This returns a list    of IDs of Modules which    depend upon our
   //        Node.
   //
   //////////////////////////////////////////////////////////////////////////
   public int []    GetDependerModuleIDs (int our_module_id, int our_node_id)
        throws BoundsException,    IndexException,    NewException, NullException {
      return GetDependIDs (our_module_id, our_node_id, ANY, true);
   }
   //////////////////////////////////////////////////////////////////////////
   //
   // Method:  GetDependerModuleIDs
   //
   // Purpose: This returns a list    of IDs of Modules which    depend upon any
   //        Nodes in our Module.
   //
   //////////////////////////////////////////////////////////////////////////
   public int []    GetDependerModuleIDs (int our_module_id)
        throws BoundsException,    IndexException,    NewException, NullException {
      return GetDependIDs (our_module_id, ANY, ANY, true);
   }
   //////////////////////////////////////////////////////////////////////////
   //
   // Method:  GetDependerNodeIDs
   //
   // Purpose: This returns a list    of IDs of Nodes    in the specified
   //        Module which depend    upon our Node.
   //
   //////////////////////////////////////////////////////////////////////////
   public int [] GetDependerNodeIDs (int our_module_id, int our_node_id, int his_module_id)
        throws BoundsException,    IndexException,    NewException, NullException {
      return GetDependIDs (our_module_id, our_node_id, his_module_id, true);
   }
   //////////////////////////////////////////////////////////////////////////
   //
   // Method:  GetDependerNodeIDs
   //
   // Purpose: This returns a list    of IDs of Nodes    in the specified
   //        Module which depend    upon any Nodes our Module.
   //
   //////////////////////////////////////////////////////////////////////////
   public int []    GetDependerNodeIDs (int    our_module_id, int his_module_id)
        throws BoundsException, IndexException, NewException, NullException {
      return GetDependIDs (our_module_id, ANY, his_module_id,    true);
   }
   //////////////////////////////////////////////////////////////////////////
   //
   // Method:  GetDependIDs
   //
   // Purpose: This returns a list    of IDs of Modules (or Nodes in the
   //        specified Module) which our    Module/Node has    dependencies
   //        to/from.
   //
   //////////////////////////////////////////////////////////////////////////
   public int [] GetDependIDs (int our_module_id, int our_node_id,
                   int his_module_id, boolean we_depend)
   throws BoundsException, IndexException, NewException, NullException {
     int num_hits = 0;
     int max_hits = 0;
     if (his_module_id != ANY) {
       max_hits = GetModule (his_module_id).GetNumNodes();
     }
     else {
       max_hits = num_modules;
     }
     boolean    used[];
     int    hits[];
     max_hits++;    // lets    us detect end via (hits[i] == -1)
     try {
       used = new boolean [max_hits];
       hits = new int     [max_hits];
     }
     catch (Exception e) {
       throw new NewException ("used or hits",    max_hits);
     }
     for (int i = 0;    i < max_hits; i++) {
       hits[i]    = -1;
       used[i]    = false;
     }
     for (int i = 0;    i < num_depends; i++) {
       int source_module_id = depends[i].GetSourceModuleID ();
       int source_node_id   = depends[i].GetSourceNodeID   ();
       int dest_module_id   = depends[i].GetDestModuleID   ();
       int dest_node_id     = depends[i].GetDestNodeID        ();
       int id = -1;
       if (we_depend) {
     if (our_module_id == source_module_id
         && (our_node_id == ANY    || our_node_id == source_node_id)) {
       if (his_module_id == ANY) {
         id = dest_module_id;
       }
       else if    (his_module_id == dest_module_id) {
         id = dest_node_id;
       }
     }
       }
       else {
     if (our_module_id == dest_module_id
         && (our_node_id == ANY    || our_node_id == dest_node_id)) {
       if (his_module_id == ANY) {
         id = source_module_id;
       }
       else if    (his_module_id == source_module_id) {
         id = source_node_id;
       }
     }
       }
       try {
     if (id >= 0 && !used[id]) {
       used[id] = true;
       hits[num_hits++] = id;
     }
       }
       catch (Exception e) {
     throw new IndexException (&quot;used[&quot; + id + &quot;] or hits[&quot; +    num_hits + &quot;]&quot;);
       }
     }
     return hits;
   }
   //////////////////////////////////////////////////////////////////////////
   //
   // Method:  GetDepends
   //
   // Purpose: This returns a list of Depends to/from the specified module/node
   //
   //////////////////////////////////////////////////////////////////////////
   public Depend    [] GetDepends (int module_id, int node_id, boolean to)
   throws BoundsException, IndexException, NullException {
     int id = (node_id == ANY ? module_id : module_offsets[module_id] + node_id);
     Vector vector[] = (node_id == ANY ? (to ? depends_to_module : depends_from_module)
                               : (to ? depends_to_node   : depends_from_node));
     int num_hits     = vector[id].size();
     Enumeration enum = vector[id].elements();
     Depend hits[]    = new Depend [num_hits];
     for (int i = 0; enum.hasMoreElements(); i++) {
       hits[i] =    (Depend) enum.nextElement();
     }
     return hits;
   }
   ///////////////////////////////////////////////////////////////////
   //
   // Method:  GetModule
   //
   // Purpose: This returns a reference to the Module specified by
   //          the index.
   //
   ///////////////////////////////////////////////////////////////////
   public Module    GetModule (int module_id)
   throws BoundsException, IndexException, NullException    {
     if (!ModuleExists (module_id)) {
       throw new    IndexException ("modules", module_id);
     }
     return modules[module_id];
   }
   ///////////////////////////////////////////////////////////////////
   //
   // Method:  GetNode
   //
   // Purpose: This returns a reference to the Node specified by
   //          the indexes.
   //
   ///////////////////////////////////////////////////////////////////
   public Node GetNode (int module_id, int node_id)
   throws BoundsException, IndexException, NullException {
     if (!NodeExists    (module_id, node_id)) {
       throw new IndexException ("modules[" + module_id + "].nodes", node_id);
     }
     return modules[module_id].GetNode (node_id);
   }
   ///////////////////////////////////////////////////////////////////
   //
   // Method:  GetNumDepends
   //
   // Purpose: This returns the current number of Depends in the    Map.
   //
   ///////////////////////////////////////////////////////////////////
   public int GetNumDepends () {
     return num_depends;
   }
   ///////////////////////////////////////////////////////////////////
   //
   // Method:  GetNumModules
   //
   // Purpose: This returns the current number of Modules in the    Map.
   //
   ///////////////////////////////////////////////////////////////////
   public int GetNumModules () {
     return num_modules;
   }
   ///////////////////////////////////////////////////////////////////
   //
   // Method:  Init
   //
   // Purpose: This initializes the map,    adding the specified Modules
   //        and    Depends    to it.    It's called by the constructors.
   //
   ///////////////////////////////////////////////////////////////////
   private void Init (Module new_modules[], Depend new_depends[],
              boolean new_final,    boolean new_editable)
   throws BoundsException, IndexException, NewException, NullException {
     if (new_modules == null) {
       throw new NullException ("new_modules");
     }
     if (new_depends == null) {
       throw new NullException ("new_depends");
     }
     int new_num_modules = new_modules.length;
     int new_num_depends = new_depends.length;
     finalized       = new_final;
     editable       = new_editable;
     num_modules       = 0;
     num_depends       = 0;
     total_nodes    = 0;
     modules       = new Module [new_num_modules];
     module_offsets = new int    [new_num_modules];
     depends       = new Depend [new_num_depends];
     for (int i = 0; i < new_num_modules; i++) {
       AddModule (new_modules[i]);
     }
     depends_from_module = new Vector [num_modules];
     depends_to_module   = new Vector [num_modules];
     depends_from_node   = new Vector [total_nodes];
     depends_to_node    = new Vector [total_nodes];
     for (int i = 0; i < num_modules; i++) {
       depends_from_module[i] = new Vector ();
       depends_to_module[i]   = new Vector ();
     }
     for (int i = 0; i < total_nodes; i++) {
       depends_from_node[i] = new Vector ();
       depends_to_node[i]   = new Vector ();
     }
     for (int i = 0; i < new_num_depends; i++) {
       AddDepend (new_depends[i]);
     }
     Validate ();
   }
   ///////////////////////////////////////////////////////////////////
   //
   // Method:  IsEditable
   //
   // Purpose: This returns the current value of    the editable bit.
   //
   ///////////////////////////////////////////////////////////////////
   public boolean IsEditable () {
     return editable;
   }
   ///////////////////////////////////////////////////////////////////
   //
   // Method:  IsFinal
   //
   // Purpose: This returns the current value of    the finalized bit.
   //
   ///////////////////////////////////////////////////////////////////
   public boolean IsFinal () {
     return finalized;
   }
   ///////////////////////////////////////////////////////////////////
   //
   // Method:  IsStable
   //
   // Purpose: This returns true    if all the Modules in the Map are
   //          stable, false otherwise.
   //
   ///////////////////////////////////////////////////////////////////
   public boolean IsStable ()
   throws BoundsException, IndexException, NullException {
     for (int i = 0; i < num_modules; i++) {
       if (!modules[i].IsStable()) {
     return false;
       }
     }
     return true;
   }
   ///////////////////////////////////////////////////////////////////
   //
   // Method:  ModuleExists
   //
   // Purpose: This returns true    if the Module specified    by the index
   //          exists, false otherwise.
   //
   ///////////////////////////////////////////////////////////////////
   public boolean ModuleExists (int module_id)
   throws BoundsException, IndexException, NullException {
     if (module_id < 0 || module_id >= num_modules) {
       return false;
     }
     Module module = null;
     try {
       module = modules[module_id];
     }
     catch (Exception e) {
       throw new IndexException ("modules", module_id);
     }
     if (module == null) {
       throw new NullException    ("modules", module_id);
     }
     return true;
   }
   ///////////////////////////////////////////////////////////////////
   //
   // Method:  NodeExists
   //
   // Purpose: This returns true    if the Node specified by the indexes
   //          exists, false otherwise.
   //
   ///////////////////////////////////////////////////////////////////
   public boolean NodeExists (int module_id, int    node_id)
   throws BoundsException, IndexException, NullException {
     if (!ModuleExists (module_id)) {
       return false;
     }
     return modules[module_id].NodeExists (node_id);
   }
   ///////////////////////////////////////////////////////////////////
   //
   // Method:  SetEditable
   //
   // Purpose: This sets    the editable bit to the specified value.
   //
   ///////////////////////////////////////////////////////////////////
   public void SetEditable (boolean new_editable) {
     editable = new_editable;
   }
   ///////////////////////////////////////////////////////////////////
   //
   // Method:  SetFinal
   //
   // Purpose: This sets    the finalized bit to the specified value.
   //
   ///////////////////////////////////////////////////////////////////
   public void SetFinal (boolean    new_finalized) {
     finalized = new_finalized;
   }
   ///////////////////////////////////////////////////////////////////
   //
   // Method:  SetStable
   //
   // Purpose: Sets the stability of all    the Nodes in all the Modules
   //          to the specified value.
   //
   ///////////////////////////////////////////////////////////////////
   public void SetStable    (boolean new_stable)
   throws BoundsException, IndexException, NullException {
     for    (int i = 0; i <    num_modules; i++) {
       modules[i].SetStable (new_stable);
     }
   }
   ///////////////////////////////////////////////////////////////////
   //
   // Method:  ToggleNode
   //
   // Purpose: This toggles the stability value of the specified    Node.
   //
   ///////////////////////////////////////////////////////////////////
   public void ToggleNode (int module_id, int node_id)
   throws BoundsException, IndexException, NullException {
     Node node      = GetNode (module_id, node_id);
     boolean stable = node.IsStable ();
     node.SetStable (!stable);
   }
   ///////////////////////////////////////////////////////////////////
   //
   // Method:  ToSerial
   //
   // Purpose: Returns a    String representation of the map.
   //
   ///////////////////////////////////////////////////////////////////
   public String    ToSerial ()
   throws BoundsException, IndexException, NullException {
     String temp = "" + num_modules;
     for (int i = 0; i < num_modules; i++) {
       temp += delim + modules[i].ToSerial();
     }
     temp += delim + num_depends;
     for (int i = 0; i < num_depends; i++) {
       temp += delim + depends[i].ToSerial();
     }
     temp += delim + (finalized ? "t" : "f") + delim + (editable ? "t" : "f");
     return temp;
   }
   ///////////////////////////////////////////////////////////////////
   //
   // Method:  Valid
   //
   // Purpose: Returns true if Map is valid, false otherwise.
   //
   ///////////////////////////////////////////////////////////////////
   public boolean Valid () {
     try {
       Validate();
       return true;
     }
     catch (Exception e) {
       return false;
     }
   }
   ///////////////////////////////////////////////////////////////////
   //
   // Method:  Validate
   //
   // Purpose: Throws an    exception if the Map is    invalid.
   //
   ///////////////////////////////////////////////////////////////////
   public void Validate ()
   throws BoundsException, IndexException, NullException {
     if (num_modules < 0) {
       throw new BoundsException ("num_modules", num_modules, 0);
     }
     if (num_depends < 0) {
       throw new BoundsException ("num_depends", num_depends, 0);
     }
     // Validate modules //
     for (int i = 0; i < num_modules; i++) {
       Module module = null;
       try {
     module = modules[i];
       }
       catch (Exception e) {
     throw new IndexException ("modules", i);
       }
       if (module == null) {
     throw new NullException    ("modules", i);
       }
       module.Validate    ();
     }
     // Validate depends //
     for (int i = 0; i < num_depends; i++) {
       Depend depend =    null;
       try {
     depend = depends[i];
       }
       catch (Exception e) {
     throw new IndexException ("depends", i);
       }
       if (depend == null) {
     throw new NullException    ("depends", i);
       }
       depend.Validate    ();
       int source_module_id = depend.GetSourceModuleID    ();
       int source_node_id   = depend.GetSourceNodeID    ();
       int dest_module_id   = depend.GetDestModuleID    ();
       int dest_node_id     = depend.GetDestNodeID    ();
       if (!ModuleExists (source_module_id)) {
     throw new IndexException ("depends[" + i + "].source_module_id", source_module_id);
       }
       if (!ModuleExists (dest_module_id)) {
     throw new IndexException ("depends[" + i + "].dest_module_id", dest_module_id);
       }
       if (!NodeExists (source_module_id, source_node_id)) {
     throw new IndexException ("depends[" + i + "].source_node_id" +    source_node_id);
       }
       if (!NodeExists (dest_module_id, dest_node_id)) {
     throw new IndexException ("depends[" + i + "].dest_node_id" + dest_node_id);
       }
     }
   }
   ///////////////////////////////////////////////////////////////////
   //
   // Method:  Verbose
   //
   // Purpose: Returns a    human-readable String representation of    Map.
   //
   ///////////////////////////////////////////////////////////////////
   public String    Verbose    () {
     String temp    = "Map:    ["
                 + num_modules +    " modules, " + num_depends + " depends]\n"
                 + "  finalized = " + finalized + "\n";
     for (int i = 0; i <    num_modules; i++) {
       temp += "     modules[" + i + "] : ";
       try {
     temp += modules[i].Verbose() + "\n";
       }
       catch (Exception e) {
     temp +=    "INVALID\n";
       }
     }
     for    (int i = 0; i <    num_depends; i++) {
       temp += "     depends[" + i + "] : ";
       try {
     temp +=    depends[i].Verbose() + "\n";
       }
       catch (Exception e) {
     temp +=    "INVALID\n";
       }
     }
     return temp;
   }
   /////////////////////////////////////////////////////////////////////
   //
   // Method:  Verbose
   //
   // Purpose: Returns human-readable details about the specified
   //        Module and its dependencies.
   //
   ////////////////////////////////////////////////////////////////////
   public String Verbose (int module_id) {
     return Verbose (module_id, ANY);
   }
   /////////////////////////////////////////////////////////////////////
   //
   // Method:  Verbose
   //
   // Purpose: Returns human-readable details about the specified
   //        Node and its dependencies.
   //
   ////////////////////////////////////////////////////////////////////
   public String Verbose (int module_id, int node_id) {
     String temp = "";
     try {
       if (node_id == ANY) {
     temp +=    modules[module_id].Verbose();
       }
       else {
     temp += modules[module_id].GetName() + "."
               + modules[module_id].GetNode(node_id).Verbose() + "\n";
       }
       for (int dir = 0; dir < 2; dir++) {
     boolean to = (dir == 0);
     temp +=    (to ? "\nDepends upon:" : "\n\nAffects:");
     Depend hits[] = GetDepends (module_id, node_id, to);
     for (int i = 0; i < hits.length; i++) {
       Depend hit    = hits[i];
       int    mid    = (to ? hit.GetSourceModuleID() : hit.GetDestModuleID());
       int    nid    = (to ? hit.GetSourceNodeID()   : hit.GetDestNodeID());
       temp += "\n  " + modules[mid].GetName() + "."
                          + modules[mid].GetNode(nid).GetName()
                          + " (" + hit.GetProbability() + ")";
     }
       }
     }
     catch (Exception e) {
       temp +=    "\n ***    INVALID    ***\n";
       temp +=    "  (" +    e.getMessage() + ")";
     }
     return temp + "\n";
   }
 }
 ////////////////////////////////////////////////////////////////////////////