/**
 * @(#)Grammar.java	17.03.2004
 * 
 * @author kst
 */
package commons.chartparser;
import java.util.ArrayList;
import java.util.List;
/**
 * Repraesentiert einen Baum, der Woerter speichert. Gedacht zur Darstellung eines Syntaxbaums. Die
 * toString()-Methode wandelt den Baum in ein Listendarstellung um: "{S{NP{DET{der} N{Hund}}
 * VP{VI{bellt}}}}"
 */
@SuppressWarnings("unchecked")
public class STree
{

private String name   = "";
private Object object = "";
private List   nodes  = null;
private STree  parent = null;
private int    pos    = 0;
static int     depth  = 0;   // nicht threadsafe!

public STree getRoot ()
{
   return (parent == null ? this : parent.getRoot());
}

/**
 * Konstruktor wird nur intern verwendet, wenn es einen Parent gibt
 */
private STree(STree parent, String name, Object object)
{
   this.parent = parent;
   this.name = name;
   this.object = object;
}

/**
 * public Konstruktor, Parent ist null.
 */
public STree()
{
   this.parent = null;
   this.name = "";
   this.object = null;
}

/**
 * Fuegt ein Kind-Objekt hinzu und gibt es zurueck.
 */
public STree addChild (String v, Object obj)
{
   STree c = new STree(this, v, obj);
   if (this.nodes == null)
   {
      this.nodes = new ArrayList();
   }
   this.nodes.add(c);
   return c;
}

public String getName ()
{
   return name;
}

public Object getObject ()
{
   return object;
}

public boolean hasChildren ()
{
   return nodes != null && nodes.size() > 0;
}

public boolean hasMoreChildren ()
{
   return nodes != null && pos < nodes.size();
}

public STree firstChild ()
{
   this.pos = 0;
   STree child = null;
   if (hasChildren())
   {
      child = (STree) nodes.get(pos++);
   }
   return child;
}

public STree nextChild ()
{
   STree child = null;
   if (hasChildren() && pos < nodes.size())
   {
      child = (STree) nodes.get(pos++);
   }
   return child;
}

public String toString ()
{
   return toString(0);
}

/**
 * Darstellung des Baums.
 * @param format beeinfluss die Ausgabe: 0 Terminalsymbole als Vollform 1 Semantische Info der
 * Terminalsymbole 2 Syntaktische Info der Terminalsymbole
 */
public String toString (int format)
{
   StringBuilder B = new StringBuilder();
   treeAsString(B, getRoot(), format);
   return B.toString();
}

public void treeAsString (StringBuilder B, STree N, int format)
{
   if (N != null)
   {
      switch (format)
      {
      case 0:
         B.append(N.name);
         break;
      case 1:
         if (N.object != null)
         {
            Rule r = (Rule) N.object;
            if (r.isTerminal())
            {
               B.append(r.getTerminal().getSemantics());
            }
            else
            {
               B.append(N.name);
            }
         }
         else
         {
            B.append(N.name);
         }
         break;
      case 2:
         if (N.object != null)
         {
            Rule r = (Rule) N.object;
            if (r.isTerminal())
            {
               B.append(r.getTerminal().getGrammar());
            }
            else
            {
               B.append(N.name);
            }
         }
         else
         {
            B.append(N.name);
         }
         break;
      }
      if (N.hasChildren())
      {
         B.append("{");
         treeAsString(B, N.firstChild(), format);
         while (N.hasMoreChildren())
         {
            B.append(" ");
            treeAsString(B, N.nextChild(), format);
         }
         B.append("}");
      }
   }
}
}