001
002
003
004
005package org.biojava.utils.automata;
006
007import java.util.HashMap;
008import java.util.HashSet;
009import java.util.Iterator;
010import java.util.Map;
011import java.util.Set;
012
013import org.biojava.bio.symbol.Symbol;
014
015/**
016 * This class caches a reference to all objects that
017 * it directs its delegate to make.  These references
018 * make it relatively easy for it to duplicate
019 * all objects made through this class.
020 */
021public class NfaSubModel
022    implements NfaBuilder
023{
024    private NfaBuilder delegate;
025    private Set nodes = new HashSet();
026    private Set transitions = new HashSet();
027
028    private FiniteAutomaton.Node start = null;
029    private FiniteAutomaton.Node end = null;
030
031    NfaSubModel(NfaBuilder delegate)
032    {
033        this.delegate = delegate;
034        start = addNode(false);
035        end = addNode(false);
036    }
037
038    public FiniteAutomaton getAutomaton()
039    {
040        return delegate.getAutomaton();
041    }
042
043    public FiniteAutomaton.Node getStart() { return start; }
044    public FiniteAutomaton.Node getEnd() { return end; }
045
046    void setStart(FiniteAutomaton.Node start)
047    {
048        nodes.add(start);
049        this.start = start;
050    }
051
052    void setEnd(FiniteAutomaton.Node end)
053    {
054        nodes.add(end);
055        this.end = end;
056    }
057
058    public FiniteAutomaton.Node addNode(boolean isTerminal)
059    {
060        FiniteAutomaton.Node newNode = delegate.addNode(isTerminal);
061        nodes.add(newNode);
062        return newNode;
063    }
064
065    public FiniteAutomaton.Transition addTransition(FiniteAutomaton.Node start, FiniteAutomaton.Node end, Symbol sym)
066    {
067        FiniteAutomaton.Transition newTransition = delegate.addTransition(start, end, sym);
068        transitions.add(newTransition);
069        return newTransition;
070    }
071
072    public FiniteAutomaton.Transition addEpsilonTransition(FiniteAutomaton.Node start, FiniteAutomaton.Node end)
073    {
074        FiniteAutomaton.Transition newTransition = delegate.addEpsilonTransition(start, end);
075        transitions.add(newTransition);
076        return newTransition;
077    }
078
079    public FiniteAutomaton.Transition addLambdaTransition(FiniteAutomaton.Node start, FiniteAutomaton.Node end)
080    {
081        FiniteAutomaton.Transition newTransition = delegate.addLambdaTransition(start, end);
082        transitions.add(newTransition);
083        return newTransition;
084    }
085
086    public FiniteAutomaton.NodeSet getNodes()
087    {
088        FiniteAutomaton.NodeSet nodeSet = delegate.createNodeSet();
089        nodeSet.addAll(nodes);
090        return nodeSet;
091    }
092
093    public Set getTransitions()
094    {
095        return transitions;
096    }
097
098    public FiniteAutomaton.NodeSet createNodeSet()
099    {
100        return delegate.createNodeSet();
101    }
102
103    /**
104     * Makes a deep clone of this instance.
105     */
106    public NfaSubModel duplicate()
107    {
108        // create a new NfaSubModel
109        NfaSubModel newSubModel = new NfaSubModel(delegate);
110
111        // create a mapping between old and new Nodes
112        Map old2New = new HashMap();
113
114        for (Iterator nodesI = nodes.iterator(); nodesI.hasNext(); ) {
115            FiniteAutomaton.Node oldNode = (FiniteAutomaton.Node) nodesI.next();
116            old2New.put(oldNode, newSubModel.addNode(oldNode.isTerminal()));
117        } 
118
119        // set up the start and end
120        newSubModel.setStart((FiniteAutomaton.Node) old2New.get(start));
121        newSubModel.setEnd((FiniteAutomaton.Node) old2New.get(end));
122
123        // for each transition, create a new one with remapped
124        // nodes.
125        for (Iterator transI = transitions.iterator(); transI.hasNext(); ) {
126            FiniteAutomaton.Transition oldTrans = (FiniteAutomaton.Transition) transI.next();
127
128            newSubModel.addTransition((FiniteAutomaton.Node) old2New.get(oldTrans.source), 
129                (FiniteAutomaton.Node) old2New.get(oldTrans.dest), oldTrans.sym);
130        }
131
132        return newSubModel;
133    }
134
135    public void append(NfaSubModel submodel)
136    {
137        addEpsilonTransition(end, submodel.getStart());
138        setEnd(submodel.getEnd());
139    }
140
141    public String toString() { return delegate.toString(); }
142}
143