1 package cz.cuni.amis.pogamut.sposh.elements;
2
3 import cz.cuni.amis.pogamut.sposh.exceptions.CycleException;
4 import cz.cuni.amis.pogamut.sposh.exceptions.DuplicateNameException;
5 import cz.cuni.amis.pogamut.sposh.exceptions.FubarException;
6 import java.awt.datatransfer.DataFlavor;
7 import java.util.ArrayList;
8 import java.util.Collections;
9 import java.util.HashSet;
10 import java.util.LinkedList;
11 import java.util.List;
12 import java.util.Set;
13
14
15
16
17
18
19
20
21
22
23
24 public final class PoshPlan extends PoshDummyElement<PoshPlan, PoshPlan> {
25
26
27
28
29 private String name = "";
30
31
32
33 private String author = "";
34
35
36
37 private String info = "";
38
39
40
41 private final DriveCollection dc;
42
43
44
45 private final List<ActionPattern> aps = new ArrayList<ActionPattern>();
46 private final List<ActionPattern> apsUm = Collections.unmodifiableList(aps);
47
48
49
50 private final List<Competence> cs = new ArrayList<Competence>();
51 private final List<Competence> csUm = Collections.unmodifiableList(cs);
52
53
54
55 private final List<Adopt> ads = new ArrayList<Adopt>();
56 private final List<Adopt> adsUm = Collections.unmodifiableList(ads);
57
58
59
60
61 public static final DataFlavor dataFlavor = new DataFlavor(PoshPlan.class, "posh_tree_root");
62
63
64
65 public static final String PROP_NAME = "posh-plan-name";
66
67
68
69 public static final String PROP_AUTHOR = "posh-plan-author";
70
71
72
73 public static final String PROP_INFO = "posh-plan-info";
74
75
76
77
78
79
80
81 PoshPlan(String driveCollectionName) {
82 this.dc = LapElementsFactory.createDriveCollection(driveCollectionName);
83 this.dc.setParent(this);
84 }
85
86
87 private Set<String> getReachableActionNames() {
88 Set<String> reachableNames = new HashSet<String>();
89
90 for (DriveElement drive : dc.getDrives()) {
91 String driveActionName = drive.getAction().getName();
92 if (isAP(driveActionName)) {
93 ActionPattern actionPattern = getAP(driveActionName);
94 reachableNames.addAll(getActionPatternActionNames(actionPattern));
95
96 } else if (isC(driveActionName)) {
97 Competence competence = getC(driveActionName);
98 reachableNames.addAll(getCompetenceActionNames(competence));
99 } else {
100 reachableNames.add(driveActionName);
101 }
102 }
103
104 return reachableNames;
105 }
106
107 private Set<String> getCompetenceActionNames(Competence c) {
108 throw new UnsupportedOperationException();
109 }
110
111 private Set<String> getActionPatternActionNames(ActionPattern ap) {
112 throw new UnsupportedOperationException();
113 }
114
115
116
117
118
119
120
121
122 public Set<String> getActionsNames() {
123 Set<String> actionNames = new HashSet<String>();
124 List<TriggeredAction> actions = getActions();
125
126 for (TriggeredAction action : actions) {
127 actionNames.add(action.getName());
128 }
129
130 return actionNames;
131 }
132
133
134
135
136
137
138
139
140 public List<TriggeredAction> getActions() {
141 List<TriggeredAction> references = getAllReferences();
142 List<TriggeredAction> actions = new LinkedList<TriggeredAction>();
143
144 for (TriggeredAction reference : references) {
145 String referenceName = reference.getName();
146 if (!isAP(referenceName) && !isC(referenceName) && !isAD(referenceName)) {
147 actions.add(reference);
148 }
149 }
150 return actions;
151 }
152
153 public List<TriggeredAction> getAllReferences() {
154 List<TriggeredAction> references = new LinkedList<TriggeredAction>();
155 for (DriveElement drive : dc.getDrives()) {
156 references.add(drive.getAction());
157 }
158 for (Competence competence : csUm) {
159 for (CompetenceElement competenceElement : competence.getChildDataNodes()) {
160 references.add(competenceElement.getAction());
161 }
162 }
163 for (ActionPattern actionPattern : apsUm) {
164 for (TriggeredAction action : actionPattern.getActions()) {
165 references.add(action);
166 }
167 }
168 for (Adopt adopt : adsUm) {
169 references.add(adopt.getAdoptedElement());
170 }
171 return references;
172 }
173
174
175
176
177
178
179
180 public Set<String> getSensesNames() {
181 Set<String> senseNames = new HashSet<String>();
182
183 addTriggerSenseNames(dc.getGoal(), senseNames);
184
185 for (DriveElement drive : dc.getDrives()) {
186 addTriggerSenseNames(drive.getTrigger(), senseNames);
187 }
188 for (Competence competence : csUm) {
189 for (CompetenceElement competenceElement : competence.getChildDataNodes()) {
190 addTriggerSenseNames(competenceElement.getTrigger(), senseNames);
191 }
192 }
193 for (Adopt adopt : adsUm) {
194 addTriggerSenseNames(adopt.getExitCondition(), senseNames);
195 }
196
197 return senseNames;
198 }
199
200
201
202
203
204
205
206 private void addTriggerSenseNames(Trigger<?> trigger, Set<String> senseNames) {
207 for (Sense triggerSense : trigger) {
208 senseNames.add(triggerSense.getName());
209 }
210 }
211
212
213
214
215
216
217
218 public boolean isC(String name) {
219 return getC(name) != null;
220 }
221
222
223
224
225
226
227
228 public Competence getC(String name) {
229 for (Competence c : getCompetences()) {
230 if (c.getName().equals(name)) {
231 return c;
232 }
233 }
234 return null;
235 }
236
237
238
239
240
241 public Competence getCompetence(int id) {
242 return csUm.get(id);
243 }
244
245
246
247
248
249
250
251
252 public boolean isAP(String name) {
253 return getAP(name) != null;
254 }
255
256
257
258
259
260
261
262 public ActionPattern getAP(String name) {
263 for (ActionPattern ap : getActionPatterns()) {
264 if (ap.getName().equals(name)) {
265 return ap;
266 }
267 }
268 return null;
269 }
270
271
272
273
274 public ActionPattern getActionPattern(int id) {
275 return apsUm.get(id);
276 }
277
278
279
280
281
282
283
284 public boolean isAD(String name) {
285 return getAD(name) != null;
286 }
287
288
289
290
291
292
293
294 public Adopt getAD(String name) {
295 for (Adopt ad : getAdopts()) {
296 if (ad.getName().equals(name)) {
297 return ad;
298 }
299 }
300 return null;
301 }
302
303
304
305
306 public Adopt getAdopt(int id) {
307 return adsUm.get(id);
308 }
309
310
311
312
313
314
315
316
317
318
319 public boolean isUniqueNodeName(String testedName) {
320 return !isAP(testedName) && !isC(testedName) && !isAD(testedName);
321 }
322
323
324
325
326
327
328 public void addCompetence(Competence competence) throws DuplicateNameException, CycleException {
329 if (!isUniqueNodeName(competence.getName())) {
330 throw DuplicateNameException.create(competence.getName());
331 }
332
333 PoshPlan orgParent = competence.getParent();
334 cs.add(competence);
335 competence.setParent(this);
336
337 if (isCycled()) {
338 competence.setParent(orgParent);
339 cs.remove(competence);
340
341 throw CycleException.createFromName(competence.getName());
342 }
343
344 emitChildNode(competence);
345 }
346
347 public void addAdopt(Adopt adopt) throws DuplicateNameException, CycleException {
348 if (!isUniqueNodeName(adopt.getName())) {
349 throw DuplicateNameException.create(adopt.getName());
350 }
351
352 PoshPlan orgParent = adopt.getParent();
353 ads.add(adopt);
354 adopt.setParent(this);
355
356 if (isCycled()) {
357 adopt.setParent(orgParent);
358 ads.remove(adopt);
359
360 throw CycleException.createFromName(adopt.getName());
361 }
362
363 emitChildNode(adopt);
364 }
365
366
367
368
369
370
371
372 public String getName() {
373 return name;
374 }
375
376
377
378
379
380
381 public void setName(String name) {
382 assert name != null;
383
384 String oldName = this.name;
385 this.name = name;
386
387 firePropertyChange(PROP_NAME, oldName, name);
388 }
389
390
391
392
393
394
395
396 public String getAuthor() {
397 return this.author;
398 }
399
400
401
402
403
404
405 public void setAuthor(String author) {
406 assert author != null;
407
408 String oldAuthor = this.author;
409 this.author = author;
410
411 firePropertyChange(PROP_AUTHOR, oldAuthor, author);
412 }
413
414
415
416
417
418
419
420 public String getInfo() {
421 return this.info;
422 }
423
424
425
426
427
428
429 public void setInfo(String info) {
430 assert info != null;
431
432 String oldInfo = this.info;
433 this.info = info;
434
435 firePropertyChange(PROP_INFO, oldInfo, info);
436 }
437
438
439
440
441
442
443 public List<Competence> getCompetences() {
444 return csUm;
445 }
446
447
448
449
450
451
452 public void addActionPattern(ActionPattern actionPattern) throws DuplicateNameException, CycleException {
453 if (!this.isUniqueNodeName(actionPattern.getName())) {
454 throw new DuplicateNameException("Action pattern '" + actionPattern.getName() + "' has duplicate name in POSH plan.");
455 }
456
457 PoshPlan orgParent = actionPattern.getParent();
458 this.aps.add(actionPattern);
459 actionPattern.setParent(this);
460
461
462 if (this.isCycled()) {
463 actionPattern.setParent(orgParent);
464 this.aps.remove(actionPattern);
465
466 throw CycleException.createFromName(name);
467 }
468
469 emitChildNode(actionPattern);
470 }
471
472
473
474
475
476
477 public List<Adopt> getAdopts() {
478 return adsUm;
479 }
480
481
482
483
484
485
486 public List<ActionPattern> getActionPatterns() {
487 return apsUm;
488 }
489
490
491
492
493 public DriveCollection getDriveCollection() {
494 return dc;
495 }
496
497
498
499
500
501
502
503 public boolean isCycled() {
504
505 for (ActionPattern apNode : this.aps) {
506 if (findCycle(apNode, new HashSet<String>())) {
507 return true;
508 }
509 }
510 for (Competence compNode : this.cs) {
511 if (findCycle(compNode, new HashSet<String>())) {
512 return true;
513 }
514 }
515 return false;
516 }
517
518
519
520
521
522
523
524
525
526
527
528
529
530 private boolean findCycle(ActionPattern apNode, Set<String> set) {
531 if (set.contains(apNode.getName())) {
532 return true;
533 }
534 set.add(apNode.getName());
535
536 for (TriggeredAction action : apNode.getActions()) {
537 ActionPattern actionAP;
538 if ((actionAP = getAP(action.getName())) != null) {
539 if (findCycle(actionAP, set)) {
540 return true;
541 }
542 }
543
544 Competence actionComp;
545 if ((actionComp = getC(action.getName())) != null) {
546 if (findCycle(actionComp, set)) {
547 return true;
548 }
549 }
550 }
551 set.remove(apNode.getName());
552 return false;
553 }
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568 private boolean findCycle(Competence compNode, Set<String> set) {
569 if (set.contains(compNode.getName())) {
570 return true;
571 }
572
573 set.add(compNode.getName());
574
575 for (CompetenceElement element : compNode.getChildDataNodes()) {
576 TriggeredAction action = element.getAction();
577
578 ActionPattern actionAP;
579 if ((actionAP = getAP(action.getName())) != null) {
580 if (findCycle(actionAP, set)) {
581 return true;
582 }
583 }
584
585 Competence actionComp;
586 if ((actionComp = getC(action.getName())) != null) {
587 if (findCycle(actionComp, set)) {
588 return true;
589 }
590 }
591 }
592 set.remove(compNode.getName());
593 return false;
594 }
595
596
597
598
599 @Override
600 public String toString() {
601 StringBuilder sb = new StringBuilder("(");
602
603 if (!name.isEmpty() || !author.isEmpty() || !info.isEmpty()) {
604 sb.append("\n\t(documentation \"");
605 sb.append(name.replace("\"", ""));
606 sb.append("\" \"");
607 sb.append(author.replace("\"", ""));
608 sb.append("\" \"");
609 sb.append(info.replace("\"", ""));
610 sb.append("\")\n");
611 }
612 for (Competence node : cs) {
613 sb.append('\n');
614 sb.append(node.toString());
615 }
616 for (ActionPattern node : this.aps) {
617 sb.append('\n');
618 sb.append(node.toString());
619 }
620 sb.append('\n');
621 sb.append(dc.toString());
622 sb.append("\n)");
623
624 return sb.toString();
625 }
626
627 @Override
628 public List<PoshElement> getChildDataNodes() {
629 List<PoshElement> children = new ArrayList<PoshElement>();
630
631 children.addAll(cs);
632 children.addAll(aps);
633 children.addAll(ads);
634 children.add(dc);
635
636 return children;
637 }
638
639 @Override
640 public boolean moveChild(int newIndex, PoshElement child) {
641 throw new UnsupportedOperationException();
642
643
644
645
646
647
648
649 }
650
651 @Override
652 public DataFlavor getDataFlavor() {
653 return dataFlavor;
654 }
655
656 @Override
657 public LapType getType() {
658 return LapType.PLAN;
659 }
660
661
662
663
664
665
666
667 public void removeCompetence(Competence removeCompetence) {
668 assert csUm.contains(removeCompetence);
669
670 int removedCIndex = csUm.indexOf(removeCompetence);
671
672 cs.remove(removeCompetence);
673 removeCompetence.setParent(null);
674
675 emitChildDeleted(removeCompetence, removedCIndex);
676 }
677
678
679
680
681
682
683
684 public void removeActionPattern(ActionPattern ap) {
685 assert apsUm.contains(ap);
686
687 int removedAPIndex = apsUm.indexOf(ap);
688
689 aps.remove(ap);
690 ap.setParent(null);
691
692 emitChildDeleted(ap, removedAPIndex);
693 }
694
695
696
697
698
699
700
701
702 public void synchronize(PoshPlan other) {
703
704 ActionPattern[] apArray = aps.toArray(new ActionPattern[aps.size()]);
705 for (ActionPattern ap : apArray) {
706 removeActionPattern(ap);
707 }
708 Competence[] compArray = cs.toArray(new Competence[cs.size()]);
709 for (Competence c : compArray) {
710 removeCompetence(c);
711 }
712 Sense[] goalSenses = dc.getGoal().toArray(new Sense[0]);
713 for (Sense goalSense : goalSenses) {
714 dc.getGoal().remove(goalSense);
715 }
716
717
718
719 try {
720
721
722
723
724 DriveElement[] originalDrives = dc.getDrives().toArray(new DriveElement[0]);
725 List<DriveElement> allDrives = new ArrayList<DriveElement>();
726 allDrives.addAll(dc.getDrives());
727 allDrives.addAll(other.dc.getDrives());
728
729 String syncDriveName = getUnusedName("temporaryDriveSyncName", allDrives);
730 DriveElement syncDrive = LapElementsFactory.createDriveElementNoTriggers(syncDriveName);
731 dc.addDrive(syncDrive);
732
733 for (DriveElement drive : originalDrives) {
734 dc.removeDrive(drive);
735 }
736
737
738 for (DriveElement drive : other.dc.getDrives()) {
739 dc.addDrive(LapElementsFactory.createDriveElement(drive));
740 }
741
742 dc.removeDrive(syncDrive);
743
744 for (ActionPattern ap : other.apsUm) {
745 addActionPattern(LapElementsFactory.createActionPattern(ap));
746 }
747 for (Competence c : other.csUm) {
748 addCompetence(LapElementsFactory.createCompetence(c));
749 }
750 for (Sense oGoalSense : other.dc.getGoal()) {
751 dc.getGoal().add(LapElementsFactory.createSense(oGoalSense));
752 }
753 } catch (DuplicateNameException ex) {
754 throw new FubarException("Original tree should be correct thus new one should be too.", ex);
755 } catch (CycleException ex) {
756 throw new FubarException("Original tree should be correct thus new one should be too.", ex);
757 }
758 }
759
760
761
762
763
764
765
766
767 public int getAdoptId(Adopt adopt) {
768 return getElementId(adsUm, adopt);
769 }
770
771
772
773
774
775
776
777 public int getActionPatternId(ActionPattern actionPattern) {
778 return getElementId(apsUm, actionPattern);
779 }
780
781
782
783
784
785
786
787
788 public int getCompetenceId(Competence competence) {
789 return getElementId(csUm, competence);
790 }
791
792 }