/**
 * @(#)Grammar.java	17.03.2004
 * 
 * @author kst
 */
package commons.chartparser;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
/**
 * Die linke Seite ist nicht eindeutig, daher wird der Hashvector verwendet: zu einer linken Seite
 * gibt es ggf. mehrere Rule-Eintraege. Jede Rule besteht aus der linken Seite und der rechten
 * Seite, die wiederum ein Array von Strings ist. Jedes Array-Element bezeichnet eine CAT, ev. mit
 * Kongruenz-Angaben. Die Eintraege werden aus einer Regeldatei gelesen, die Eintraege dieser Form
 * speichert: VP VH NP VT:part NP DET:4 ADJ N
 */
@SuppressWarnings("unchecked")
public class Grammar
{

HashVector linkeSeiten  = null;
HashVector rechteSeiten = null;
List       allRules     = null;

/**
 * Konstruktor fuer eine Grammatik, verwendet rulesfile verweist auf die einzulesende
 * Grammatikdatei.
 */
public Grammar(String rulesfile)
{
   linkeSeiten = new HashVector();
   rechteSeiten = new HashVector();
   allRules = new ArrayList();
   readFromFile(rulesfile);
}

/**
 * Iteriert ueber allen Reglen.
 */
public Iterator rules ()
{
   return allRules.iterator();
}

/**
 * liefert das Startelement der Grammatik.
 */
public String startElement ()
{
   Rule r = findStart(null);
   return r.lexpr();
}

/**
 * rekursive methode zum finden des Startelements.
 * @TODO: rework, das ist nicht sicher: V und VT werden auf der rechten seite ev. z.B. nicht korrekt
 * unterschieden (?).
 */
private Rule findStart (Rule r)
{
   Iterator I = rechteSeiten.values().iterator();
   if (I != null && I.hasNext())
   {
      while (I.hasNext())
      {
         Iterator rules = ((ArrayList) I.next()).iterator();
         while (rules.hasNext())
         {
            Rule r2 = (Rule) rules.next();
            if (r == null) // init: nimm igendein element
            { return findStart(r2); }
            for (int i = 0; i < r2.rexpr.length; i++)
            {
               if (r2.rexpr[i].trim().equals(r.lexpr)) { return findStart(r2); }
               // else
               // {
               // String v = ".*"+r2.rexpr[i].trim()+".*";
               // if(r.lexpr.matches(v))
               // {
               // return findStart(r2);
               // }
               // }
            }
         }
      }
   }
   return r;
}

/**
 * Liefert die Anzahl der Regeln.
 */
public int size ()
{
   return allRules.size();
}

/**
 * Liefert einen Iterator, der alle Rules zu einer linken Seite enthaelt. Gibt Woerter zurueck.
 */
public Iterator expand (String left)
{
   return linkeSeiten.iterator(left);
}

/**
 * Liefert einen Iterator, dessen Elemente die linken Seiten zu der rechte Seite enthaelt. Als
 * rechte Seite wird ein Leerzeichen-separierter String erwartet, z.B.: VT VT NP DET:4 ADJ N Die
 * linken Seiten sind jeweils nur Strings. Die Iterator-Objekte sind also Strings wie NP oder S.
 */
public Iterator reduce (String rs)
{
   Iterator I = rechteSeiten.keySet().iterator(); // alle
   if (I != null)
   {
      ArrayList list = new ArrayList();
      while (I.hasNext())
      {
         String k = (String) I.next(); // Format: DET:4.* ADJ.* N.*
         if (Unify.rules(k, rs))
         {
            // jedes Element eine Liste:
            ArrayList rules = (ArrayList) rechteSeiten.get(k);
            Iterator i = rules.iterator();
            if (i != null)
            {
               while (i.hasNext())
               {
                  Rule r = (Rule) i.next();
                  list.add(r.lexpr);
               }
            }
         }
      }
      I = list.iterator();
   }
   return I;
}

/**
 * Regeln aus einer Datei einlesen.
 */
private void readFromFile (String filename)
{
   if (new File(filename).exists())
   {
      BufferedReader reader = null;
      try
      {
         reader = new BufferedReader(new FileReader(filename));
         String nextLine = null;
         while (null != (nextLine = reader.readLine()))
         {
            if (!nextLine.startsWith("#"))
            {
               new Rule(this, nextLine);
            }
         }
      }
      catch (IOException e)
      {
         Main.debug(e.toString());
      }
      finally
      {
         try
         {
            reader.close();
         }
         catch (Exception e)
         {}
      }
   }
   else
   {
      Main.debug("Nicht gefunden: '" + filename + "'");
   }
}
}