Package fmg.fmg8.endlAutomat

Source Code of fmg.fmg8.endlAutomat.EndlicherAutomat

/*
* Datei:            EndlicherAutomat.java
* Autor(en):        Lukas K�nig
* Java-Version:     6.0
* Erstellt (vor): 15.10.2008
*
* (c) Lukas K�nig, die Datei unterliegt der LGPL
* -> http://www.gnu.de/lgpl-ger.html
*/

package fmg.fmg8.endlAutomat;

import fmg.fmg8.earleyErkenner.EarleyErkenner;
import fmg.fmg8.endlAutomat.conditions.Condition;
import fmg.fmg8.endlAutomat.conditions.ConstLeaf;
import fmg.fmg8.endlAutomat.script.Script;
import fmg.fmg8.endlAutomat.script.ScriptInterpreter;
import fmg.fmg8.endlAutomat.translator.Translator;
import fmg.fmg8.graphVis.fensterDialoge.AllgemeinerDialog;
import fmg.fmg8.graphVis.graph.Graph;
import fmg.fmg8.graphVis.graph.Knoten;
import fmg.fmg8.sonstiges.SonstMeth;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Stack;


/**
* Klasse zur Repr�sentation eines endlichen Automaten.
*
* @author Lukas K�nig
*/
public class EndlicherAutomat extends Graph implements Serializable {
   
    /**
     * Die Serial Version ID (generiert am 25. April 2007).
     */
    private static final long serialVersionUID = -3668557617529889755L;

    /**
     * Speichert den Namen des Startknotens.
     */
    private Integer startKnName = null;

    /**
     * Der Erkenner f�r die Sequenzgrammatik.
     */
    private EarleyErkenner seqErkenner;

    /**
     * The script interpreter.
     */
    private ScriptInterpreter scriptInterpreter;
   
    /**
     * Die Sequenz dieses Automaten. Wenn sie null ist, muss sie neu berechnet
     * werden.
     */
    private String sequenz;
   
    /**
     * Konstruktor.
     *
     * @param earl    Der Earley-Erkenner f�r die Sequenz-Grammatik.
     * @param scrInt  A script interpreter to generate automata from scripts.
     */
    public EndlicherAutomat(final EarleyErkenner    earl,
                            final ScriptInterpreter scrInt) {
        super();
        this.seqErkenner = earl;
        this.scriptInterpreter = scrInt;
        this.sequenz = null;
    }

    /**
     * Konstruktor, der den Automaten ohne Earley-Erkenner und
     * Script-Interpreter initialisiert.
     */
    public EndlicherAutomat() {
        this(null, null);
    }
   
    /**
     * Entfernt einen Knoten mit s�mtlichen inzidenten Kanten.
     *
     * @param knotenName  Der Name des zu entfernenden Knotens.
     *
     * @return  True, falls der Knoten entfernt wurde, false, falls er nicht
     *          vorhanden war.
     */
    public boolean entferneKnoten(final Integer knotenName) {
        final ArrayList<Integer> knotenlisteV;
        final ArrayList<Integer> knotenlisteN;
        Iterator<Integer>  it;
        Knoten          knoten;
        HashMap<Integer, Knoten> nachfolger;
        HashMap<Integer, Knoten> vorgaenger;

        nachfolger = this.holeKnoten(knotenName).holeNachfolger();
        vorgaenger = this.holeKnoten(knotenName).holeVorgaenger();
        knotenlisteN = new ArrayList<Integer>(nachfolger.keySet());
        knotenlisteV = new ArrayList<Integer>(vorgaenger.keySet());

        if (this.startKnName != null
            && this.startKnName.equals(knotenName)) {
            this.entferneStartZ();
        }

        if (this.holAdj().containsKey(knotenName)) {
            it = knotenlisteV.iterator();
            while (it.hasNext()) {
                knoten = this.holeKnoten(it.next());
                this.entferneKante(knoten.holeName(), knotenName);
                knoten.entferneNachfolger(this.holeKnoten(knotenName));
                knoten.entferneVorgaenger(this.holeKnoten(knotenName));
            }
            it = knotenlisteN.iterator();
            while (it.hasNext()) {
                knoten = this.holeKnoten(it.next());
                knoten.entferneNachfolger(this.holeKnoten(knotenName));
                knoten.entferneVorgaenger(this.holeKnoten(knotenName));
            }
            this.holAdj().remove(knotenName);
           
            this.sequenz = null;
           
            return true;
        } else {
            return false;
        }
    }

    /**
     * F�gt einen Knoten in den Graph ein. Ist der Knoten bereits vorhanden,
     * werden die zu ihm inzidenten Kanten eingef�gt, die angeh�ngte
     * Zusatzinformation wird jedoch nur angeh�ngt, falls diese beim bereits
     * vorhandenen Knoten null war. (Siehe auch Javadoc der Klasse Graph!)
     *
     * @param knotenName  Der Name des neuen Knoten.
     * @param nachfolger  Die Nachfolger des Knotens.
     * @param vorgaenger  Die Vorg�nger des Knotens.
     * @param aktion      Zusatzinformationen f�r den endlichen Automaten;
     *                    das sind: Aktion, Param. und Achsenbeschriftungen.
     * @param param       Zusatzinformationen f�r den endlichen Automaten;
     *                    das sind: Aktion, Param. und Achsenbeschriftungen.
     * @param beds        Zusatzinformationen f�r den endlichen Automaten;
     *                    das sind: Aktion, Param. und Achsenbeschriftungen.
     * @param alt         Das Rekombinationsalter des Knotens.
     *
     * @return  True, falls der Knoten eingef�gt wurde, false, falls er bereits
     *          vorhanden war (ob Kanten eingef�gt wurden, geht nicht aus dem
     *          R�ckgabewert hervor).
     */
    public boolean einfuegenKnoten(final Integer                  knotenName,
                                   final HashMap<Integer, Knoten> nachfolger,
                                   final HashMap<Integer, Knoten> vorgaenger,
                                   final int                      aktion,
                                   final int                      param,
                                   final List<Transition>         beds,
                                   final int                      alt) {
        boolean eingefuegt;
        boolean start = false;

        if (start) {
            if (this.startKnName != null
                && !this.startKnName.equals(knotenName)) {
                throw new RuntimeException(
                           Messages.getString("EndlicherAutomat."
                               + "VersucheinerMehrfachbelegung"
                               + "desStartknotens"));
            }
            this.startKnName = (Integer) knotenName;
        }

        ZInfo zusatz = new ZInfo(aktion, param, beds, start, alt);

        eingefuegt =  super.einfuegenKnoten(knotenName,
                                            nachfolger,
                                            vorgaenger,
                                            zusatz);
       
        if (eingefuegt) {
            this.sequenz = null;
            return true;
        } else {
            return false;
        }
    }

    /**
     * Erstellt einen neuen Knoten mit dem �bergebenen Namen und f�gt ihn in
     * den Graph ein.
     *
     * @param knotenName  Der Name des neuen Knotens.
     * @param aktion      Zusatzinformationen f�r den endlichen Automaten;
     *                    das sind: Aktion, Param. und Achsenbeschriftungen.
     * @param param       Zusatzinformationen f�r den endlichen Automaten;
     *                    das sind: Aktion, Param. und Achsenbeschriftungen.
     * @param alt         Das Rekombinationsalter des Knotens.
     *
     * @return  True, falls der Knoten eingef�gt wurde, false, falls er bereits
     *          vorhanden war.
     */
    public boolean einfuegenKnoten(final Integer knotenName,
                                   final int     aktion,
                                   final int     param,
                                   final int     alt) {

        return this.einfuegenKnoten(knotenName,
                                    new HashMap<Integer, Knoten>(),
                                    new HashMap<Integer, Knoten>(),
                                    aktion,
                                    param,
                                    null,
                                    alt);
    }

    /**
     * �berschreibung der Methode der Vaterklasse.
     *
     * @param knotenName   Ohne Funktion.
     * @param nachfolger   Ohne Funktion.
     * @param vorgaenger   Ohne Funktion.
     * @param information  Ohne Funktion.
     *
     * @return  Nichts.
     */
    public boolean einfuegenKnoten(final Object                  knotenName,
                                   final HashMap<Object, Knoten> nachfolger,
                                   final HashMap<Object, Knoten> vorgaenger,
                                   final Object                  information) {
        throw new RuntimeException(
            Messages.getString("EndlicherAutomat."
                              + "BenutzungeinerunerlaubtenMethode"));
    }

    /**
     * �berschreibung der Methode der Vaterklasse.
     *
     * @param knotenName  Ohne Funktion.
     *
     * @return  Nichts.
     */
    public boolean einfuegenKnoten(final Object knotenName) {
        throw new RuntimeException(Messages.getString("EndlicherAutomat."
            + "BenutzungeinerunerlaubtenMethode"));
    }

    /**
     * F�gt eine Kante von Knoten1 nach Knoten2 ein, wobei die Bedingung bed
     * der Liste der Bedingungen von Knoten1 hinzugef�gt wird.
     *
     * @param knotenName1  Erster zur Kante inzidenter Knoten.
     * @param knotenName2  Zweiter zur Kante inzidenter Knoten.
     * @param bedingung    Bedingung, unter der die Kante "durchlaufen werden"
     *                     soll.
     * @param alt          Das Alter der Transition, zu der die Bedingung
     *                     geh�rt.
     *
     * @return  Immer <code>true</code>.
     */
    public boolean einfuegKante(final Integer knotenName1,
                                final Integer knotenName2,
                                final String bedingung,
                                final int    alt) {

        return this.einfuegKante(knotenName1,
                                 knotenName2,
                                 SonstMeth.ausFormatBed(bedingung),
                                 alt);
    }

    /**
     * F�gt eine Kante von Knoten1 nach Knoten2 ein, wobei die Bedingung bed
     * der Liste der Bedingungen von Knoten1 hinzugef�gt wird.
     *
     * @param knotenName1  Erster zur Kante inzidenter Knoten.
     * @param knotenName2  Zweiter zur Kante inzidenter Knoten.
     * @param cond         Bedingung, unter der die Kante "durchlaufen werden"
     *                     soll (in der <code>Condition</code> - Datenstruktur).
     * @param alt          Das Alter der Transition, zu der die Bedingung
     *                     geh�rt.
     *
     * @return  Immer <code>true</code>.
     */
    public boolean einfuegKante(final Integer    knotenName1,
                                final Integer    knotenName2,
                                final Condition  cond,
                                final int        alt) {

        final Knoten knoten1 = this.holeKnoten(knotenName1);
        final Knoten knoten2 = this.holeKnoten(knotenName2);
        ZInfo zusatz1;
        final Transition bed;

        if (!this.getAdjazenzliste().containsKey(knotenName1)
            || !this.getAdjazenzliste().containsKey(knotenName2)) {
            throw new RuntimeException(
                Messages.getString("EndlicherAutomat."
                    + "EinerderbeidenKnotenexistiertnicht"));
        }

        knoten1.neuerNachfolger(knoten2);
        knoten2.neuerVorgaenger(knoten1);

        zusatz1 = knoten1.getInfo();
        bed = new Transition(cond,
                             knotenName1.intValue(),
                             knotenName2.intValue(),
                             alt);

        zusatz1.addBedingung(bed);
       
        this.sequenz = null;

        return true;
    }

    /**
     * �berschreibung der Methode der Vaterklasse.
     *
     * @param knotenName1  Ohne Funktion.
     * @param knotenName2  Ohne Funktion.
     *
     * @return  Nichts.
     */
    public boolean einfuegenKante(final Object knotenName1,
                                  final Object knotenName2) {
        throw new RuntimeException(
            Messages.getString("EndlicherAutomat."
                + "BenutzungeinerunerlaubtenMethode"));
    }

    /**
     * Entfernt eine Kante zwischen zwei benachbarten Knoten.
     *
     * @param knotenName1  Der erste der benachbarten Knoten (Vorg�nger).
     * @param knotenName2  Der zweite der benachbarten Knoten (Nachfolger).
     *
     * @return  True, falls eine Kante zwischen den Knoten
     *          existiert hat, die entfernt werden konnte, false in allen
     *          anderen F�llen.
     */
    public boolean entferneKante(final Integer knotenName1,
                                 final Integer knotenName2) {
        boolean entfernt;
        ZInfo zusatz;

        entfernt = this.holeKnoten(knotenName1).entferneNachfolger(
                   this.holeKnoten(knotenName2));
        entfernt = entfernt
                   && this.holeKnoten(knotenName2).entferneVorgaenger(
                       this.holeKnoten(knotenName1));

        zusatz = (ZInfo) this.holeKnoten(knotenName1).getInfo();
        zusatz.entferneTransZuZustand(((Integer) knotenName2).intValue());

        if (entfernt) {
            this.sequenz = null;
        }
       
        return entfernt;
    }

    /**
     * Entfernt eine Kante zwischen zwei benachbarten Knoten, die mit einer
     * angegebenen Bedingung beschriftet ist. Insbesondere wird NUR die
     * Bedingung gel�scht, falls mehrere Kanten zwischen den Knoten existieren.
     *
     * @param knotenName1  Der erste der benachbarten Knoten (Vorg�nger).
     * @param knotenName2  Der zweite der benachbarten Knoten (Nachfolger).
     * @param bed          Die Bedingung, die zur Kante geh�rt.
     *
     * @return  True, falls eine Kante zwischen den Knoten
     *          existiert hat, die entfernt werden konnte, false in allen
     *          anderen F�llen.
     */
    public boolean entferneKante(final Integer    knotenName1,
                                 final Integer    knotenName2,
                                 final Transition bed) {
        boolean entfernt;
        ZInfo zusatz = (ZInfo)
                        this.holeKnoten(knotenName1).getInfo();
        int intName2 = ((Integer) knotenName2).intValue();
       
        entfernt = zusatz.entferneBed(bed);
       
        if (zusatz.getTransZuZustand(intName2).size() == 0) {
       
            entfernt = entfernt
                       && this.holeKnoten(knotenName1).entferneNachfolger(
                          this.holeKnoten(knotenName2));
            entfernt = entfernt
                       && this.holeKnoten(knotenName2).entferneVorgaenger(
                          this.holeKnoten(knotenName1));
   
            zusatz = (ZInfo)
                        this.holeKnoten(knotenName1).getInfo();
            zusatz.entferneTransZuZustand(((Integer) knotenName2).intValue());
       
        }
       
        if (entfernt) {
            this.sequenz = null;
        }
       
        return entfernt;
    }

    /**
     * Gibt eine Sequenz als String zur�ck.
     *
     * @param l  Die auszugebende Sequenz.
     *
     * @return  String.
     */
    public String ausgabe(final LinkedList<Integer> l) {
        Iterator<Integer> it = l.iterator();
        int zahl;
        String seq = new String();

        while (it.hasNext()) {
            zahl = it.next().intValue();

            if (!seq.equals("")) {
                seq = seq + ", ";
            }
            if (zahl < 100) {
                seq = seq + "0";
            }
            if (zahl < 10) {
                seq = seq + "0";
            }
            seq = seq + zahl;
        }

        return seq;
    }

    /**
     * Gibt die Automatensequenz von <code>this</code> als fertige
     * String-Sequenz zur�ck.
     *
     * @return  Die Stringsequenz des Endlichen Automaten.
     */
    public String erzeugeStringSeq() {
        // TODO
        this.sequenz = null;
       
        if (this.sequenz == null) {
            this.sequenz = this.ausgabe(this.erzeugeSequenz());
        }

        return this.sequenz;
    }
   
    /**
     * Setzt die String-Sequenz auf null, als Zeichen, dass der Automat
     * von au�en ver�ndert wurde.
     */
    public void setSeqVeraendert() {
        this.sequenz = null;
    }
   
    /**
     * Gibt die zu <code>this</code> geh�rende Automatensequenz zur�ck.
     *
     * @return  Die Automatensequenz.
     */
    public synchronized LinkedList<Integer> erzeugeSequenz() {
        LinkedList<Integer> seq = new LinkedList<Integer>();
        ArrayList<Knoten> alleKnot
            = new ArrayList<Knoten>(this.holAdj().values());
        Iterator<Knoten> it1;
        Iterator<Transition> it2;
        Knoten aktKnot;
        ZInfo aktZusatz;
        Integer aktName;
        Integer aktBefehl;
        Integer aktParam;
        Integer aktAlter;
        Transition aktBed;
        String bed;
        Integer folgeZu;
        String token;
        Stack<Character> stk;
        char tokC;
        Character c;
        Integer transAlter;

        // Sorgt daf�r, dass der Startzustand am Beginn der Sequenz steht.
        Collections.sort(alleKnot, new StartZustKomp());

        it1 = alleKnot.iterator();
        while (it1.hasNext()) {
            aktKnot = it1.next();
            aktZusatz = (ZInfo) aktKnot.getInfo();

            aktName = (Integer) aktKnot.holeName();
            aktBefehl = new Integer(aktZusatz.getAktion());
            aktParam = new Integer(aktZusatz.getParam());
            aktAlter = new Integer(aktZusatz.getAlter());

            seq.add(aktName);
            seq.add(aktBefehl);
            seq.add(aktParam);
            seq.add(aktAlter);

            it2 = aktZusatz.getBeds().iterator();
            while (it2.hasNext()) {
                aktBed = it2.next();
                bed = aktBed.getCond().formatted();
                folgeZu = new Integer(aktBed.getFolgezustand());
                transAlter = new Integer(aktBed.getAlter());

                stk = new Stack<Character>();

                // " (  h 002 <  h 004 &  h 002 > 100 ) "
                for (int i = 0; i + 2 < bed.length(); i = i + 3) {
                    token = bed.substring(i, i + 3);
                    tokC = token.charAt(1);

                    if (tokC == Konstanten.KA) {
                        stk.push(new Character(Konstanten.KA));
                    } else if (tokC == Konstanten.KZ) {
                        while (!stk.empty()) {
                            c = (Character) stk.pop();
                            if (c.charValue() == Konstanten.KA) {
                                break;
                            } else {
                                seq.add(new Integer(Konstanten.TRENNZEICHEN));
                                seq.add(new Integer(
                                        this.sonderz2Code(c.charValue())));
                            }
                        }
                    } else if (SonstMeth.istOper(tokC)) {
                        if (stk.empty()) {
                            stk.push(new Character(tokC));
                        } else {
                            while (!stk.empty()) {
                                c = (Character) stk.pop();
                                if (c.charValue() == Konstanten.KA) {
                                    stk.push(c);
                                    break;
                                } else if (SonstMeth.istOper(c.charValue())) {
                                    if (this.schwaecher(c.charValue(), tokC)) {
                                        stk.push(c);
                                        break;
                                    } else {
                                        seq.add(new Integer(0));
                                        seq.add(new Integer(
                                            this.sonderz2Code(c.charValue())));
                                    }
                                }
//                              if (this.kleiner(c.charValue(), tokC)
//                                      || c.charValue() == Konstanten.KA) {
//                                      break;
//                                  }
                            }
                            stk.push(new Character(tokC));
                        }
                    } else {
                        if (SonstMeth.istSonderzeichen(tokC)) {
                            seq.add(new Integer(0));
                            seq.add(new Integer(this.sonderz2Code(tokC)));
                        } else {
                            seq.add(new Integer(Integer.parseInt(token)));
                        }
                    }
                }
                while (!stk.empty()) {
                    c = (Character) stk.pop();
                    seq.add(new Integer(0));
                    seq.add(new Integer(this.sonderz2Code(c.charValue())));
                }

                seq.add(new Integer(Konstanten.TRENNZEICHEN));
                seq.add(new Integer(Konstanten.TRENNZEICHEN));
                seq.add(folgeZu);
                seq.add(transAlter);
            }

            seq.add(new Integer(Konstanten.TRENNZEICHEN));
            seq.add(new Integer(Konstanten.TRENNZEICHEN));
            seq.add(new Integer(Konstanten.TRENNZEICHEN));
        }

        return seq;
    }

    /**
     * Gibt zur�ck, ob der erste der �bergebenen Operatoren schw�cher bindet
     * als der zweite. Als Operatoren sind alle Character erlaubt, bei denen
     * die Methode <code>istOperator</code> <code>true</code> zur�ckgeben
     * w�rde.
     *
     * @param c1  Der erste Operator.
     * @param c2  Der zweite Operator.
     *
     * @return  Ob der erste Operator als der zweite Operator ist.
     */
    private boolean schwaecher(final char c1,
                               final char c2) {
        if (!SonstMeth.istOper(c1) || !SonstMeth.istOper(c2)) {
            throw new RuntimeException("Vergleichselement ist kein Operator.");
        }

        int i1;
        int i2;
        if (c1 == Konstanten.UND || c1 == Konstanten.ODER) {
            i1 = 1;
        } else {
            i1 = 2;
        }

        if (c2 == Konstanten.UND || c2 == Konstanten.ODER) {
            i2 = 1;
        } else {
            i2 = 2;
        }

        return i1 < i2;
    }

    /**
     * Erzeugt den Kode aus dem Buchstaben eines  Sonderzeichens. Sonderzeichen
     * sind alle Character, bei denen die Methode <code>istSonderzeichen</code>
     * <code>true</code> zur�ckgeben w�rde.
     *
     * @param c  Der zu kodierende Buchstabe.
     *
     * @return  Der Kode des Buchstabens.
     */
    private int sonderz2Code(final char c) {
        if (c == Konstanten.EING) {
            return Konstanten.EING_CODE;
        } else if (c == Konstanten.FALSE) {
            return Konstanten.FALSE_CODE;
        } else if (c == Konstanten.GL) {
            return Konstanten.GL_CODE;
        } else if (c == Konstanten.GR) {
            return Konstanten.GR_CODE;
        } else if (c == Konstanten.GRGL) {
            return Konstanten.GRGL_CODE;
        } else if (c == Konstanten.KA) {
            return Konstanten.KA_CODE;
        } else if (c == Konstanten.KL) {
            return Konstanten.KL_CODE;
        } else if (c == Konstanten.KLGL) {
            return Konstanten.KLGL_CODE;
        } else if (c == Konstanten.KZ) {
            return Konstanten.KZ_CODE;
        } else if (c == Konstanten.ODER) {
            return Konstanten.ODER_CODE;
        } else if (c == Konstanten.TRUE) {
            return Konstanten.TRUE_CODE;
        } else if (c == Konstanten.UGL) {
            return Konstanten.UGL_CODE;
        } else if (c == Konstanten.UND) {
            return Konstanten.UND_CODE;
        } else if (c == Konstanten.UNGF) {
            return Konstanten.UNGF_CODE;
        } else if (c == Konstanten.NUNGF) {
            return Konstanten.NUNGF_CODE;
        } else {
            throw new RuntimeException("Undefiniertes Sonderzeichen.");
        }
    }

    /**
     * Entfernt ung�ltige Zeichen aus dem String und f�gt bei Zahlen, die aus
     * weniger als drei Ziffern bestehen entsprechend viele Nullen an.
     *
     * @param seqOrig  Die zu bereinigende Sequenz.
     *
     * @return  Die bereinigte Sequenz.
     */
    public synchronized String bereinige(final String seqOrig) {
        String seq = " " + seqOrig;
        String seq1 = "";
        String seq2 = "";
        boolean trennSymb = false;
        String zwisch;

        for (int i = 0; i < seq.length(); i++) {
            if (SonstMeth.istZiff(seq.charAt(i))) {
                seq1 = seq1 + seq.charAt(i);
                trennSymb = false;
            } else {
                if (!trennSymb) {
                    seq1 = seq1 + " ";
                }
                trennSymb = true;
            }
        }

        if (!SonstMeth.istZiff(seq1.charAt(seq1.length() - 1))) {
            seq1 = seq1.substring(0, seq1.length() - 1);
        }

        zwisch = "";
        for (int i = 0; i < seq1.length(); i++) {
            if (SonstMeth.istZiff(seq1.charAt(i))) {
                zwisch = zwisch + seq1.charAt(i);
            } else {
                if (zwisch.length() == 3) {
                    seq2 = seq2 + zwisch;
                } else if (zwisch.length() == 2) {
                    seq2 = seq2 + "0" + zwisch;
                } else if (zwisch.length() == 1) {
                    seq2 = seq2 + "00" + zwisch;
//                } else if (zwisch.length() > 3) {
//                    throw new RuntimeException(
//                        Messages.getString("EndlicherAutomat."
//                            + "FehlerhafteSequenz"));
                }

                seq2 = seq2 + seq1.charAt(i);
                zwisch = "";
            }
        }
        if (zwisch.length() == 3) {
            seq2 = seq2 + zwisch;
        } else if (zwisch.length() == 2) {
            seq2 = seq2 + "0" + zwisch;
        } else if (zwisch.length() == 1) {
            seq2 = seq2 + "00" + zwisch;
//        } else if (zwisch.length() > 3) {
//            throw new RuntimeException(
//                Messages.getString("EndlicherAutomat."
//                    + "FehlerhafteSequenz"));
        }

        return seq2;
    }

    /**
     * Erzeugt eine Infix-Repr�sentation einer Bedingung aus einer Postfix-
     * repr�sentation.
     *
     * @param seq  Die Postfix-Repr�sentation einer Bedingung.
     *
     * @return  Die Infix-Repr�sentation der Bedingung.
     */
    private synchronized LinkedList<Integer> bedPost2in(
                      final LinkedList<Integer> seq) {
        Stack<LinkedList<Integer>> stk = new Stack<LinkedList<Integer>>();
        LinkedList<Integer> s1;
        LinkedList<Integer> s2;
        LinkedList<Integer> s3;
        int token;
        int i = 0;

        while (i < seq.size()) {
            token = ((Integer) seq.get(i)).intValue();
            if (token == Konstanten.TRENNZEICHEN) {
                i++;
                token = ((Integer) seq.get(i)).intValue();

                if (SonstMeth.istOperator(token)) {
                    s2 = stk.pop();
                    s1 = stk.pop();
                    if (token == Konstanten.ODER_CODE
                        || token == Konstanten.UND_CODE) {
                        s1.addFirst(new Integer(Konstanten.KA_CODE));
                        s1.addFirst(new Integer(0));
                        s1.add(new Integer(0));
                        s1.add(new Integer(token));
                        s1.addAll(s2);
                        s1.add(new Integer(0));
                        s1.add(new Integer(Konstanten.KZ_CODE));
                        stk.push(s1);
                    } else {
                        s1.add(new Integer(0));
                        s1.add(new Integer(token));
                        s1.addAll(s2);
                        stk.push(s1);
                    }
                } else {
                    s3 = new LinkedList<Integer>();
                    s3.add(new Integer(0));
                    s3.add(new Integer(token));
                    if (token == Konstanten.EING_CODE) {
                        i++;
                        token = ((Integer) seq.get(i)).intValue();
                        s3.add(new Integer(token));
                    }
                    stk.push(s3);
                }
            } else {
                s3 = new LinkedList<Integer>();
                s3.add(new Integer(token));
                stk.push(s3);
            }

            i++;
        }

        return stk.pop();
    }

    /**
     * Fragt den Benutzer, ob seq auf Korrektheit �berpr�ft werden soll und
     * �berpr�ft diese im positiven Fall. Dabei ist die Korrektheit im Sinn
     * einer syntaktischen Richtigkeit bezogen auf die Standardkodierung
     * gemeint.
     *
     * @param seq  Die zu pr�fende Sequenz.
     * @return  Ob die Sequenz korrekt ist oder der Benutzer keine �berpr�fung
     *          angefordert hat.
     */
    private boolean seqKorrPruef(final String seq) {
        final AllgemeinerDialog confirm;
        final AllgemeinerDialog dia;
        final ArrayList<String> buttonsConf = new ArrayList<String>();
        buttonsConf.add(fmg.fmg8.graphVis.Messages.getString("Vis.Yes"));
        buttonsConf.add(fmg.fmg8.graphVis.Messages.getString("Vis.No"));
        buttonsConf.add(fmg.fmg8.graphVis.Messages.getString("Vis.Cancel"));
        final ArrayList<String> buttons = new ArrayList<String>();
        buttons.add(fmg.fmg8.graphVis.Messages.getString("SteuerFenster.OK"));


        confirm = new AllgemeinerDialog(null,
        fmg.fmg8.graphVis.Messages.getString(
                "SteuerFenster.ObSeqParsen"),
        fmg.fmg8.graphVis.Messages.getString(
                "SteuerFenster.ObSeqParsenTitel"),
        buttonsConf,
        null);
        confirm.setVisible(true);
      
        if (confirm.getResult().equals(
                fmg.fmg8.graphVis.Messages.getString(
                       "Vis.Yes"))) {
            if (!this.seqErkenner.erkenne(seq)) {
                dia = new AllgemeinerDialog(null,
                        null,
                        fmg.fmg8.graphVis.Messages.getString(
                            "SteuerFenster.Earley"),
                            buttons,
                        "<"
                        + seq
                        + ">\n\n\n"
                        + this.seqErkenner.toString());
                dia.setVisible(true);
                return false;
            }
        } else if (confirm.getResult().equals(
                fmg.fmg8.graphVis.Messages.getString("Vis.Cancel"))) {
            return false;
        }
       
        return true;
    }

    /**
     * Erzeugt einen endlichen Automaten aus einer Sequenz mit einem
     * Translator und �berschreibt <code>this</code> damit.
     *
     * @param seq      Die Sequenz des neuen Automaten.
     * @param trans    Der Translator, mit dem die Sequenz �bersetzt werden
     *                 soll. Wenn hier <code>null</code> �bergeben wird, wird
     *                 der Standardtranslator f�r Verhalten aus der Klasse
     *                 <code>Konstanten</code> des Pakets
     *                 <code>fmg.fmg7.endlAutomat.translator</code> verwendet.
     * @param pruefen  Gibt an, ob die Sequenz gepr�ft werden soll, bevor
     *                 der alte Automat �berschrieben und ein neuer erzeugt
     *                 wird. Die �berpr�fung bezieht sich auf die Standard-
     *                 kodierung, ist also nicht sinnvoll, wenn ein anderer
     *                 Translator als der Standardtranslator �bergeben wurde.
     */
    public synchronized void erzeugeAusSequenz(
            final String seq,
            final Translator trans,
            final boolean pruefen) {
        String seq2 = this.bereinige(seq);
        Translator trans2, konstTrBE;
       
        konstTrBE = fmg.fmg8.endlAutomat.translator.Konstanten.STD_TRANSL_BE;
       
        if (trans == null) {
            trans2 = konstTrBE;
        } else {
            trans2 = trans;
        }

        if (Konstanten.SEQUENZ_KORREKTHEIT_PRUEFEN) {
            if (pruefen) {
                if (!this.seqKorrPruef(seq2)) {
                    return;
                }
            }
        }

        Script neuScript = trans2.translate(seq2);
        trans2.getScriptInterpreter().generateAutomaton(this, neuScript);

/* TODO: Langfristig weglassen, dient nur Testzwecken:
        Translator konstTrTR
            = fmg.fmg8.endlAutomat.translator.Konstanten.STD_TRANSL_TR;
        if (trans2.equals(konstTrBE) || trans2.equals(konstTrTR)) {
            SonstMeth.log(
                    SonstMeth.LOG_DEBUG,
                    "Teste Sequenz...",
                    trans2.getPars());
            if (this.getClass().equals(EndlicherAutomat.class)) {
                EndlicherAutomat aut = new EndlicherAutomat();
                try {
                    aut.erzeugeAusSequenz(seq, pruefen);
                } catch (final Exception e) {
                    SonstMeth.log(
                            SonstMeth.LOG_DEBUG,
                            " Test nicht durchgef�hrt - Kein Standardcode.",
                            trans2.getPars(),
                            "plain",
                            null);
                    return true;
                }
                if (aut.equals(this)) {
                    return true;
                } else {
                    SonstMeth.log(
                            SonstMeth.LOG_DEBUG,
                            "Test nicht erfolgreich.",
                            trans2.getPars(),
                            "plain",
                            null);
                    SonstMeth.log(
                            SonstMeth.LOG_DEBUG,
                            "\nSequenz:   " + seq,
                            trans2.getPars(),
                            "plain",
                            null);
                    SonstMeth.log(
                            SonstMeth.LOG_DEBUG,
                            "\nErw�nscht: " + aut.erzeugeStringSeq(),
                            trans2.getPars(),                           
                            "plain",
                            null);

                    SonstMeth.log(
                            SonstMeth.LOG_DEBUG,
                            "\nThis:      " + this.erzeugeStringSeq(),
                            trans2.getPars(),                           
                            "plain",
                            null);
                    return false;
                }
            } else {
                Translator aut = new Translator(
                        "",
                        new ScriptInterpreter(
                                null,
                                ScriptInterpreter.MODUS_VERHALTEN),
                        ((Translator) this).getPars());
                try {
                    aut.erzeugeAusSequenz(seq, pruefen);
                } catch (final Exception e) {
                    SonstMeth.log(
                            SonstMeth.LOG_DEBUG,
                            "Test nicht durchgef�hrt - ung�ltiger Code.",
                            trans2.getPars(),
                            "plain",
                            null);
                }
               
                if (aut.equals(this)) {
                    return true;
                } else {
                    SonstMeth.log(
                            SonstMeth.LOG_DEBUG,
                            "Test nicht erfolgreich.",
                            trans2.getPars(),
                            "plain",
                            null);
                    SonstMeth.log(
                            SonstMeth.LOG_DEBUG,
                            "\nSequenz:   " + seq,
                            trans2.getPars(),
                            "plain",
                            null);
                    SonstMeth.log(
                            SonstMeth.LOG_DEBUG,
                            "\nErw�nscht: " + aut.erzeugeStringSeq(),
                            trans2.getPars(),                           
                            "plain",
                            null);

                    SonstMeth.log(
                            SonstMeth.LOG_DEBUG,
                            "\nThis:      " + this.erzeugeStringSeq(),
                            trans2.getPars(),                           
                            "plain",
                            null);
                    return false;
                }
            }
        } else {
            SonstMeth.log(
                    SonstMeth.LOG_DEBUG,
                    "Teste nicht.",
                    trans2.getPars());
            return true;
        }
*/
    }
   
    /**
     * Erzeugt einen Endlichen Automaten aus einer Sequenz per fester
     * "Standardkodierung". Die Standardkodierung ist durch diese Methode
     * definiert.<BR>
     * <BR>
     * Diese Methode kann, wenn ein Translator zur Verf�gung steht, immer
     * durch
     * <code>public synchronized void erzeugeAusSequenz(
     *      final String seq,
     *      final Translator trans,
     *      final boolean pruefen)</code>
     * ersetzt werden.
     *
     * @param seq      Die Sequenz, aus der der Automat erzeugt werden soll.
     * @param pruefen  Gibt an, ob die Sequenz gepr�ft werden soll, bevor
     *                 der alte Automat �berschrieben und ein neuer erzeugt
     *                 wird.
     */
    public synchronized void erzeugeAusSequenz(
            final String  seq,
            final boolean pruefen) {
        final String seq2 = this.bereinige(seq);

        if (Konstanten.SEQUENZ_KORREKTHEIT_PRUEFEN) {
            if (pruefen) {
                if (!this.seqKorrPruef(seq2)) {
                    return;
                }
            }
        }

        LinkedList<LinkedList<Integer>> zustaende
            = new LinkedList<LinkedList<Integer>>();
        LinkedList<Integer> zustand;
        LinkedList<LinkedList<Integer>> bedingungen;
        LinkedList<Integer> bedingung;
        LinkedList<Integer> folgeZustaende;
        LinkedList<Integer> kantenAlter;
        int folgeZ;
        int kantAlt;
        int aktZustand = 1000;
        Iterator<LinkedList<Integer>> it;
        Iterator<LinkedList<Integer>> it1;
        Iterator<Integer> it2;
        Iterator<Integer> it3;
        Iterator<Integer> it4;
       
        Integer aktTok;
        int letzt;
        int vletzt;
        String token;
        int[] tokenInt = new int[seq2.length() / 4];
        int j = 0;

        this.leereGraph();

        // Einzelne Ziffer-Tokens parsen.
        for (int i = 0; i < seq2.length(); i = i + 4) {
            token = seq2.substring(i + 1, i + 4);
            tokenInt[j] = Integer.parseInt(token);
            j = j + 1;
        }

        // Tokenliste in Zust�nde aufteilen.
        zustand = new LinkedList<Integer>();
        int i = 0;
        while (i < tokenInt.length) {
            if (tokenInt[i] == Konstanten.TRENNZEICHEN
                && tokenInt[i + 1] == Konstanten.TRENNZEICHEN
                && tokenInt[i + 2] == Konstanten.TRENNZEICHEN) {

                zustaende.add(zustand);
                zustand = new LinkedList<Integer>();
                i = i + 3;
            } else {
                zustand.add(new Integer(tokenInt[i]));
                i++;
            }
        }

        // Knoten erzeugen.
        j = 0;
        it = zustaende.iterator();
        while (it.hasNext()) {
            zustand = it.next();
            this.einfuegenKnoten(zustand.get(0),
                                zustand.get(1).intValue(),
                                zustand.get(2).intValue(),
                                zustand.get(3).intValue());
            if (j == 0) {
                this.setStart(this.holeKnoten(zustand.get(0)));
            }
            j++;
        }

        // Kanten erzeugen.
        it = zustaende.iterator();
        bedingungen = new LinkedList<LinkedList<Integer>>();
        folgeZustaende = new LinkedList<Integer>();
        kantenAlter = new LinkedList<Integer>();
        while (it.hasNext()) {
            zustand = (LinkedList<Integer>) it.next();

            it4 = zustand.iterator();
            if (it4.hasNext()) {
                aktZustand = ((Integer) it4.next()).intValue();
                it4.next();
                it4.next();
                it4.next();
            }

            bedingung = new LinkedList<Integer>();
            j = 0;
            letzt = 1000;
            vletzt = 1000;
            while (it4.hasNext()) {
                aktTok = (Integer) it4.next();

                bedingung.add(j, aktTok);
                if (letzt == Konstanten.TRENNZEICHEN
                    && vletzt == Konstanten.TRENNZEICHEN) {
                    bedingung.remove(j);
                    bedingung.remove(j - 1);
                    bedingung.remove(j - 2);
                    bedingungen.add(bedingung);
                    bedingung = new LinkedList<Integer>();
                    folgeZustaende.add(aktTok);
                    aktTok = (Integer) it4.next();
                    kantenAlter.add(aktTok);

                    j = 0;
                    letzt = 1000;
                    vletzt = 1000;
                } else {
                    vletzt = letzt;
                    letzt = aktTok.intValue();
                    j++;
                }
            }

            it1 = bedingungen.iterator();
            it2 = folgeZustaende.iterator();
            it3 = kantenAlter.iterator();
            while (it1.hasNext() && it2.hasNext() && it3.hasNext()) {
                bedingung = it1.next();
                bedingung = this.bedPost2in(bedingung); // Umwandeln in Infix.
                folgeZ = ((Integer) it2.next()).intValue();
                kantAlt = ((Integer) it3.next()).intValue();
                this.einfuegKante(new Integer(aktZustand),
                                    new Integer(folgeZ),
                                    this.stringAusListe(bedingung),
                                    kantAlt);
            }

            bedingungen = new LinkedList<LinkedList<Integer>>();
            folgeZustaende = new LinkedList<Integer>();
            kantenAlter = new LinkedList<Integer>();
        }
    }

    /**
     * Erzeugt einen String aus der Kodierung durch eine Liste von Integern.
     *
     * @param liste  Die kodierte Liste.
     *
     * @return  Dekodierter String.
     */
    private String stringAusListe(final LinkedList<Integer> liste) {
        String bed = "";
        Iterator<Integer> it;
        int akt;

        it = liste.iterator();
        while (it.hasNext()) {
            akt = ((Integer) it.next()).intValue();
            if (akt == Konstanten.TRENNZEICHEN) {
                akt = ((Integer) it.next()).intValue();
                bed = bed + " ";
                if (akt == Konstanten.EING_CODE) {
                    bed = bed + Konstanten.EING;
                }
                if (akt == Konstanten.FALSE_CODE) {
                    bed = bed + Konstanten.FALSE;
                }
                if (akt == Konstanten.GL_CODE) {
                    bed = bed + Konstanten.GL;
                }
                if (akt == Konstanten.GR_CODE) {
                    bed = bed + Konstanten.GR;
                }
                if (akt == Konstanten.GRGL_CODE) {
                    bed = bed + Konstanten.GRGL;
                }
                if (akt == Konstanten.KA_CODE) {
                    bed = bed + Konstanten.KA;
                }
                if (akt == Konstanten.KL_CODE) {
                    bed = bed + Konstanten.KL;
                }
                if (akt == Konstanten.KLGL_CODE) {
                    bed = bed + Konstanten.KLGL;
                }
                if (akt == Konstanten.KZ_CODE) {
                    bed = bed + Konstanten.KZ;
                }
                if (akt == Konstanten.ODER_CODE) {
                    bed = bed + Konstanten.ODER;
                }
                if (akt == Konstanten.TRUE_CODE) {
                    bed = bed + Konstanten.TRUE;
                }
                if (akt == Konstanten.UGL_CODE) {
                    bed = bed + Konstanten.UGL;
                }
                if (akt == Konstanten.UND_CODE) {
                    bed = bed + Konstanten.UND;
                }
                if (akt == Konstanten.UNGF_CODE) {
                    bed = bed + Konstanten.UNGF;
                }
                if (akt == Konstanten.NUNGF_CODE) {
                    bed = bed + Konstanten.NUNGF;
                }
                bed = bed + " ";
            } else {
                if (akt < 10) {
                    bed = bed + "0";
                }
                if (akt < 100) {
                    bed = bed + "0";
                }
                bed = bed + akt;
            }
        }

        return bed;
    }

    /**
     * Setzt den Knoten k als Startknoten ein und entfernt diese Eigenschaft
     * vom fr�heren Startknoten.
     *
     * @param k  Der als Startknoten einzusetzenden Knoten. Bei null wird
     *           der Startknoten NICHT VER�NDERT.
     */
    public void setStart(final Knoten k) {
        if (k == null) {
            return;
        }
       
        Knoten knot = this.holeKnoten(k.holeName());
       
        if (this.startKnName != null) {
            ((ZInfo)
             this.holeKnoten(this.startKnName).getInfo()).setStartZu(false);
        }

        ((ZInfo) knot.getInfo()).setStartZu(true);
        this.startKnName = (Integer) knot.holeName();
       
        this.sequenz = null;
    }
   
    /**
     * Setzt den Startknoten auf den ersten vorhandenen Knoten in der
     * Adjazenzliste oder l�scht ihn, falls die Liste leer ist.
     */
    public void setStartBeliebig() {
        if (this.getAdjazenzliste().size() > 0) {
            this.setStart(this.getAdjazenzliste().values().iterator().next());
        } else {
            this.entferneStartZ();
        }
    }
   
    /**
     * Gibt den Startknoten des endlichen Automaten zur�ck.
     *
     * @return  Der Startknoten.
     */
    public Knoten holeStartzustand() {
        return this.holeKnoten(this.startKnName);
    }

    /**
     * Gibt zur�ck, ob der �bergebene Knoten der Startknoten ist.
     *
     * @param k  Der zu �berpf�fende Knoten.
     *
     * @return  Ob der Knoten der Startknoten ist.
     */
    public boolean istStartZ(final Knoten k) {
        return ((ZInfo) k.getInfo()).istStartZ();
    }

    /**
     * Entfernt den Startzustand.
     */
    public void entferneStartZ() {
        if (this.startKnName != null) {
            ((ZInfo)
             this.holeKnoten(this.startKnName).getInfo()).setStartZu(
                                                                        false);
            this.startKnName = null;
            this.sequenz = null;
        }
    }

    /**
     * Erzeugt einen leeren Graphen ohne Knoten und Kanten.
     */
    public void leereGraph() {
        this.entferneStartZ();
        super.leereGraph();
        this.sequenz = "";
    }

    /**
     * F�gt eine Clique, das hei�t, einen vollst�ndig verbundenen Teilgraphen
     * aus den Knoten der Knotennamen, zum Graphen hinzu. Dabei werden keine
     * expliziten Selbstbez�ge (Schleifen) eingef�gt; implizit k�nnen sich
     * aber Schleifen durch doppelte Vorkommen der Knotennamen oder durch
     * bereits im Graphen this vorhandene Knoten ergeben!
     *
     * ACHTUNG: Dabei werden die Knoten- und Kantenbeschriftungen mit
     *          Standardwerten belegt.
     *
     * @param knotenNamen  Die Namen der Knoten, die eingef�gt werden sollen.
     */
    public void einfClique(final ArrayList<Integer> knotenNamen) {
        for (int i = 0; i < knotenNamen.size(); i++) {
            this.einfuegenKnoten(knotenNamen.get(i), 1, 1, 1);
        }
        for (int i = 0; i < knotenNamen.size(); i++) {
            for (int j = 0; j < knotenNamen.size(); j++) {
                if (i != j) {
                    this.einfuegKante(knotenNamen.get(i),
                                        knotenNamen.get(j),
                                        " "
                                        + Konstanten.TRUE
                                        + " ",
                                        1);
                }
            }
        }
       
        this.sequenz = null;
    }

    /**
     * F�gt einen Stern als Teilgraphen in den aktuellen Graph ein, also einen
     * Graphen, der einen ausgezeichneten mittleren Knoten hat, mit dem alle
     * anderen Knoten verbunden sind, und keine weiteren Kanten. Dabei
     * sind die KnotenNAMEN und die Information, die beim mittleren Knoten
     * zus�tzlich gespeichert werden soll, als Parameter zu �bergeben.
     * (Knotennamen k�nnen beliebige Objekte sein, also insbesondere auch die
     * gesamte Information tragen, die den Knoten ausmacht. Falls keine
     * strukturgleichen Knotennamen auftauchen sollen, m�ssen die zugeh�rigen
     * Klassen die Methoden equals und hashCode implementieren.)
     *
     * ACHTUNG: Dabei werden die Knoten- und Kantenbeschriftungen mit
     *          Standardwerten belegt.
     *
     * @param mittelKnoten  Der Name des Mittelknotens des Sterns.
     * @param andereKnoten  Die Namen der anderen, mit dem Mittelpunkt zu
     *                      verbindenden Knoten.
     */
    public void einfStern(final Integer       mittelKnoten,
                               final List<Integer> andereKnoten) {
        Integer           aktKnot;
        Iterator<Integer> it;

        this.einfuegenKnoten(mittelKnoten,
                             new HashMap<Integer, Knoten>(),
                             new HashMap<Integer, Knoten>(),
                             1,
                             1,
                             null,
                             1);

        it = andereKnoten.iterator();
        while (it.hasNext()) {
            aktKnot = it.next();
            this.einfuegenKnoten(aktKnot, 1, 1, 1);
            this.einfuegKante(mittelKnoten,
                                aktKnot,
                                " "
                                + Konstanten.TRUE
                                + " ",
                                1);
        }
       
        this.sequenz = null;
    }

    /**
     * Entfernt alle Leerzeichen aus dem String.
     *
     * @param str  Der String, aus dem die Leerzeichen entfernt werden sollen.
     *
     * @return  Der String ohne Leerzeichen.
     */
    private static String entferneLeerzeichen(final String str) {
        String neuerStr = "";

        for (int i = 0; i < str.length(); i++) {
            if (str.charAt(i) != ' ') {
                neuerStr = neuerStr + str.charAt(i);
            }
        }

        return neuerStr;
    }

    /**
     * Gibt die �bergebene Bedingung formatiert zur�ck.
     *
     * @param bed  Die zu formatierende Bedingung.
     *
     * @return  Die formatierte Bedingung.
     */
    public static String formatBed(final String bed) {
        String zwischBed1 = entferneLeerzeichen(bed).toLowerCase();
        String zwischBed2 = zwischBed1.replaceAll("false", "f");
        String zwischBed3 = zwischBed2.replaceAll("true", "t");
        String zwischBed4 = zwischBed3.replaceAll("<=", "[");
        String zwischBed5 = zwischBed4.replaceAll(">=", "]");
        String zwischBed6 = zwischBed5.replaceAll("!=", "!");
        String zwischBed7 = zwischBed6.replaceAll("!~", "#");
        String zwischBed = zwischBed7;
           
        String neueBed = "";
        int i = 0;

        while (i < zwischBed.length()) {
            if (SonstMeth.istZiff(zwischBed.charAt(i))) {
                if (i + 1 >= zwischBed.length()
                    || !SonstMeth.istZiff(zwischBed.charAt(i + 1))) {
                    neueBed = neueBed + "00";
                    neueBed = neueBed + zwischBed.charAt(i);
                } else if (i + 2 >= zwischBed.length()
                           || !SonstMeth.istZiff(zwischBed.charAt(i + 2))) {
                        neueBed = neueBed
                                  + "0"
                                  + zwischBed.charAt(i)
                                  + zwischBed.charAt(i + 1);
                        i++;
                } else {
                    neueBed = neueBed
                              + zwischBed.charAt(i)
                              + zwischBed.charAt(i + 1)
                              + zwischBed.charAt(i + 2);
                    i = i + 2;
                }
            } else {
                if (SonstMeth.istSonderzeichen(zwischBed.charAt(i))) {
                    neueBed = neueBed
                              + " "
                              + zwischBed.charAt(i)
                              + " ";
                } else {
                    throw new RuntimeException(
                        "Ung�ltiges Zeichen in einer Bedingung: " + bed);
                }
            }
            i++;
        }

        return neueBed;
    }
   
    /**
     * Gibt eine HashMap mit allen Knotennamen und zugeh�rigen
     * Kantenbedingungen zur�ck (jeder Key ist ein Knotenname eines
     * Ursprungsknotens, der Value ist eine Liste der Bedingungen).
     * Insbesondere k�nnen daraus alle Kanten des Graphen abgeleitet werden.
     *
     * @return Eine HashMap mit allen Kantenbedingungen
     */
    public HashMap<Integer, LinkedList<Transition>> getAlleBedingungen() {
        HashMap<Integer, LinkedList<Transition>> alleBeds
            = new HashMap<Integer, LinkedList<Transition>>(
                    this.getAdjazenzliste().size());
        LinkedList<Transition> bedingungen;
        ArrayList<Integer> knotenNam
            = new ArrayList<Integer>(this.getAdjazenzliste().keySet());
        Iterator<Integer> it1 = knotenNam.iterator();
        Integer aktNam;
       
        while (it1.hasNext()) {
            aktNam = it1.next();
            bedingungen = this.holeKnoten(aktNam).getInfo().getBeds();
           
            alleBeds.put(aktNam, bedingungen);
        }
       
        return alleBeds;
    }
   
    /**
     * Gibt die unsortierte Liste aller vorhandenen Bedingungen zur�ck.
     *
     * @return  Die unsortierte Liste aller Bedingungen.
     */
    public ArrayList<Transition> getBedListe() {
        ArrayList<Transition> beds = new ArrayList<Transition>();
        ArrayList<Integer> knoten = this.getKnList();
        Iterator<Integer> it = knoten.iterator();
        Knoten aktKnoten;
       
        while (it.hasNext()) {
            aktKnoten = this.holeKnoten(it.next());
            beds.addAll(((ZInfo) aktKnoten.getInfo()).getBeds());
        }
       
        return beds;
    }
   
    /**
     * Gibt zur�ck, ob bereits eine Kante vom Knoten mit Namen knoten1 zum
     * Knoten mit Namen knoten2 existiert.
     *
     * @param knoten1  Der Name des Ausgangsknotens A.
     * @param knoten2  Der Name des Zielknotens Z.
     *
     * @return Ob eine Kante von A nach Z existiert.
     */
    public boolean kanteExistiert(final Integer knoten1,
                                  final Integer knoten2) {
        Knoten k1;

        if (knoten1 == null || knoten2 == null) {
            return false;
        }
       
        k1 = this.holeKnoten(knoten1);

        if (k1 == null) {
            return false;
        }
       
        return k1.holeNachfolger().containsKey(knoten2);
    }
   
    /**
     * Gibt eine Liste aller Knoten des Automaten zur�ck.
     * @return  Eine Liste aller Knoten des Automaten zur�ck.
     */
    public ArrayList<Integer> getKnList() {
        return new ArrayList<Integer>(this.getAdjazenzliste().keySet());
    }

    /**
     * Gibt zur�ck, ob l von k aus erreichbar ist. Falls k == null, wird der
     * Startknoten gew�hlt. Dabei werden nur topologische Eigenschaften
     * betrachtet, ob Kantenbedingungen erf�llbar sind, wird nicht gepr�ft.
     *
     * @param k  Ein Startknotenname (kann null sein).
     * @param l  Ein Zielknotenname.
     *
     * @return  Ob l von k aus erreichbar ist.
     */
    public boolean erreichbar(final Integer k, final Integer l) {
        Knoten start;
        Knoten ziel;
       
        if (k == null) {
            start = this.holeStartzustand();
        } else {
            start = this.holeKnoten(k);
        }
       
        ziel = this.holeKnoten(l);
       
        if (start == null || ziel == null) {
            return false;
        }
           
        return erreichbar(start, ziel, new LinkedList<Knoten>());
    }
   
    /**
     * Gibt zur�ck, ob l von k aus erreichbar ist.
     *
     * @param k        Ein Knotenname (darf nicht null sein).
     * @param l        Ein Knotenname.
     * @param besucht  Liste bereits besuchter Knoten.
     *
     * @return  Ob l von k aus erreichbar ist.
     */
    private boolean erreichbar(final Knoten k,
                               final Knoten l,
                               final LinkedList<Knoten> besucht) {
        ArrayList<Knoten> nachF;
        Iterator<Knoten> it;
       
        if (k == l) {
            return true;
        }
       
        if (besucht.contains(k)) {
            return false;
        }
       
        besucht.add(k);
        nachF = new ArrayList<Knoten>(k.holeNachfolger().values());

        it = nachF.iterator();
        while (it.hasNext()) {
            Knoten aktNachf = (Knoten) it.next();
           
            LinkedList<Transition> transs
                = ((ZInfo) k.getInfo()).getTransZuZustand(
                        ((Integer) aktNachf.holeName()).intValue());
            Iterator<Transition> it2 = transs.iterator();
           
            while (it2.hasNext()) {
                Transition trans = (Transition) it2.next();
               
                // Pr�fen, ob Bedingung potentiell erf�llbar (nicht false).
                if (!trans.getCond().getClass().equals(ConstLeaf.class)
                        || trans.evaluiere(null)) {
                    if (erreichbar(aktNachf, l, besucht)) {
                        return true;
                    }
                } else {
                    break;
                }
            }
        }
       
        return false;
    }
   
    /**
     * Gibt die (erste) Bedingung zur�ck, mit der die Transition von k1 (mit
     * Namen kName1) nach k2 (mit Name kName2) beschriftet ist, falls eine
     * existiert, sonst null.
     *
     * @param kName1  Der Name von k1.
     * @param kName2  Der Name von k2.
     *
     * @return  Die Bedingung der Transition von k1 nach k2 oder null.
     */
    public Condition getCondZuTrans(final Integer kName1,
                                    final Integer kName2) {
        if (kName1 == null || kName2 == null) {
            return null;
        }

        Knoten k1 = this.holeKnoten(kName1);
        if (k1 == null) {
            return null;
        }
       
        ZInfo z = (ZInfo) k1.getInfo();
        List<Transition> l = z.getTransZuZustand(((Integer) kName2).intValue());
       
        if (l.size() > 0) {
            return ((Transition) l.get(0)).getCond();
        } else {
            return null;
        }
    }
   
    /**
     * Vereinfacht den endlichen Automaten.<BR>
     * <BR>
     * Bisher implementiert: (1) Nichterreichbare Zust�nde l�schen.
     *                       (2) true und false sowie andere Tautologien aus
     *                           nichttrivialen Transitionen entfernen.
     *                       (3) Inaktive Kanten entfernen.
     */
    public void vereinfache() {
        Integer knotenNam;
        LinkedList<Integer> zuEntf = new LinkedList<Integer>();
        ArrayList<Transition> beds;
        Iterator<Transition> it1;
        Iterator<Integer> it2;
        Transition trans;
       
        // Bedingungen vereinfachen.
        beds = this.getBedListe();       
        it1 = beds.iterator();
        while (it1.hasNext()) {
            trans = it1.next();
            Condition bedE = trans.getCond().simplify();
            trans.setBedingung(bedE.formatted());
        }
       
        // Unerreichbare Knoten l�schen.
        it2 = this.getKnList().iterator();
        while (it2.hasNext()) {
            knotenNam = it2.next();
            if (!this.erreichbar(null, knotenNam)) {
                zuEntf.add(knotenNam);
            }
        }

        it2 = zuEntf.iterator();
        while (it2.hasNext()) {
            this.entferneKnoten(it2.next());
        }

        // Inaktive Kanten l�schen.
        beds = this.getBedListe();
        it1 = beds.iterator();
        while (it1.hasNext()) {
            trans = it1.next();
            if (trans.getCond().getClass().equals(ConstLeaf.class)) {
                if (!trans.getCond().evaluiere(null)) {
                    this.entferneKante(
                        new Integer(trans.getUrsprungsZustand()),
                        new Integer(trans.getFolgezustand()),
                        trans);
                }
            }
           
        }
       
        this.sequenz = null;
    }
   
    /**
     * Erzeugt einen Automaten aus einem �bergebenen Script.
     *
     * @param script  Das Script, aus dem der Automat erzeugt werden soll.
     */
    public void erzeugeAusScript(final String script) {
        this.scriptInterpreter.generateAutomaton(this, new Script(script));
        this.sequenz = null;
    }
   
    /**
     * @param knotenName  Der Name des gesuchten Knotens.
     *
     * @return  Ob der Knoten existiert.
     */
    public boolean knotenExistiert(final Integer knotenName) {
        return this.getAdjazenzliste().containsKey(knotenName);
    }

    /**
     * @return Returns the scriptInterpreter.
     */
    public ScriptInterpreter getScriptInterpreter() {
        return this.scriptInterpreter;
    }
   
    /**
     * Setzt das Objekt auf "changed" als Nachricht f�r die Observer.
     */
    public void setzeChanged() {
        this.setChanged();
    }
   
    /**
     * @return  Der Hashcode.
     */
    @Override
    public int hashCode() {
        final int prime = 31;
        long result = 1;
        for (int i : this.getAdjazenzliste().keySet()) {
            result += prime * result + i;
            for (int j : this.holeKnoten(i).holeNachfolger().keySet()) {
                result += prime * result + j;
            }
        }
       
        return (int) (result % Integer.MAX_VALUE);
    }

    /**
     * Wie die equals-Methode, nur ohne Standardgebrauch mit hashCode().
     *
     * @param obj  Der zu vergleichende Automat.
     *
     * @return  Ob dieser und der zu vergleichende Automat aequivalent sind.
     */
    @Override
    public boolean equals(final Object obj) {
        if (this == obj) {
            return true;
        }
       
        if (obj == null) {
            return false;
        }
       
        if (this.getClass() != obj.getClass()) {
            return false;
        }
       
        final EndlicherAutomat anderer = (EndlicherAutomat) obj;
       
        HashSet<Integer> s1 = new HashSet<Integer>();
        HashSet<Integer> s2 = new HashSet<Integer>();
        Knoten k2;
       
        s1.addAll(this.getAdjazenzliste().keySet());
        s2.addAll(anderer.getAdjazenzliste().keySet());
       
        // �berpr�fe vorhandene Knotennamen in Automaten.
        if (!s1.equals(s2)) {
            return false;
        }
       
        // �berpr�fe f�r jeden Knoten: Info und Nachfolger der Knoten.
        for (Knoten k : this.getAdjazenzliste().values()) {
            k2 = anderer.holeKnoten(k.holeName());
            s1.clear();
            s2.clear();
            s1.addAll(k.holeNachfolger().keySet());
            s2.addAll(k2.holeNachfolger().keySet());
           
            if (!s1.equals(s2)
                    || !k.getInfo().equals(k2.getInfo())) {
                return false;
            }
        }
       
        return true;
    }

    /**
     * @param scriInt  Der neue Scriptinterpreter.
     */
    public void setScriptInterpreter(final ScriptInterpreter scriInt) {
        this.scriptInterpreter = scriInt;
    }
}
TOP

Related Classes of fmg.fmg8.endlAutomat.EndlicherAutomat

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.