001    /**
002     * @author paulk
003     */
004    package toolbus;
005    
006    import java.util.ArrayList;
007    import java.util.IdentityHashMap;
008    import java.util.Iterator;
009    import java.util.List;
010    import toolbus.atom.Atom;
011    import toolbus.atom.msg.SndMsg;
012    import toolbus.environment.Environment;
013    import toolbus.exceptions.ToolBusException;
014    import toolbus.process.ProcessInstance;
015    import toolbus.process.debug.ExecutionResult;
016    import aterm.ATerm;
017    
018    /**
019     * class State represents one state in the state diagram of a process. It consists of StateElements
020     */
021    public class State{
022            private final List<StateElement> elements;
023            
024            private final IdentityHashMap<StateElement, Boolean> cache;
025            
026            private int nElements = 0;
027            
028            private int lastElement = 0;
029            
030            private boolean allAtoms = true;
031            
032            public State(){
033                    elements = new ArrayList<StateElement>();
034                    
035                    cache = new IdentityHashMap<StateElement, Boolean>();
036            }
037            
038            public void addElement(StateElement a){
039                    if(!elements.contains(a)){
040                            elements.add(a);
041                            nElements += 1;
042                            if(!(a instanceof Atom)){
043                                    allAtoms = false;
044                            }
045                    }
046            }
047            
048            public void delElement(StateElement a){
049                    if(elements.remove(a)) nElements -= 1;
050            }
051            
052            public State union(State b){
053                    State c = new State();
054                    
055                    Iterator<StateElement> elementsIterator = elements.iterator();
056                    while(elementsIterator.hasNext()){
057                            StateElement se = elementsIterator.next();
058                            
059                            c.addElement(se);
060                    }
061                    
062                    Iterator<StateElement> stateIterator = b.getElementsAsList().iterator();
063                    while(stateIterator.hasNext()){
064                            StateElement se = stateIterator.next();
065                            
066                            c.addElement(se);
067                    }
068                    return c;
069            }
070            
071            public List<StateElement> getElementsAsList(){
072                    return elements;
073            }
074            
075            public int size(){
076                    return elements.size();
077            }
078            
079            public void setTest(ATerm test, Environment env) throws ToolBusException{
080                    if(test != null){
081                            Iterator<StateElement> elementsIterator = elements.iterator();
082                            while(elementsIterator.hasNext()){
083                                    StateElement a = elementsIterator.next();
084                                    
085                                    a.setTest(test, env);
086                            }
087                    }
088            }
089            
090            public boolean isEnabled(){
091                    Iterator<StateElement> elementsIterator = elements.iterator();
092                    while(elementsIterator.hasNext()){
093                            StateElement a = elementsIterator.next();
094                            
095                            try{
096                                    if(a.isEnabled()){
097                                            return true;
098                                    }
099                            }catch(ToolBusException e){
100                                    // TODO Auto-generated catch block
101                                    e.printStackTrace();
102                            }
103                    }
104                    return false;
105            }
106            
107            public String toString(){
108                    String sep = "";
109                    
110                    String s = "{";
111                    
112                    Iterator<StateElement> elementsIterator = elements.iterator();
113                    while(elementsIterator.hasNext()){
114                            StateElement a = elementsIterator.next();
115                            
116                            s += sep + a;
117                            sep = ",\n  ";
118                    }
119                    
120                    s += "}";
121                    
122                    return s;
123            }
124            
125            public boolean contains(StateElement a){
126                    if(cache.containsKey(a)){
127                            Boolean bval = cache.get(a);
128                            return bval.booleanValue();
129                    }
130                    Iterator<StateElement> elementsIterator = elements.iterator();
131                    while(elementsIterator.hasNext()){
132                            StateElement b = elementsIterator.next();
133                            
134                            if(b.contains(a)){
135                                    if(allAtoms) cache.put(a, Boolean.TRUE);
136                                    return true;
137                            }
138                    }
139                    if(allAtoms) cache.put(a, Boolean.FALSE);
140                    
141                    return false;
142            }
143            
144            public State gotoNextStateAndActivate(){
145                    if(nElements > 0){
146                            return elements.get(lastElement).gotoNextStateAndActivate();
147                    }
148                    return this;
149            }
150            
151            public State gotoNextStateAndActivate(StateElement a){
152                    Iterator<StateElement> elementsIterator = elements.iterator();
153                    while(elementsIterator.hasNext()){
154                            StateElement b = elementsIterator.next();
155                            
156                            // System.err.println("State.getNextState2: trying " + b);
157                            if(b.equals(a) || b.contains(a)){
158                                    return b.gotoNextStateAndActivate(a);
159                            }
160                    }
161                    System.err.println("State.GetNextState2: no element " + a);
162                    return null;
163            }
164            
165            public void activate(){
166                    // System.err.println("State.activate: " + this);
167                    Iterator<StateElement> elementsIterator = elements.iterator();
168                    while(elementsIterator.hasNext()){
169                            StateElement e = elementsIterator.next();
170                            
171                            e.activate();
172                    }
173            }
174            
175            /**
176             * Execute one step for an element in this state.
177             */
178            public boolean execute() throws ToolBusException{
179                    if(nElements == 0) return false;
180                    
181                    for(int index = (lastElement + 1) % nElements, nleft = nElements; nleft > 0; index = (index + 1) % nElements, nleft--){
182                            StateElement a = elements.get(index);
183                            
184                            if(a.execute()){
185                                    lastElement = index;
186                                    //LoggerFactory.log(a.getProcess().getProcessName(), "execute: " + a, IToolBusLoggerConstants.EXECUTE);
187                                    
188                                    return true;
189                            }
190                    }
191                    return false;
192            }
193            
194            /**
195             * Executes one step in debug mode and returns the executed state element as result.
196             * 
197             * @return The result of the execution (if contains the state element and partners); null if
198             * none was executed.
199             * @throws ToolBusException Thrown if something went wrong.
200             */
201            public ExecutionResult debugExecute() throws ToolBusException{
202                    if(nElements == 0) return null;
203                    
204                    for(int index = (lastElement + 1) % nElements, nleft = nElements; nleft > 0; index = (index + 1) % nElements, nleft--){
205                            StateElement a = elements.get(index);
206                            
207                            ProcessInstance[] partners = a.debugExecute();
208                            if(partners != null){
209                                    lastElement = index;
210                                    
211                                    return new ExecutionResult(a, partners);
212                            }
213                    }
214                    return null;
215            }
216            
217            /**
218             * Returns the last executed state element in the current state.
219             * (This method is used for debugging only).
220             * @return The last executed state element in the current state.
221             */
222            public StateElement getLastExecutedStateElement(){
223                    return elements.get(lastElement);
224            }
225            
226            public List<StateElement> getUnhandledMessages(){
227                    List<StateElement> unhandledMessages = new ArrayList<StateElement>();
228                    
229                    int nrOfElements = elements.size();
230                    
231                    try{
232                            while((--nrOfElements) >= 0){
233                                    StateElement element = elements.get(nrOfElements);
234                                    if(element instanceof SndMsg){
235                                            unhandledMessages.add(element);
236                                    }
237                            }
238                    }catch(RuntimeException rex){
239                            // This will never happen, it's here just in case.
240                    }
241                    
242                    return unhandledMessages;
243            }
244    }