//: Node.java

////////////////////////////////////////////////////////////////////////////////
// Author: Miroslava Kaloper
// Overview: Creates a node object and looks for parents and children 
// Note:    One node / GO Term
// Modifications:
// July/15/99 - Mira - Created
// June/21/01 - Kane Tse - modified extensively to work with GOTree.java
///////////////////////////////////////////////////////////////////////////////

package goview;

import java.io.*;
import java.util.Vector;
import java.util.Enumeration;
import java.util.StringTokenizer;

public class Node {

  private String node; // obsolete variable?
  private String goNumber; // GO ID number
  private String desc = new String(); // GO Term, description of this node

  private Vector secondaryGONumbers = new Vector(); // secondary GO IDs

  // primary GO IDs of parents of this node
  private Vector parentGOids = new Vector(); 
  // primary GO IDs of children of this node
  private Vector childrenGOids = new Vector();

  // primary GO IDs of "parts" of this node
  private Vector parts = new Vector();

  // primary GO IDs of nodes that this node is a "part of"
  private Vector partOf = new Vector();

  private String type; // obsolete variable?
  private char symbol; // obsolete variable?

  private String flatFileLine; // the line from the flat-file that represents
  // the first occurrence of this GO term


/*************************************************************************
 *
 * Method:     Node() - class constructor
 * Purpose:    Creates a node representing a single GO Term
 * Parameters: String description - the GO Term for this node (text string)
 *             String goID - the GO ID number for this GO Term
 *             String parent - a single parent node for this GO Term
 *               (In the flat-file each GO Term has only one parent listed
 *                on the previous level, other parents are lines on the same 
 *                line).
 *             char fileSymbol - the first non-space character listed on
 *               the line of the flat-file containing this entry
 *             String line - the line of the flat file on which this GO term
 *               is located
 * Returns:    None.  Constructors cannot return any values
 *
 ************************************************************************/
  public Node(String description,
	      String goID,
	      String parent,
	      char fileSymbol,
	      String line) {
       desc = description;

       // handle cases where a node is assigned more than one GO ID
       Vector goNumbers = parseGOID(goID);
       Enumeration goIDEnum = goNumbers.elements();

       // assign goNumber to be the first (and presumably the primary) GO ID
       //  in the list of GO ids passed to this node
       goNumber = (String) goIDEnum.nextElement();
       while (goIDEnum.hasMoreElements()) {
	    secondaryGONumbers.addElement(goIDEnum.nextElement());
       }

       // dealing with parent/child relationships
       if (fileSymbol == '%') {
	    type = new String("instance of"); 
	    addParent(parent);	    
       }
       if (fileSymbol == '<') {
	    type = new String("part of");
	    addPartOf(parent);
	    fileSymbol = '%';
       }
       
       // disocvering if this is the root of the tree or not
       if (fileSymbol == '$') {
	    type = new String("root");
       }
       symbol = fileSymbol;

       flatFileLine = line;
  } // Node constructor


/*************************************************************************
 *
 * Method:     Node() - class constructor
 * Purpose:    Creates an empty GO node.
 * Parameters: None.
 * Returns:    Constructors cannot return any values
 * Notes:      This is useful for creating a node that will not be used
 *               for anything other than avoid null pointer errors.  The
 *               node created by this constructure should not be used for
 *               any non-transient data.
 * Example:    Create a Node() in the case of the parents of the root node.
 *               Since the root node has no parents, this method node can be
 *               used when the createNode(root) attempts to set root as the
 *               children of a "dummy node"
 *
 ************************************************************************/
  public Node () {
       desc = null;
       goNumber = null;
  } // Dummy node constructor

/*************************************************************************
 *
 * Method:     getDesc()
 * Purpose:    Accessor method to retrieve the textual GO Term of this node
 * Parameters: None.
 * Returns:    String - the text string descriptor of this node.
 *               An empty string is returned if this node has no text
 *               description
 *
 ************************************************************************/
  public String getDesc()  {
     return desc;
  } //getDesc

/*************************************************************************
 *
 * Method:     addChild()
 * Purpose:    Adds a child to this node to the list of children.
 * Parameters: String childID - the GO ID number of the child to be added
 *               to this node.
 * Returns:    None
 * Note:       This method does not validate the GO ID passed to it.  Also,
 *               if a GO ID has already been added to this node, it will not
 *               add the child's GO ID again.  This makes it important only to
 *               use primary GO IDs when adding children.
 *
 ************************************************************************/
  public void addChild(String childID) {
       if (childID == null) return;

       if (childrenGOids.contains(childID)) {
	    return;
       }
       else {
	    childrenGOids.addElement(childID);
       }
  }

/*************************************************************************
 *
 * Method:     addParent()
 * Purpose:    Adds a parent to this node to the list of parents.
 * Parameters: String parentID - the GO ID number of the parent to be added
 *               to this node.
 * Returns:    None
 * Note:       This method does not validate the GO ID passed to it.  Also,
 *               if a GO ID has already been added to this node, it will not
 *               add the parent's GO ID again.  This makes it important only to
 *               use primary GO IDs when added nodes parents.
 *
 ************************************************************************/
  public void addParent(String parentID) {
       if (parentID == null) return;
       
       if (parentGOids.contains(parentID)) {
	    return;
       }
       else {
	    parentGOids.addElement(parentID);
       }
  }

/*************************************************************************
 *
 * Method:     addPartOf()
 * Purpose:    Adds a node that is a "part of" this node to the list.
 * Parameters: String parentID - the GO ID number of the greater part of
 *               this node.
 * Returns:    None
 * Note:       This method does not validate the GO ID passed to it.  Also,
 *               if a GO ID has already been added to this node, it will not
 *               add parentID's  GO ID again.  This makes it important only to
 *               use primary GO IDs with this method.
 *
 ************************************************************************/
  public void addPartOf(String parentID) {
       if (parentID == null) return;

       if (partOf.contains(parentID)) {
	    return;
       }
       else {
	    partOf.addElement(parentID);
       }
  }
/*************************************************************************
 *
 * Method:     addPart()
 * Purpose:    Adds a part to this node to the list of parts to the list.
 * Parameters: String parentID - the GO ID number of the part to be added
 *               to this node.
 * Returns:    None
 * Note:       This method does not validate the GO ID passed to it.  Also,
 *               if a GO ID has already been added to this node, it will not
 *               add the part's GO ID again.  This makes it important only to
 *               use primary GO IDs when added nodes parts.
 *
 ************************************************************************/
  public void addPart(String partID) {
       if (partID == null) return;

       if (parts.contains(partID)) {
	    return;
       }
       else {
	    parts.addElement(partID);
       }
  }

/*************************************************************************
 *
 * Method:     getChildren()
 * Purpose:    Accessor method to retrieve the children of this node
 * Parameters: None.
 * Returns:    Vector - primary GO IDs of all the children of this node.
 *               An empty vector is returned if this node has no children.
 *
 ************************************************************************/
  public Vector getChildren() {
       return childrenGOids;
  }

/*************************************************************************
 *
 * Method:     getParents()
 * Purpose:    Accessor method to retrieve the parents of this node
 * Parameters: None.
 * Returns:    Vector - primary GO IDs of all the parents of this node.
 *               An empty vector is returned if this node has no parents.
 *
 ************************************************************************/
  public Vector getParents() {
       return parentGOids;
  }

/*************************************************************************
 *
 * Method:     getParts()
 * Purpose:    Accessor method to retrieve the parts of this node
 * Parameters: None.
 * Returns:    Vector - primary GO IDs of all the parts of this node.
 *               An empty vector is returned if this node has no parts.
 *
 ************************************************************************/
  public Vector getParts() {
       return parts;
  }

/*************************************************************************
 *
 * Method:     getPartOfs()
 * Purpose:    Accessor method to retrieve all nodes that this node is a 
 *               part of.
 * Parameters: None.
 * Returns:    Vector - primary GO IDs of all the nodes that this is a part
 *               of.
 *               An empty vector is returned if this node is not a part of
 *               any other node.
 *
 ************************************************************************/
  public Vector getPartOfs() {
       return partOf;
  }

/*************************************************************************
 *
 * Method:     getParents()
 * Purpose:    Accessor method to retrieve the parents of this node
 * Parameters: None.
 * Returns:    Vector - GO IDs of all the parents of this node.
 *               An empty vector is returned if this node has no parents.
 *
 ************************************************************************/
  public String getGOid() {
       return goNumber;
  }

/*************************************************************************
 *
 * Method:     getFlatFileline()
 * Purpose:    Accessor method to retrieve the flat-file line (from the GO
 *               file) in which this GO Term was first encountered as a node
 *               (but not solely as a parent of another node)
 *             "First encountered" means closest to the start of the file.
 * Parameters: None.
 * Returns:    String - the line from the flat-file.
 *
 ************************************************************************/
  public String getFlatFileLine() {
       return flatFileLine;
  }

/*************************************************************************
 *
 * Method:     toString()
 * Purpose:    Retrieves a string representation of this node, which is quite
 *               handy for debugging purposes.
 * Parameters: None.
 * Returns:    String - a string representation of this node.
 *
 ************************************************************************/
  public String toString() {
       String stringRepresentation = new String();

       stringRepresentation += " Node:\t" + desc + "\n";
       stringRepresentation += "   GO:\t" + goNumber + "\n";
       stringRepresentation += " Type:\t" + type + "\n";
       stringRepresentation += " Symb:\t" + symbol + "\n";
              
       stringRepresentation += " Prnt:\t" + getParentString() 
	    + "[" + getPartOfsString() + "]" 
	    + "\n";
       stringRepresentation += " Chld:\t" + getChildrenString() 
	    + "[" + getPartOfsString() + "]"
	    + "\n";

       return stringRepresentation;
       
  }

/*************************************************************************
 *
 * Method:     getParentString()
 * Purpose:    Retrieves a list of direct parents of this node.
 *               "Direct parent" = parents who are one level above this node.
 * Parameters: None.
 * Returns:    String - listing GO IDs of all immediate parents of this node,
 *               comma-delimited.
 *
 ************************************************************************/
  public String getParentString() {
       String parentGOidList = new String();
       Enumeration enum = (Enumeration) parentGOids.elements();;
       while (enum.hasMoreElements()) {
	    parentGOidList += enum.nextElement() + ", ";
       }
       return parentGOidList;
  }

/*************************************************************************
 *
 * Method:     getChildrenString()
 * Purpose:    Retrieves a list of direct children of this node.
 *               "Direct children" = chilren who are one level below this node.
 * Parameters: None.
 * Returns:    String - listing GO IDs of all immediate children of this node,
 *               comma-delimited.
 *
 ************************************************************************/
  public String getChildrenString() {
       String childrenGOidList = new String();
       Enumeration enum = (Enumeration) childrenGOids.elements();
       while (enum.hasMoreElements()) {
	    childrenGOidList += enum.nextElement() + ", ";
       }
       return childrenGOidList;
  }

/*************************************************************************
 *
 * Method:     getPartsString()
 * Purpose:    Retrieves a list of nodes who are part of this node.
 * Parameters: None.
 * Returns:    String - listing all parts of this node, comma-delimiated.  The 
 *               list returned contains GO IDs.
 *
 ************************************************************************/
  public String getPartsString() {
       String partGOidList = new String();
       Enumeration enum = (Enumeration) parts.elements();;
       while (enum.hasMoreElements()) {
	    partGOidList += enum.nextElement() + ", ";
       }
       return partGOidList;
  }

/*************************************************************************
 *
 * Method:     getPartOfsString()
 * Purpose:    Retrieves a list of nodes that this node is a part of.
 * Parameters: None.
 * Returns:    String - listing GO IDs of all nodes that this node is a part;
 *               the list is comma-delimated
 *
 ************************************************************************/
  public String getPartOfsString() {
       String partOfGOidList = new String();
       Enumeration enum = (Enumeration) partOf.elements();;
       while (enum.hasMoreElements()) {
	    partOfGOidList += enum.nextElement() + ", ";
       }
       return partOfGOidList;
  }

/*************************************************************************
 *
 * Method:     getParentCount()
 * Purpose:    Counts the number of parents of this node.
 * Parameters: None.
 * Returns:    int - the number of parents of this node.
 *
 ************************************************************************/  
  public int getParentCount() {
       return parentGOids.size();
  }

/*************************************************************************
 *
 * Method:     getChildrenCount()
 * Purpose:    Counts the number of parents of this node.
 * Parameters: None.
 * Returns:    int - the number of childrens of this node.
 *
 ************************************************************************/  
  public int getChildrenCount() {
       return childrenGOids.size();
  }

/*************************************************************************
 *
 * Method:     getPartOfCount()
 * Purpose:    Counts the number of nodes that this node is a part of
 * Parameters: None.
 * Returns:    int - the number of nodes that this node is a part of
 *
 ************************************************************************/  
  public int getPartOfCount() {
       return partOf.size();
  }

/*************************************************************************
 *
 * Method:     getPartsCount()
 * Purpose:    Counts the number of nodes that are parts of this node
 * Parameters: None.
 * Returns:    int - the number of nodes that are parts of this node
 *
 ************************************************************************/  
  public int getPartsCount() {
       return parts.size();
  }

/*************************************************************************
 *
 * Method:     parseGOIDs()
 * Purpose:    Takes a string of separate (presumably secondary) GO IDs
 *               and splits them.
 * Parameters: String - line containing multiple GO IDs, delimited by "GO: "
 *               presumably, this string is formatted as in the GO flat file
 * Returns:    Vector - containing one string for each GO ID parsed out of
 *               the string.
 *
 ************************************************************************/  
  private Vector parseGOID(String goIDs) {
       Vector splitGOIDs = new Vector();
       
       StringTokenizer st_goID = new StringTokenizer (goIDs, ", GO:");
       while (st_goID.hasMoreTokens()) {
	    String goID = st_goID.nextToken().trim();
	    if (!splitGOIDs.contains(goID)) {
		 splitGOIDs.addElement(goID);
	    }
       }
       return splitGOIDs;
  }

/*************************************************************************
 *
 * Method:     getSecondaryGONumbers()
 * Purpose:    Retrieves all secondary GO numbers assigned to the current node
 * Parameters: None
 * Returns:    Vector - containing one string for each secondary GO ID 
 *
 ************************************************************************/  
  public Vector getSecondaryGONumbers() {
       return secondaryGONumbers;
  }

} //class Node