View Javadoc

1   package cz.cuni.amis.pogamut.sposh.elements;
2   
3   import cz.cuni.amis.pogamut.sposh.exceptions.*;
4   import java.awt.datatransfer.DataFlavor;
5   import java.util.Collections;
6   import java.util.LinkedList;
7   import java.util.List;
8   import java.util.logging.Level;
9   import java.util.logging.Logger;
10  
11  /**
12   * Structure for holding information about competences in POSH file. Competence
13   * is basic reactive plans. They allow a BOD agent to complete a task robustly
14   * and opportunistically.
15   *
16   * @author HonzaH
17   */
18  public final class Competence extends NamedLapElement implements Comparable<Competence> {
19  
20      /**
21       * Name of this competence, can be referenced
22       */
23      private String name;
24      /**
25       * Formal parameters of the competence
26       */
27      private FormalParameters params = new FormalParameters();
28      /**
29       * List of all possible elements (choices) of this competence
30       */
31      private final List<CompetenceElement> elements = new LinkedList<CompetenceElement>();
32      /**
33       * Unmodifiable proxy list of elements
34       */
35      private final List<CompetenceElement> elementsUm = Collections.unmodifiableList(elements);
36      /**
37       * Property string of competence name
38       */
39      public static final String cnName = "cnName";
40      /**
41       * Data flavor of competence classs, used for drag-and-drop
42       */
43      public static final DataFlavor dataFlavor = new DataFlavor(Competence.class, "competence-node");
44  
45      /**
46       * Create a new Competence with passed name and assign passed elements to
47       * this competence (set parent).
48       *
49       * @param name Name of competence node, it can be referenced
50       * @param elements List of elements that are not part of any other
51       * competence. Shallow copy
52       * @throws FubarException if names of elements are not unique
53       */
54      public Competence(String name, FormalParameters params, List<CompetenceElement> elements) {
55          this.name = name;
56          this.params = new FormalParameters(params);
57  
58          try {
59              for (CompetenceElement element : elements) {
60                  addElement(element);
61              }
62          } catch (DuplicateNameException ex) {
63              Logger.getLogger(Competence.class.getName()).log(Level.SEVERE, ex.getMessage(), ex);
64              throw new FubarException(ex);
65          }
66      }
67  
68      /**
69       * Add passed element as the last element of this competence and emit.
70       *
71       * @param element element that will be added into this competence
72       */
73      public void addElement(CompetenceElement element) throws DuplicateNameException {
74          // sanity check that element's parent doesn't list element as a child
75          if (element.getParent() != null) {
76              assert !element.getParent().getChildDataNodes().contains(element);
77          }
78  
79          if (isUsedName(element.getName(), elementsUm)) {
80              throw new DuplicateNameException("Competence " + name + " already has element with name " + element.getName());
81          }
82  
83          elements.add(element);
84          element.setParent(this);
85  
86          emitChildNode(element);
87      }
88  
89      /**
90       * Create text representation of this competence, compatible with parser, so
91       * we can directly output it.
92       *
93       * @return
94       */
95      @Override
96      public String toString() {
97          String ret = "\t(C " + name;
98          // parameters of the competence are right after declaration
99          if (!params.isEmpty()) {
100             ret += " vars(" + params.toString() + ")";
101         }
102         ret += "\n\t\t(elements";
103         // In order to utilize compatibility with older plans, use dbl  braces
104         for (CompetenceElement element : elements) {
105             ret += "\n\t\t\t(" + element.toString() + ")";
106         }
107         return ret + "\n\t\t)\n\t)";
108     }
109 
110     @Override
111     public List<CompetenceElement> getChildDataNodes() {
112         return elementsUm;
113     }
114 
115     /**
116      * Change name of competence node.
117      *
118      * @param name new name of competence node
119      */
120     public void setName(String name) throws DuplicateNameException, CycleException, InvalidNameException {
121         PoshPlan plan = getRootNode();
122 
123         name = name.trim();
124 
125         if (!name.matches(IDENT_PATTERN)) {
126             throw new InvalidNameException("Name " + name + " is not valid.");
127         }
128 
129         // Check for duplicity
130         if (!this.name.equals(name)) {
131             if (plan != null && !plan.isUniqueAPorComp(name)) {
132                 throw new DuplicateNameException("New name for competence '" + this.name + "'(" + name + ") is not unique for reaction plan.");
133             }
134         }
135 
136         String oldName = this.name;
137         this.name = name;
138 
139         if (plan != null && plan.isCycled()) {
140             this.name = oldName;
141             throw new CycleException("New name (" + name + ") for competence '" + this.name + "' is causing cycle.");
142         }
143         firePropertyChange(cnName, oldName, name);
144     }
145 
146     /**
147      * Get name of the competence
148      *
149      * @return name of the competence
150      */
151     @Override
152     public String getName() {
153         return name;
154     }
155 
156     @Override
157     public boolean moveChild(PoshElement child, int relativePosition) {
158         return moveNodeInList(elements, child, relativePosition);
159     }
160 
161     @Override
162     public DataFlavor getDataFlavor() {
163         return dataFlavor;
164     }
165 
166     @Override
167     public void addChildDataNode(PoshElement element) throws DuplicateNameException {
168         if (element instanceof CompetenceElement) {
169             addElement((CompetenceElement) element);
170         } else {
171             throw new UnexpectedElementException("Class " + element.getClass().getSimpleName() + " not accepted.");
172         }
173     }
174 
175     @Override
176     public void neutralizeChild(PoshElement child) {
177         if (elements.contains(child)) {
178             if (elements.size() == 1) {
179                 String unusedName = getUnusedName("choice-", elementsUm);
180                 try {
181                     addElement(CompetenceElement.create(unusedName));
182                 } catch (DuplicateNameException ex) {
183                     String msg = "Unused name " + unusedName + " is not unused.";
184                     Logger.getLogger(Competence.class.getName()).log(Level.SEVERE, msg, ex);
185                     throw new FubarException(msg, ex);
186                 }
187             }
188             elements.remove(child);
189             child.remove();
190         } else {
191             throw new UnexpectedElementException("Not expecting " + child.toString());
192         }
193     }
194 
195     @Override
196     public int compareTo(Competence o) {
197         return toString().compareTo(o.toString());
198     }
199 
200     /**
201      * Get list of formal parametrs of competence (names and default values).
202      *
203      * @return
204      */
205     public FormalParameters getParameters() {
206         return params;
207     }
208 }