View Javadoc

1   package cz.cuni.amis.pogamut.sposh.elements;
2   
3   import java.util.ArrayList;
4   import java.util.List;
5   import java.awt.datatransfer.DataFlavor;
6   import java.util.Collections;
7   
8   /**
9    * CompetenceElement is basic unit of competence.
10   * <p>
11   * It has name, list of triggers and defined action that should be done
12   * if triggers are fullfilled.
13   * <p>
14   * Example in POSH:
15   * <pre>(move (trigger ((see-player))) move-player)</pre>
16   * 
17   * @author HonzaH
18   */
19  public class CompetenceElement extends NamedLapElement {
20      // XXX: more refined, later
21      static CompetenceElement create() {
22          return new CompetenceElement("choice", new Sense("succeed"), "doNothing", null);
23      }
24  
25      /**
26       * Create new element with specified name
27       * @param name name of new element
28       * @return created competence element 
29       */
30      static CompetenceElement create(String name) {
31          return new CompetenceElement(name, new Sense("succeed"), "doNothing", null);
32      }
33  
34      private String name;
35      private ElementList<Sense> triggers;
36      private TriggeredAction action;
37      private Integer retries;
38      private String comment;
39      public static final String caName = "caName";
40      public static final String caRetries = "caRetries";
41      public static final String caComment = "caComment";
42  
43      /**
44       * Create competence atom from passed parameters and assign
45       * parents propertly.
46       *
47       * @param name Name of competence atom. Mostly for use, not used in execution of POSH plan.
48       * @param triggers List of senses. If triggers are fulfilled, competence can execute the action.
49       * @param actionName Name of action, can be normal action, ActionPattern name or another competence name. Cycles are not allowed.
50       * @param retries can be null.
51       */
52      public CompetenceElement(String name,
53              ElementList<Sense> triggers,
54              String actionName,
55              Integer retries,
56              String comment) {
57          this(name, triggers, new Sense.SenseCall(actionName), retries, comment);
58      }
59      
60      public CompetenceElement(String name,
61              ElementList<Sense> triggers,
62              Sense.SenseCall actionCall,
63              Integer retries,
64              String comment) {
65          if (triggers == null) {
66              triggers = new ElementList<Sense>();
67          }
68  
69          this.name = name;
70          this.triggers = triggers;
71          this.action = new TriggeredAction(actionCall);
72          this.retries = retries;
73          this.comment = comment;
74  
75          action.setParent(this);
76          for (Sense sense : triggers) {
77              sense.setParent(this);
78          }
79      }
80  
81      /**
82       * Create an CompetenceElement from passed parameters.
83       * See {@link CompetenceElement#CompetenceElement(java.lang.String, cz.cuni.pogamut.posh.tree.ElementList, java.lang.String, java.lang.Integer) other constructor}
84       * for parameters.
85       */
86      public CompetenceElement(String name,
87              Sense triggers,
88              String actionName,
89              Integer retries) {
90          this(name, new ElementList<Sense>(new Sense[]{triggers}), actionName, retries, null);
91      }
92  
93      /**
94       * Add trigger sense to this competence atom.
95       * Emit new child node after addition.
96       *
97       * @param trigger Sense, that is necessary to trigger this action.
98       */
99      public void addTriggerAct(Sense trigger) {
100         trigger.setParent(this);
101         triggers.add(trigger);
102         emitChildNode(trigger);
103     }
104 
105     /**
106      * This method differs from {@link CompetenceElement.addTriggerAct} because if
107      * the only trigger is <b>fail</b> or <b>succeed</b>, than replace it with
108      * passed sense.
109      * <p>
110      * Otherwise same as {@link CompetenceElement.addTriggerAct}.
111      */
112     public void addUserTrigger(Sense trigger) {
113         if (triggers.size() == 1 && (
114                 "fail".equals(triggers.get(0).getSenseName()) ||
115                 "succeed".equals(triggers.get(0).getSenseName()))) {
116             triggers.get(0).changeTo(trigger);
117         } else {
118             addTriggerAct(trigger);
119         }
120     }
121 
122     /**
123      * Set action (by removing old action and emiting new one) of this
124      * CompetenceElement.
125      *
126      * @param newAction
127      */
128     public void setAction(TriggeredAction newAction) {
129         // Remove old action
130         action.remove();
131         action.setParent(null);
132 
133         // and set new one
134         newAction.setParent(this);
135         this.action = newAction;
136         emitChildNode(newAction);
137     }
138 
139     public TriggeredAction getAction() {
140         return action;
141     }
142 
143     @Override
144     public String toString() {
145         String ret;
146         if (triggers.size() == 0) {
147             ret = "(" + name + " " + action.getName();
148         } else {
149             ret = "(" + name + " (trigger " + triggers.toString() + ") " + action.getName();
150         }
151 
152         if (retries != null) {
153             ret += " " + retries.toString();
154         }
155 
156         if (comment != null) {
157             ret += " \"" + comment + "\"";
158         }
159 
160         return ret + ")";
161     }
162 
163     @Override
164     public List<PoshElement> getChildDataNodes() {
165         List<PoshElement> children = new ArrayList<PoshElement>(triggers);
166         children.add(action);
167         return children;
168     }
169 
170     public String getComment() {
171         return comment;
172     }
173 
174     public void setComment(String comment) {
175         this.comment = comment;
176     }
177 
178     @Override
179     public String getName() {
180         return this.name;
181     }
182 
183     /**
184      * Set name of Competence atom, name has to match <tt>IDENT_PATTERN</tt>, trimmed.
185      * @param name
186      */
187     public void setName(String name) {
188         name = name.trim();
189         if (name.matches(IDENT_PATTERN)) {
190             this.name = name;
191             firePropertyChange(caName, null, name);
192         }
193     }
194 
195     public Integer getRetries() {
196         return this.retries;
197     }
198 
199     public void setRetries(Integer retries) {
200         this.retries = retries;
201         firePropertyChange(caRetries, null, retries);
202     }
203 
204     @Override
205     public boolean moveChild(PoshElement child, int relativePosition) {
206         return moveNodeInList(this.triggers, child, relativePosition);
207     }
208     public static final DataFlavor dataFlavor = new DataFlavor(CompetenceElement.class, "competence-atom");
209 
210     @Override
211     public DataFlavor getDataFlavor() {
212         return dataFlavor;
213     }
214 
215     @Override
216     public void addChildDataNode(PoshElement newChild) {
217         if (newChild instanceof Sense) {
218             this.addTriggerAct((Sense) newChild);
219         } else if (newChild instanceof TriggeredAction) {
220             this.setAction((TriggeredAction) newChild);
221         }
222     }
223 
224     @Override
225     public void neutralizeChild(PoshElement childNode) {
226         if (this.action == childNode) {
227             this.setAction(new TriggeredAction("do_nothing"));
228         } else if (this.triggers.contains(childNode)) {
229             if (this.triggers.size() <= 1) {
230                 this.addTriggerAct(new Sense("succeed"));
231             }
232             this.triggers.remove(childNode);
233             childNode.remove();
234         }
235     }
236 
237     /**
238      * Get unmodifiable list of trigger senses in the CE
239      */
240     public List<Sense> getTriggerSenses() {
241         return Collections.unmodifiableList(triggers);
242     }
243 }