/*******************************************************************************
 * This file is part of OpenNMS(R).
 *
 * Copyright (C) 2008-2012 The OpenNMS Group, Inc.
 * OpenNMS(R) is Copyright (C) 1999-2012 The OpenNMS Group, Inc.
 *
 * OpenNMS(R) is a registered trademark of The OpenNMS Group, Inc.
 *
 * OpenNMS(R) is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published
 * by the Free Software Foundation, either version 3 of the License,
 * or (at your option) any later version.
 *
 * OpenNMS(R) is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with OpenNMS(R).  If not, see:
 *      http://www.gnu.org/licenses/
 *
 * For more information contact:
 *     OpenNMS(R) Licensing <license@opennms.org>
 *     http://www.opennms.org/
 *     http://www.opennms.com/
 *******************************************************************************/

/* Generated By:JJTree: Do not edit this line. SimpleNode.java */
import java.util.Hashtable;
import java.lang.StringBuffer;
import java.util.Enumeration;
import java.util.TreeMap;
import java.util.Vector;

/**
 * The MIB parser was made by writing 2 files  <br>
 * <blockquote>
 *   ParseMib.jjt - a grammar for ASN1.  <br>
     *   SimpleNode.java - initially generated by JavaCC with additional fields  <br>
 *                     added that save important information.  <br>
 * </blockquote>
     * These are the only 2 files that should need to be edited for changes. <br><br>
 * The parser.jjt specified the important tokens to recognize.
 * When a token is recognized, a method can be called from this class. You can
 * use existing methods or add your own. For example, here is a typical example
 * of how information is saved from a token that has been scanned in the ASN.1
 * <c> <br><br>
 *      void SequenceOfVars() #TableOidVars : <br>
 *      { <br>
 *          Token t; <br>
 *      } <br>
 *      { <br>
 *          STUFF DELETED ... <br>
 *          { <br>
 *              jjtThis.setName(t.image); <br>
 *          } <br>
 *      } <br>
 * </c> <br><br>
 * The code above is called when a token is recognized in the ASN.1. This
 * would recognize something like: <br>
 * <c>SysOREntry ::= SEQUENCE {  </c><br>
 * and save the "image" field "SysOrentry" in the AST that is being generated
 * when tokens are found.
 * Note that not every token needs to have information saved from it. This
 * is because a small subset of information is output to the XML file that
 * OpenNms uses. <br>
 * When fields are saved in the jjt file, they can call methods in this file,
 * SimpleNode.java. This saves information to the Abstract Syntax Tree (AST)
     * which is built by the parser and can be later accessed through these methods.
 * Any number of new fields or methods can be added to SimpleNode.java if you
 * want to extend the parser. The initial SimpleNode.java was nearly just stub
 * code. The reason for using AST is that it can be repeatedly walked and more
 * information added as needed. This is in contrast to the small number of
 * tokens that may be on the stack at any time during lexical analysis or
 * parsing. This is useful because not all information can be determined at
 * parse time. It is simpler and more clear to build it up gradually. For
 * example, consider the AST walk methods, which must be called in this order
 * because the AST is decorated on each walk. More Symbol Table information
 * is added on each walk. <br>
 * <c>
 * collectTableInfo() <br>
 * collectTableIndexInfo() <br>
 * collectSequenceInfo() <br>
 * collectOids() <br>
 * collectTextualConventionsInfo() <br>
 * </c>
 * Note that all the walks could probably have been combined into 1 or 2
 * walks but this would have made the code less clear. Cpu time is cheap,
 * engineering time to understand code is expensive. The AST is not that
 * big so the walks are not really that expensive.
 *
 * The SimpleNode class has methods that:<br>
 * <blockquote>
 *    Walk the Abstract Syntax Tree (AST) to decorate the nodes.<br>
 *    Add information to the Symbol Table (ST) - various hash tables.<br>
 *    Emit the final XML representation of the important Object Identifiers (OIDS)<br>
 * </blockquote>
 *
 * @author John Rodriguez
 * @version 1.0
 * @since 8/23/2003 <br><br>
 *
 * For any problems with this code, please email <br><br>
 *
 *   John Rodriguez  "snmpfactotum@yahoo.com"
 *
 * and include the MIBs that this compiler could not handle.
 */

public class SimpleNode
    implements Node {
  /**
   * The symbol table (ST) is made up of several different Hashtables
   * of which oidNames is one.
   * This hashtable contains all the object identifier names.
   * The key is the oid, e.g. "lightsurf", the value is the full OID
   * This is so that they can be built up from the base oid str
   *   .iso.org.dod.internet.private
   * As a simplifying assumption, everything is assumed to be under the above.
   */
  static Hashtable oidNames = new Hashtable();

  /**
       * Keep every variable that was in a ASN.1 table in a symbol table (hashtable).
   * This is because variables in an ASN.1 table have different xml printed.
   * Saving them in a symbol table allows gathering them when discovered in
   * the ASN.1
   * For example, in a non-table it would appear as: <br>
   * <c>instance=".0"</c>
   * while in a table it would appear as (depending on the index variable name): <br>
   * <c>instance="ifTableIndex"</c> <br>
   * name/value oidName/tableName
   */
  static Hashtable oidVarsTableName = new Hashtable();

  /**
   * A MIB table declaration will have an entry like: <br>
   *   auiTable OBJECT-TYPE  <br>
   *      SYNTAX SEQUENCE OF AuiEntry ... <br>
   * Save the entry ("AuiEntry") as the  key, and  the name ("auiTable")
   * as the value.
   */
  static Hashtable entryNameAndTableName = new Hashtable();

  /**
   * Save the index OID of a table as key=tableName, value=indexName
   */
  static Hashtable tableAndIndex = new Hashtable();

  /**
   * Save TEXTUAL-CONVENTION names and the base type in this table as
   * key=type before TEXTUAL-CONVENTION, value=baseType
   */
  static Hashtable typeNameTable = new Hashtable();

  /**
   * This is an ordered list of OIDS used for output at the end. As
   * the OIDS are discovered in the AST, they are added to the ST and this
   * list. The list is necessary because Hashtables do not maintain the order
   * that the OIDS were inserted.
   */
  static Vector orderList = new Vector();

  /**
   * This String just gives a shortcut so that we do not have to parse everything.
   */
  static final String rfc1155TextOID = ".iso.org.dod.internet";

  /**
   * This String just gives a shortcut so that we do not have to parse everything.
   */
  static final String rfc1155NumericOID = ".1.3.6.1";

  /**
   * This String just gives a shortcut so that we do not have to parse everything.
   */
  static final String baseTextOID = ".iso.org.dod.internet.private";

  /**
   * This String just gives a shortcut so that we do not have to parse everything.
   */
  static final String baseNumericOID = ".1.3.6.1.4";

  /**
   * This string is catenated on an alias that is greater then 19 chars
   * This is an rrd limitation.
   */
  static final String TOO_LONG = "TOOLONG";
  static final int tooLongSize = 19;

  /**
   * Every node has 1 and only 1 parent.
   */
  protected Node parent;

  /**
   * A node may have 0 or more children. This is kept in an array for easy
   * walking.
   */
  protected Node[] children;

  /**
   * Every node has a unique id.
   */
  protected int id;

  protected ParseMib parser;

  /**
   * Some String fields have this default String so we can tell if
   * they have been assigned or not.
   */
  static final String DEFAULT = "default";

  /**
   * The name found in the MIB for an OID. This is for the string part
   * of the OID. By saving every text OID name, we can later output the
   * entire text name of an OID by gradually building up the name based
   * on ancestors text names.
   */
  protected String identifier_text = DEFAULT;
  protected String identifier_parent_text = DEFAULT;

  /**
   *  for searches of the tree to see whether this node has been visited
   */
  protected boolean visited = false;

  /**
   *  mark every OID variable that is in a table, done with a walk of the AST
   */
  protected boolean isOidInTable = false;

  protected static boolean printDebug = false;

  static {
    try {
      if (printDebug) {
        System.out.println("building oidNames of oids");
        // put the numeric and text oid bases in the hashtable
        // eventually, these could be parsed from imports
        //
        // this can get things started with a few basic declarations
        // that are commonly used
        //   .iso/.1
        //   .iso.org.dod.internet.private.enterprises/.1.3.6.1.4.1
      }
      OidValues oids = new OidValues();
      oids.setTextOid(".iso");
      oids.setNumericOid(".1");
      oidNames.put("iso", oids);

      // build up some of the oids that are from RFC1155-SMI
      // directory, mgmt, experimental, private, enterprises
      oids = new OidValues();
      oids.setTextOid(rfc1155TextOID + "." + "directory");
      oids.setNumericOid(rfc1155NumericOID + ".1");
      oidNames.put("directory", oids);

      oids = new OidValues();
      oids.setTextOid(rfc1155TextOID + "." + "mgmt");
      oids.setNumericOid(rfc1155NumericOID + ".2");
      oidNames.put("mgmt", oids);

      oids = new OidValues();
      oids.setTextOid(rfc1155TextOID + "." + "experimental");
      oids.setNumericOid(rfc1155NumericOID + ".3");
      oidNames.put("experimental", oids);

      oids = new OidValues();
      oids.setTextOid(rfc1155TextOID + "." + "private");
      oids.setNumericOid(rfc1155NumericOID + ".4");
      oidNames.put("private", oids);

      oids = new OidValues();
      oids.setTextOid(baseTextOID + "." + "enterprises");
      oids.setNumericOid(baseNumericOID + ".1");
      oidNames.put("enterprises", oids);
    }
    catch (Throwable e) {
      System.err.println("exception during oidNames init" + e.getMessage());
    }
  }

  /**
   * turn debug on or off.
   */
  public static void setDebug(boolean b) {
    printDebug = b;
  }

  /**
   * Constructor for a node.
   *
   * @param i is a unique id
   */

  public SimpleNode(int i) {
    id = i;
  }

  /**
   * Constructor for a node.
   *
   * @param p is the parser.
   * @param i is the unique id.
   */

  public SimpleNode(ParseMib p, int i) {
    this(i);
    parser = p;
  }

  /**
   * Get the unique id of the node.
   */

  public int getId() {
    return id;
  }

  /**
   * Return a boolean indicating whether this node has been visited previously or not. The visited boolean may be reset
   * between walks.
   */

  public boolean getVisited() {
    return visited;
  }

  /**
   * Set whether this node has been visited previously.
   *
   * @param b is the value to set visited
   */

  public void setVisited(boolean b) {
    visited = b;
  }

  /**
   * For some nodes, the parser will save information found in the MIB
   * declaration. The jjt will have a construct like Token t, and this
   * will call this method with a text name to save.
   *
   * @param str is the text from the MIB construct to save.
   */

  public void setName(String str) {
    identifier_text = str;
  }

  /**
   * During parsing, certain MIB constructs will have caused a save of the
   * text name. This routine gets that text.
   */

  public String getName() {
    return identifier_text;
  }

  /**
   * This is a convenience method to save the name of the parent node. It
   * would have been easy to walk back up the tree and get the parent.
   *
   * @param str is the name of the parent found in the MIB.
   */

  public void setParentName(String str) {
    identifier_parent_text = str;
  }

  /**
   * Get the name of the parent node found during MIB parsing.
   */

  public String getParentName() {
    return identifier_parent_text;
  }

  /**
   * In order to declare a MIB table, one has to use a SEQUENCE declaration
   * followed by 1 or more OIDS. This just records the fact an OID is to
   * be part of a table.
   *
   * @param b set true or false whether this OID is part of a table.
   */

  public void setIsOidInTable(boolean b) {
    isOidInTable = b;
  }

  /**
   * Was this OID part of a MIB table.
   */

  public boolean getIsOidInTable() {
    return isOidInTable;
  }

  public void jjtOpen() {
  }

  public void jjtClose() {
  }

  public void jjtSetParent(Node n) {
    parent = n;
  }

  public Node jjtGetParent() {
    return parent;
  }

  public void jjtAddChild(Node n, int i) {
    if (children == null) {
      children = new Node[i + 1];
    }
    else if (i >= children.length) {
      Node c[] = new Node[i + 1];
      System.arraycopy(children, 0, c, 0, children.length);
      children = c;
    }
    children[i] = n;
  }

  public Node jjtGetChild(int i) {
    return children[i];
  }

  public int jjtGetNumChildren() {
    return (children == null) ? 0 : children.length;
  }

  /**
   * You can override these two methods in subclasses of SimpleNode to
   * customize the way the node appears when the tree is dumped.  If
   * your output uses more than one line you should override
   * toString(String), otherwise overriding toString() is probably all
   *  you need to do.
   */

  public String toString() {
    return ParseMibTreeConstants.jjtNodeName[id]
        + " " + this.getName() + " visited=" +
        ( (getVisited() == true) ? "true" : "false") + " children=" +
        ( (children == null) ? "0" :
         "" + children.length);
  }

  public String toString(String prefix) {
    return prefix + toString();
  }

  /**
   * Override this method if you want to customize how the node dumps
   * out its children.
   */

  public void dump(String prefix) {
    if (printDebug) {
      System.out.println(toString(prefix));
    }
    if (children != null) {
      for (int i = 0; i < children.length; ++i) {
        SimpleNode n = (SimpleNode) children[i];
        if (n != null) {
          n.dump(prefix + " ");
        }
      }
    }
  }

  /**
   * Walk through the AST and mark every node as not being visited.
   * Some tree walks, like a depth first search, would require this.
   * This keeps nodes from being revisited.
   */
  public void markNotVisited() {
    //if (printDebug) System.out.println("markNotVisited node=" + this.toString());
    this.setVisited(false);
    if (children != null) {
      for (int i = 0; i < children.length; ++i) {
        SimpleNode n = (SimpleNode) children[i];
        if (n != null) {
          n.setVisited(false);
          n.markNotVisited();
        }
      }
    }
  }

  /**
   * Walk the abstract syntax tree and collect the text oids
   */
  public void collectOids() {
    //if (printDebug) System.out.println("collectOids node=" + this.toString());
    if (this.getVisited() == true) {
      return;
    }
    boolean foundDeclOID = ParseMibTreeConstants.jjtNodeName[this.id].equals(
        "DeclOID") ||
        ParseMibTreeConstants.jjtNodeName[this.id].equals("ModuleIdentity");
    boolean processMultipleOids = false;

    if (children != null) {
      // if (printDebug) System.out.println("Found DeclOID=" + foundDeclOID + " node= " + toString());
      // build the OIDs
      // there are some children under this node like:
      //  DeclOID default children=3
      //    ObjectIdentifier smsFileQueue children=0
      //    GetTypeIdentifier Gauge32 visited=false children=0
      //    GetAccessIdentifier read-only visited=false children=0
      //    Parent products children=0
      //    PartialOID 7 children=0
      // get all that info from the children
      // this example would be something like
      //   iso...products.smsFileQueue
      //   .1...2.7   if products was 2 (products is already saved in the ST)
      String parent = null;
      String textOid = null;
      String numericOid = null;
      String typeId = null;
      String accessName = OidValues.NOT_ACCESSIBLE;

      // walk through the children and collect information
      for (int i = 0; i < children.length; ++i) {
        SimpleNode n = (SimpleNode) children[i];
        if (n != null) {
          // if (printDebug && foundDeclOID) System.out.println("DeclOID child=" + toString());

          if (ParseMibTreeConstants.jjtNodeName[n.getId()].equals("Parent")) {
            parent = n.identifier_parent_text;
            textOid = n.identifier_text;
          }
          else if (ParseMibTreeConstants.jjtNodeName[n.getId()].equals(
              "PartialOID")) {
            numericOid = n.identifier_text;
          }
          else if (ParseMibTreeConstants.jjtNodeName[n.getId()].equals(
              "GetTypeIdentifier")) {
            typeId = n.identifier_text;
          }
          else if (ParseMibTreeConstants.jjtNodeName[n.getId()].equals(
              "GetAccessIdentifier")) {
            accessName = n.identifier_text;
          }
          else if (ParseMibTreeConstants.jjtNodeName[n.getId()].equals(
              "MultipleOids")) {
            processMultipleOids = true; // more complicated tree walk
          }

        } // end if

        if (n != null) {
          n.collectOids();
          n.setVisited(true);
        }
      } // end for

      if (foundDeclOID) {
        // now that we have all the info, look in the hash table, the parent
        // should be in there, from the parent we build new oids for the currentOid
        if (printDebug) {
          System.out.println("found parent=" + parent + " textOid=" + textOid +
                             " numericOid=" + numericOid);
        }
        String tableName = (String) oidVarsTableName.get(textOid);

        if (tableName != null) {
          if (printDebug) {
            System.out.println("the OID " + textOid + " is in table=" +
                               tableName);
          }
          if (printDebug) {
            System.out.println("the index name=" +
                               (String) tableAndIndex.get(tableName));
          }
        }

        // get the oid record out of the hashtable
        OidValues parentOid = (OidValues) oidNames.get(parent);

        if (printDebug) {
          System.out.println("found numericOid=" + numericOid);

        }
        if (processMultipleOids) {
          String curTextOid = textOid; // add to ST after loops
          String curNumericOid = numericOid; // add to ST after loops

          if (printDebug) {
            System.out.println("process multiple oids in a list");
            // this is a declaration like
            // mgmt OBJECT IDENTIFIER ::= { iso org(3) dod(6) internet(1) mgmt(2) }
            // that requires walking the tree and adding a piece at a time
            // go down the tree and add the MultipleOids subtrees a piece at
            // a time.
            // the tree has some nodes like:
            // already have the parent from above.
            // note that the parent has both the parent and child names in the node
            // n.identifier_parent_text is the parent
            // n.identifier_text is the child only when there is 1 id in the {}
            /*
                             DeclOID default visited=false children=6
             ObjectIdentifier mgmt visited=false children=0
             Parent mgmt visited=false children=0
             MultipleOids default visited=false children=2
              ChildTextIdentifier org visited=false children=0
              ChildNumericIdentifier 3 visited=false children=0
             MultipleOids default visited=false children=2
              ChildTextIdentifier dod visited=false children=0
              ChildNumericIdentifier 6 visited=false children=0
             MultipleOids default visited=false children=2
              ChildTextIdentifier internet visited=false children=0
              ChildNumericIdentifier 1 visited=false children=0
             MultipleOids default visited=false children=2
              ChildTextIdentifier mgmt visited=false children=0
              ChildNumericIdentifier 2 visited=false children=0
             */
            // walk through the children and collect information
          }
          for (int i = 0; i < children.length; ++i) {
            SimpleNode nouter = (SimpleNode) children[i];
            if (nouter != null) {

              if (ParseMibTreeConstants.jjtNodeName[nouter.getId()].equals(
                  "MultipleOids")) {

                for (int j = 0; j < nouter.jjtGetNumChildren(); ++j) {
                  SimpleNode n = (SimpleNode) nouter.jjtGetChild(j);
                  if (n != null) {

                    if (ParseMibTreeConstants.jjtNodeName[n.getId()].equals(
                        "ChildTextIdentifier")) {
                      textOid = n.identifier_text;
                    }
                    else if (ParseMibTreeConstants.jjtNodeName[n.getId()].
                             equals("ChildNumericIdentifier")) {
                      if (printDebug) {
                        System.out.println(
                            "processing multiple ids in a declaration");
                      }
                      numericOid = n.identifier_text;

                      // we have everything that we need to add to the ST
                      OidValues currentOid = new OidValues();
                      String fullOid = parentOid.getTextOid();
                      if (printDebug) {
                        System.out.println("found fullOid * =" + fullOid);

                        // build the text oid
                      }
                      fullOid = fullOid + "." + textOid;
                      currentOid.setTextOid(fullOid);
                      if (printDebug) {
                        System.out.println("added text oid * : " + fullOid);

                        // build the numeric oid
                      }
                      fullOid = parentOid.getNumericOid();
                      fullOid = fullOid + "." + numericOid;
                      currentOid.setNumericOid(fullOid);
                      if (printDebug) {
                        System.out.println("added numeric oid * : " + fullOid);

                      }
                      accessName = OidValues.READ_ONLY;
                      currentOid.setAccess(accessName);
                      if (printDebug) {
                        System.out.println("added access=" + accessName);

                      }
                      oidNames.put(textOid, currentOid);
                      // The Hashtables do not save in order so maintain a list that
                      // will have the correct order on output
                      orderList.addElement(textOid);

                      // so that as we walk down the oids, the prev becomes the parent
                      parentOid = (OidValues) oidNames.get(textOid);
                    }

                  } // end if

                } // end for j inner

                // now add the child of all the children just added
                OidValues currentOid = new OidValues();
                String fullOid = parentOid.getTextOid();
                if (printDebug) {
                  System.out.println("found fullOid ** =" + fullOid);

                  // build the text oid
                }
                fullOid = fullOid + "." + curTextOid;
                currentOid.setTextOid(fullOid);
                if (printDebug) {
                  System.out.println("added text oid ** : " + fullOid);

                  // build the numeric oid
                }
                fullOid = parentOid.getNumericOid();
                fullOid = fullOid + "." + curNumericOid;
                currentOid.setNumericOid(fullOid);
                if (printDebug) {
                  System.out.println("added numeric oid ** : " + fullOid);

                }
                accessName = OidValues.READ_ONLY;
                currentOid.setAccess(accessName);
                if (printDebug) {
                  System.out.println("added access=" + accessName);

                }
                oidNames.put(curTextOid, currentOid);
                // The Hashtables do not save in order so maintain a list that
                // will have the correct order on output
                orderList.addElement(curTextOid);

              }
            }
          } // end for i outer

        }
        else {
          OidValues currentOid = new OidValues();
          String fullOid = null;
          try {
            fullOid = parentOid.getTextOid();
          }
          catch (Throwable t) {
            System.err.println("ERROR: can't find parent '" + parent +
                               "' for textOid '" + textOid +
                "'\nFind which MIB the parent is defined in and add that to the command line\n");
            if (printDebug) {
              dumpOidNamesSymbolTable();
            }
            System.exit(Errors.INCLUDE_MIB_MISSING);
          }
          if (printDebug) {
            System.out.println("found fullOid *** =" + fullOid);

            // build the text oid
          }
          fullOid = fullOid + "." + textOid;
          currentOid.setTextOid(fullOid);
          if (printDebug) {
            System.out.println("added text oid *** : " + fullOid);

            // build the numeric oid
          }
          fullOid = parentOid.getNumericOid();
          fullOid = fullOid + "." + numericOid;
          currentOid.setNumericOid(fullOid);
          if (printDebug) {
            System.out.println("added numeric oid *** : " + fullOid);

          }
          if (typeId != null) {
            currentOid.setTypeId(typeId);
            if (printDebug) {
              System.out.println("added typeId=" + typeId);
            }
          }
          else {
            if (printDebug) {
              System.out.println("typeId was null and not added");
            }
          }

          currentOid.setAccess(accessName);
          if (printDebug) {
            System.out.println("added access=" + accessName);

          }
          oidNames.put(textOid, currentOid);
          // The Hashtables do not save in order so maintain a list that
          // will have the correct order on output
          orderList.addElement(textOid);

          /*
                  String fullOid = (String)oidNames.get(parent);
               if (printDebug) System.out.println("found fullOid **** =" + fullOid);
                  fullOid = fullOid + "." + textOid;
                  oidNames.put(textOid, fullOid);
               if (printDebug) System.out.println("added to oidNames: " + fullOid);
           */
        }
      } // end if foundDeclOID

    } // end if children != null
  } // end collectOIDS

  /**
   * Walk the abstract syntax tree and collect information about
   * any OID in a table
   */
  public void collectTableInfo() {
    //if (printDebug) System.out.println("collectTableInfo node=" + this.toString());

    if (this.getVisited() == true) {
      return;
    }

    //   auiTable OBJECT-TYPE
    //      SYNTAX SEQUENCE OF AuiEntry ...
    // Save the name ("auiTable") as the value, and the entry ("AuiEntry") as the key
    // The entry is the key so that we can search it later by entry when we get the
    // sequence entry (in collectSequenceInfo)
    //  entryNameAndTableName is the symbol table Hashtable
    // The tree looks like:
    //    DeclOID default visited=false children=4
    //      ObjectIdentifier auiTable visited=false children=0
    //      TableSequenceOf AuiEntry visited=false children=0
    //      GetAccessIdentifier read-only visited=false children=0
    //      Parent auiTable visited=false children=0
    //      PartialOID 1 visited=false children=0
    boolean declOidFound = ParseMibTreeConstants.jjtNodeName[this.id].equals(
        "DeclOID");
    // walk through and see if it contains a TableSequenceOf node

    if (children != null) {
      // walk through the children and collect information
      String tableName = null;
      String entryName = null;
      for (int i = 0; i < children.length; ++i) {
        SimpleNode n = (SimpleNode) children[i];
        if (n != null) {
          if (ParseMibTreeConstants.jjtNodeName[n.getId()].equals("Parent")) {
            tableName = n.identifier_text;
          }
          else if (ParseMibTreeConstants.jjtNodeName[n.getId()].equals(
              "TableSequenceOf")) {
            // could mark the parent as a table here if we wanted to
            entryName = n.identifier_text;
          }

        } // end if

        if (n != null) {
          n.collectTableInfo();
          n.setVisited(true);
        }
      } // end for

      // we know we have found a table if entryName != null
      if (declOidFound && entryName != null) {
        if (printDebug) {
          System.out.println("collectTableInfo adding " + entryName + "/" +
                             tableName);
        }
        entryNameAndTableName.put(entryName, tableName);
      }
    }
  } // end collectTableInfo

  /**
   * Walk the abstract syntax tree and collect SEQUENCE information about
   * any OID in a table
   */
  public void collectSequenceInfo() {
    //if (printDebug) System.out.println("collectSequenceInfo node=" + this.toString());

    if (this.getVisited() == true) {
      return;
    }

    // Look for a tree starting with "TableOidVars"
    // 1) the first child is the index of the table
    // 2) add every entry with the table name entry as the value (from example below "AuiEntry")
    //  TableOidVars AuiEntry visited=false children=5
    //    IdentifierInSequenceOfVars auiTableIndex visited=false children=0
    //    IdentifierInSequenceOfVars activeSessions visited=false children=0
    //    IdentifierInSequenceOfVars inactiveSessions visited=false children=0
    //    IdentifierInSequenceOfVars openCursors visited=false children=0
    //    IdentifierInSequenceOfVars accounts visited=false children=0

    String entryName = this.getName();
    String tableName = (String) entryNameAndTableName.get(entryName);

    if (children != null) {
      // walk through the children and collect information
      String indexName = null;
      for (int i = 0; i < children.length; ++i) {
        SimpleNode n = (SimpleNode) children[i];

        if (n.getIsOidInTable()) {
          if (printDebug) {
            System.out.println("adding OID " + n.getName() + " to table");
            // put all the OID vars in a symbol table (hashtable) oidName/tableName
          }
          oidVarsTableName.put(n.getName(), tableName);
        }

        if (n != null) {
          n.collectSequenceInfo();
          n.setVisited(true);
        }
      } // end for

    }

  } // end collectSequenceInfo

  /**
   * Walk the abstract syntax tree and collect information about
   * the index of a table. By convention, the index of a table is the
   * first variable in the MIB SEQUENCE delcaration.
   */
  public void collectTableIndexInfo() {
    //if (printDebug) System.out.println("collectTableIndexInfo node=" + this.toString());

    if (this.getVisited() == true) {
      return;
    }

    //   auiTable OBJECT-TYPE
    //      SYNTAX SEQUENCE OF AuiEntry ...
    // Save the name ("auiTable") as the value, and the entry ("AuiEntry") as the key
    // The entry is the key so that we can search it later by entry when we get the
    // sequence entry (in collectSequenceInfo)
    //  entryNameAndTableName is the symbol table Hashtable
    // The tree looks like:
    //     TableOidVars AuiEntry visited=false children=5
    //         IdentifierInSequenceOfVars auiTableIndex visited=false children=0
    //         IdentifierInSequenceOfVars activeSessions visited=false children=0
    //         IdentifierInSequenceOfVars inactiveSessions visited=false children=0
    //         IdentifierInSequenceOfVars openCursors visited=false children=0
    //         IdentifierInSequenceOfVars accounts visited=false children=0

    String entryName = this.getName();
    String tableName = (String) entryNameAndTableName.get(entryName);

    if (children != null) {
      // walk through the children and collect information
      String indexName = null;
      for (int i = 0; i < children.length; ++i) {
        SimpleNode n = (SimpleNode) children[i];
        if (i == 0) {
          // the index is always the first child
          if (ParseMibTreeConstants.jjtNodeName[n.getId()].equals(
              "IdentifierInSequenceOfVars")) {
            indexName = n.identifier_text;
          }
        } // end if

        if (n.getIsOidInTable()) {
          // this was set during parsing
          if (printDebug) {
            System.out.println("adding OID " + n.getName() + " to table");
            // put all the OID vars in a symbol table (hashtable) oidName/tableName
          }
          oidVarsTableName.put(n.getName(), tableName);
        }

        if (n != null) {
          n.collectTableIndexInfo();
          n.setVisited(true);
        }
      } // end for

      // we know we have found a table if indexName |= null
      if (indexName != null) {
        if (printDebug) {
          System.out.println("collectTableIndexInfo indexName=" + indexName);
        }
        if (printDebug) {
          System.out.println("collectTableIndexInfo entryName=" + entryName);

        }
        if (printDebug) {
          System.out.println("collectTableIndexInfo tableName=" + tableName);
        }
        tableAndIndex.put(tableName, indexName);
      }
    }

  } // end collectTableIndexInfo

  /**
   * Walk the abstract syntax tree and collect information about
   * any TEXTUAL-CONVENTIONS. The reason for collecting these in
   * a symbol table is that this relates the underlying type to
   * the text name and it is the underlying type that would need
   * to be printed in the xml.
   */
  public void collectTextualConventionsInfo() {
    //if (printDebug) System.out.println("collectTextualConventionsInfo node=" + this.toString());

    if (this.getVisited() == true) {
      return;
    }

    // Look for a tree starting with "TextConvention" or "Assignment"
    // 0) the node TextConvention has some type name
    // 1) the first child is the base type, that is referred to by the type name above
    //    TextConvention VasStates visited=false children=1
    //     GetTypeIdentifier Integer32 visited=false children=0

    boolean textConventionFound = ParseMibTreeConstants.jjtNodeName[this.id].
        equals("TextConvention") ||
        ParseMibTreeConstants.jjtNodeName[this.id].equals("Assignment");
    // walk through and find the index of the table which is the first child

    String typeName = this.getName();
    String baseTypeName = null; // will be in the child

    if (children != null) {
      // walk through the children and collect information
      String indexName = null;
      for (int i = 0; i < children.length; ++i) {
        SimpleNode n = (SimpleNode) children[i];

        if (textConventionFound) {
          if (printDebug) {
            System.out.println("adding OID " + n.getName() + "/" + typeName +
                               " to typeNametable");
            // put all the OID vars in a symbol table (hashtable) oidName/tableName
          }
          baseTypeName = n.getName();
          typeNameTable.put(typeName, baseTypeName);
        }

        if (n != null) {
          n.collectTextualConventionsInfo();
          n.setVisited(true);
        }
      } // end for

    }

  } // end collectTextualConventionInfo

  /**
   * Walk the symbol tables and output XML
   */
  public void writeOids() {

    // write something like:
    // <mibObj oid=".1.3.6.1.2.1.2.2.1.10" instance="ifIndex" alias="ifInOctets" type="counter"/>
    StringBuffer sb = new StringBuffer();
    OidValues oidValues = null;
    TreeMap sortedMap = new TreeMap();

    if (printDebug) {
      System.out.println("Sorted OIDS from Vector");
    }
    sb = new StringBuffer();
    for (int i = 0; i < orderList.size(); i++) {
      String name = (String) orderList.elementAt(i);
      oidValues = (OidValues) oidNames.get(name);
      if (! (oidValues.getTypeId().equals("DEFAULT") ||
             oidValues.getAccess().equals(OidValues.NOT_ACCESSIBLE))) {
        String instanceVar = "0"; // TBD get the table instance var
        String aliasVar = oidValues.getTextOid();
        int index = aliasVar.lastIndexOf(".") + 1;
        String lastOidStr = aliasVar.substring(index);
        String tableName = (String) oidVarsTableName.get(lastOidStr);
        String numericOid = oidValues.getNumericOid();
        String typeName = oidValues.getTypeId();
        String typeFromTable = (String) typeNameTable.get(typeName);
        if (typeFromTable != null) {
          typeName = typeFromTable; // this gets the base type

        }
        if (tableName != null) {
          instanceVar = (String) tableAndIndex.get(tableName);
        }
        // There is a 19 char rrd limitation. Catenate a string onto the alias.
        if (lastOidStr.length() > tooLongSize) {
          lastOidStr = lastOidStr + TOO_LONG;
        }
        sb.append("<mibObj oid=\"").append(numericOid).append("\" ");
        sb.append("instance=\"").append(instanceVar).append("\" ");
        sb.append("alias=\"").append(lastOidStr).append("\" ");
        sb.append("type=\"").append(typeName).append("\" />").append("\n");
        System.out.print(sb.toString());
        sortedMap.put(numericOid, sb.toString());
        sb = new StringBuffer();

      }
      else {
        if (printDebug && oidValues.getTypeId().equals("DEFAULT")) {
          System.out.println("skipping oid with DEFAULT type, oid=" +
                             oidValues.getTextOid());
        }
        if (printDebug && oidValues.getAccess().equals(OidValues.NOT_ACCESSIBLE)) {
          System.out.println("skipping oid with no ACCESS, oid=" +
                             oidValues.getAccess());
        }
      }
    }

  } // end writeOIDS

  /**
   * Dump the oidNames symbol tables - primarily debugging routine
   */
  public void dumpOidNamesSymbolTable() {

    StringBuffer sb = new StringBuffer();
    OidValues oidValues = null;
    String key = null;
    String oidName = null;

    sb.append("Symbol Table oidNames for text OID/OidValues\n");
    for (Enumeration e = oidNames.keys(); e.hasMoreElements(); ) {
      key = (String) e.nextElement();
      oidValues = (OidValues) oidNames.get(key);
      sb.append(key + "/" + oidValues.toString()).append("\n");
    }

    if (printDebug) {
      System.out.println(sb.toString());
    }
  }

  /**
   * Dump the symbol tables - primarily debugging routine
   */
  public void dumpSymbolTables() {

    StringBuffer sb = new StringBuffer();
    OidValues oidValues = null;
    String key = null;
    String oidName = null;
    String entryName = null;
    String indexName = null;
    String baseType = null;

    dumpOidNamesSymbolTable();

    sb.append("Symbol Table oidVarsTableName for tableName/OidName\n");
    for (Enumeration e = oidVarsTableName.keys(); e.hasMoreElements(); ) {
      key = (String) e.nextElement();
      oidName = (String) oidVarsTableName.get(key);
      sb.append(key + "/" + oidName).append("\n");
    }

    sb.append("Symbol Table entryNameAndTableName for entryName/tableName\n");
    for (Enumeration e = entryNameAndTableName.keys(); e.hasMoreElements(); ) {
      key = (String) e.nextElement();
      entryName = (String) entryNameAndTableName.get(key);
      sb.append(key + "/" + entryName).append("\n");
    }

    sb.append("Symbol Table tableAndIndex for tableName/indexName\n");
    for (Enumeration e = tableAndIndex.keys(); e.hasMoreElements(); ) {
      key = (String) e.nextElement();
      indexName = (String) tableAndIndex.get(key);
      sb.append(key + "/" + indexName).append("\n");
    }

    sb.append("Symbol Table typeNameTable for type/baseType\n");
    for (Enumeration e = typeNameTable.keys(); e.hasMoreElements(); ) {
      key = (String) e.nextElement();
      baseType = (String) typeNameTable.get(key);
      sb.append(key + "/" + baseType).append("\n");
    }

    if (printDebug) {
      System.out.println(sb.toString());

    }
  } // end dumpSymbolTables

}
