source: trunk/autoquest-core-tasktrees/src/main/java/de/ugoe/cs/autoquest/tasktrees/temporalrelation/CondenseSimilarTasksRule.java @ 1973

Last change on this file since 1973 was 1973, checked in by pharms, 9 years ago
  • again two smaller bugfixes in task merging
File size: 82.7 KB
Line 
1//   Copyright 2012 Georg-August-Universität Göttingen, Germany
2//
3//   Licensed under the Apache License, Version 2.0 (the "License");
4//   you may not use this file except in compliance with the License.
5//   You may obtain a copy of the License at
6//
7//       http://www.apache.org/licenses/LICENSE-2.0
8//
9//   Unless required by applicable law or agreed to in writing, software
10//   distributed under the License is distributed on an "AS IS" BASIS,
11//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12//   See the License for the specific language governing permissions and
13//   limitations under the License.
14
15package de.ugoe.cs.autoquest.tasktrees.temporalrelation;
16
17import java.util.ArrayList;
18import java.util.Collection;
19import java.util.HashMap;
20import java.util.Iterator;
21import java.util.LinkedList;
22import java.util.List;
23import java.util.Map;
24
25import de.ugoe.cs.autoquest.tasktrees.taskequality.TaskEquality;
26import de.ugoe.cs.autoquest.tasktrees.temporalrelation.utils.MostSimilarTaskDeterminer;
27import de.ugoe.cs.autoquest.tasktrees.temporalrelation.utils.SimilarTasks;
28import de.ugoe.cs.autoquest.tasktrees.temporalrelation.utils.TaskTraversal;
29import de.ugoe.cs.autoquest.tasktrees.treeifc.DefaultTaskInstanceTraversingVisitor;
30import de.ugoe.cs.autoquest.tasktrees.treeifc.IIteration;
31import de.ugoe.cs.autoquest.tasktrees.treeifc.IIterationInstance;
32import de.ugoe.cs.autoquest.tasktrees.treeifc.IMarkingTemporalRelationship;
33import de.ugoe.cs.autoquest.tasktrees.treeifc.IOptional;
34import de.ugoe.cs.autoquest.tasktrees.treeifc.IOptionalInstance;
35import de.ugoe.cs.autoquest.tasktrees.treeifc.ISelection;
36import de.ugoe.cs.autoquest.tasktrees.treeifc.ISelectionInstance;
37import de.ugoe.cs.autoquest.tasktrees.treeifc.ISequence;
38import de.ugoe.cs.autoquest.tasktrees.treeifc.ISequenceInstance;
39import de.ugoe.cs.autoquest.tasktrees.treeifc.ITask;
40import de.ugoe.cs.autoquest.tasktrees.treeifc.ITaskBuilder;
41import de.ugoe.cs.autoquest.tasktrees.treeifc.ITaskFactory;
42import de.ugoe.cs.autoquest.tasktrees.treeifc.ITaskInstance;
43import de.ugoe.cs.autoquest.tasktrees.treeifc.ITaskInstanceList;
44import de.ugoe.cs.autoquest.tasktrees.treeifc.ITaskModel;
45import de.ugoe.cs.autoquest.tasktrees.treeifc.IUserSession;
46import de.ugoe.cs.autoquest.tasktrees.treeifc.TaskPath;
47import de.ugoe.cs.util.console.Console;
48import difflib.Chunk;
49import difflib.Delta;
50
51/**
52 * <p>
53 * This rule performs a condensing of a task tree. It searches for similar tasks and merges them
54 * if possible in to one task with different execution variants. Hence, this rule detects selections
55 * and optionals.
56 * </p>
57 * <p>
58 * The similarity of tasks is determined by comparing task traversals. A task traversal is an
59 * ordered list of the leaf nodes of a task. This is similar to performing a minimal execution of
60 * the task. The task traversals of two tasks are compared using string comparison algorithms. The
61 * less differences the lists have, the more similar they are.
62 * </p>
63 * <p>
64 * If two tasks are similar, they are merged. Merging is done based on the differences between
65 * the task traversals. Two tasks are merged based on their instances. First, all instances of both
66 * tasks are flattened. Instances of selections or commonalities of both tasks stay unflattened.
67 * Then the lists resulting from this flattening are extended with instances of optionals and
68 * selections which are introduced where required. Finally, the instances are put together to a
69 * single task again by applying the {@link SequenceForTaskDetectionRule} on them.
70 * </p>
71 * <p>
72 * Merging has to consider several specific situations. E.g., tasks may look similar but due to
73 * iterations, they can not be merged correctly. Here, the rule ensures, that these so called
74 * interleaving iterations are detected, not traversed when traversing a task and its instances,
75 * and, therefore, preserved.
76 * </p>
77 * <p>
78 * All details about this rule are described in the extended ACHI2014 paper of Harms "Trace-based
79 * task tree generation". The extended paper was submitted to the IntSys IARIA Journal.
80 * </p>
81 *
82 * @author Patrick Harms
83 */
84class CondenseSimilarTasksRule implements ISessionScopeRule {
85
86    /**
87     * <p>
88     * the task factory to be used for creating substructures for the temporal
89     * relationships identified during rule application
90     * </p>
91     */
92    private ITaskFactory taskFactory;
93    /**
94     * <p>
95     * the task builder to be used for creating substructures for the temporal relationships
96     * identified during rule application
97     * </p>
98     */
99    private ITaskBuilder taskBuilder;
100
101    /**
102     * <p>
103     * the task handling strategy to be used for comparing tasks during iteration detection an trie
104     * generation, i.e., after the tasks are harmonized
105     * </p>
106     */
107    private TaskHandlingStrategy identTaskHandlStrat;
108   
109    /**
110     * <p>
111     * instantiates the rule and initializes it with a task equality to be considered when
112     * comparing tasks as well as a task factory and builder to be used for creating task
113     * structures.
114     * </p>
115     *
116     * @param minimalTaskEquality the task equality to be considered when comparing tasks
117     * @param taskFactory         the task factory to be used for creating substructures
118     * @param taskBuilder         the task builder to be used for creating substructures
119     */
120    CondenseSimilarTasksRule(TaskEquality minimalTaskEquality,
121                             ITaskFactory taskFactory,
122                             ITaskBuilder taskBuilder)
123    {
124        this.taskFactory = taskFactory;
125        this.taskBuilder = taskBuilder;
126       
127        this.identTaskHandlStrat = new TaskHandlingStrategy(TaskEquality.IDENTICAL);
128    }
129
130    /* (non-Javadoc)
131     * @see java.lang.Object#toString()
132     */
133    @Override
134    public String toString() {
135        return "CondenseSimilarTasksRule";
136    }
137
138    /* (non-Javadoc)
139     * @see de.ugoe.cs.autoquest.tasktrees.temporalrelation.ISessionScopeRule#apply(java.util.List)
140     */
141    @Override
142    public RuleApplicationResult apply(List<IUserSession> sessions) {
143       
144        // >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
145        // >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> TEST IMPLEMENTATION >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
146        /*final List<IEventTaskInstance> formerInstances = new ArrayList<>();
147        final List<IEventTaskInstance> newInstances = new ArrayList<>();
148       
149        try {
150            ITaskInstanceVisitor visitor = new DefaultTaskInstanceTraversingVisitor() {
151                @Override
152                public void visit(IEventTaskInstance eventTaskInstance) {
153                    formerInstances.add(eventTaskInstance);
154                }
155            };
156           
157            PrintStream out = new PrintStream(new FileOutputStream(new File("01.out")));
158           
159            for (IUserSession session : sessions) {
160                new TaskTreeEncoder().encode(session, out, null);
161               
162                for (ITaskInstance instance : session) {
163                    instance.accept(visitor);
164                }
165            }
166            out.close();
167        }
168        catch (FileNotFoundException e) {
169            e.printStackTrace();
170        }
171       
172        PrintStream fileout = null;
173        try {
174            fileout = new PrintStream("sysout.txt");
175        }
176        catch (FileNotFoundException e1) {
177            e1.printStackTrace();
178        }
179       
180        PrintStream origOut = System.out;
181        if (fileout != null) {
182            System.setOut(fileout);
183        }*/
184       
185        // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
186        // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< TEST IMPLEMENTATION <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
187       
188       
189        RuleApplicationData appData = new RuleApplicationData(sessions);
190       
191        do {
192            appData.setTaskModel(taskFactory.createTaskModel(sessions));
193            appData.setMostSimilarTasks(null);
194           
195            // >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
196            // >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> TEST IMPLEMENTATION >>>>>>>>>>>>>>>>>>>>>
197            // for (ITask task : appData.getTaskModel().getTasks()) {
198            //     if (task.getInstances().size() <= 0) {
199            //         throw new RuntimeException("task " + task + " has no instances anymore");
200            //     }
201            //     
202            //     try {
203            //         new TaskTreeValidator().validate(task);
204            //     }
205            //     catch (Exception e) {
206            //         new TaskTreeEncoder().encode(task, System.err);
207            //     }
208            // }
209            //
210            // new TaskTreeValidator().validate(sessions);
211           
212            // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
213            // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< TEST IMPLEMENTATION <<<<<<<<<<<<<<<<<<<<<<
214
215
216            Console.println("condensing " + appData.getTaskModel().getTasks().size() + " tasks");
217
218            getMostSimilarTasks(appData);
219
220            if (appData.getMostSimilarTasks() != null) {
221                for (SimilarTasks mostSimilarTask : appData.getMostSimilarTasks()) {
222                    handleSimilarTasks(mostSimilarTask, appData);
223                    appData.markAsAlreadyCondensed
224                        (mostSimilarTask.getLeftHandSide(), mostSimilarTask.getRightHandSide());
225                }
226            }
227           
228            harmonizeMarkingTemporalRelationships(sessions);
229        }
230        while (appData.getMostSimilarTasks() != null);
231       
232       
233        // >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
234        // >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> TEST IMPLEMENTATION >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
235        /*try {
236            ITaskInstanceVisitor visitor = new DefaultTaskInstanceTraversingVisitor() {
237                @Override
238                public void visit(IEventTaskInstance eventTaskInstance) {
239                    newInstances.add(eventTaskInstance);
240                }
241            };
242           
243            PrintStream out = new PrintStream(new FileOutputStream(new File("02.out")));
244           
245            for (IUserSession session : sessions) {
246                new TaskTreeEncoder().encode(session, out, null);
247               
248                for (ITaskInstance instance : session) {
249                    instance.accept(visitor);
250                }
251            }
252            out.close();
253        }
254        catch (FileNotFoundException e) {
255            e.printStackTrace();
256        }
257       
258        System.out.println("sizes  " + formerInstances.size() + "  " + newInstances.size());
259        for (int i = 0; i < newInstances.size(); i++) {
260            if (formerInstances.get(i) != newInstances.get(i)) {
261                System.out.println(i + "  " + formerInstances.get(i) + "  " + newInstances.get(i));
262            }
263        }
264       
265        System.setOut(origOut);
266        fileout.close();*/
267        // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
268        // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< TEST IMPLEMENTATION <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
269
270       
271        return appData.finalizeRuleApplicationResult();
272    }
273
274    /**
275     *
276     */
277    private void harmonizeMarkingTemporalRelationships(List<IUserSession> sessions) {
278        final Map<ITask, IIteration> harmonizedIterations = new HashMap<>();
279        final Map<ITask, IOptional> harmonizedOptionals = new HashMap<>();
280       
281        for (IUserSession session : sessions) {
282            for (ITaskInstance instance : session) {
283                instance.accept(new DefaultTaskInstanceTraversingVisitor() {
284                   
285                    @Override
286                    public void visit(IIterationInstance iterationInstance) {
287                        // visit the children
288                        super.visit(iterationInstance);
289                       
290                        // there may have been a model update at the children. If so, set the
291                        // new marked task
292                        IIteration iteration = iterationInstance.getIteration();
293                        ITask newChildTask = iterationInstance.get(0).getTask();
294                       
295                        if (newChildTask != iteration.getMarkedTask()) {
296                            taskBuilder.setMarkedTask(iteration, newChildTask);
297                        }
298                       
299                        // check, if there is a harmonized iteration
300                        IIteration harmonizedIteration =
301                            harmonizedIterations.get(iteration.getMarkedTask());
302                       
303                        if ((harmonizedIteration != null) && (iteration != harmonizedIteration)) {
304                            // there is a harmonized iteration --> set it as new task
305                            /*System.out.println("harmonizing iteration of " +
306                                               iteration.getMarkedTask() + " from " + iteration +
307                                               " to " + harmonizedIteration);*/
308                            taskBuilder.setTask(iterationInstance, harmonizedIteration);
309                        }
310                        else if (harmonizedIteration == null) {
311                            // remember this iteration as the harmonized one
312                            harmonizedIterations.put(iteration.getMarkedTask(), iteration);
313                        }
314                    }
315                   
316                    @Override
317                    public void visit(IOptionalInstance optionalInstance) {
318                        // visit the children
319                        super.visit(optionalInstance);
320                       
321                        if (optionalInstance.getChild() == null) {
322                            return;
323                        }
324                       
325                        // there may have been a model update at the child. If so, set the
326                        // new marked task
327                        IOptional optional = optionalInstance.getOptional();
328                        ITask newChildTask = optionalInstance.getChild().getTask();
329                       
330                        if (newChildTask != optional.getMarkedTask()) {
331                            taskBuilder.setMarkedTask(optional, newChildTask);
332                        }
333                       
334                        // check, if there is a harmonized optional
335                        IOptional harmonizedOptional =
336                            harmonizedOptionals.get(optional.getMarkedTask());
337                       
338                        if ((harmonizedOptional != null) && (optional != harmonizedOptional)) {
339                            // there is a harmonized optional --> set it as new task
340                            /*System.out.println("harmonizing optional of " +
341                                               optional.getMarkedTask() + " from " + optional +
342                                               " to " + harmonizedOptional);*/
343                            taskBuilder.setTask(optionalInstance, harmonizedOptional);
344                        }
345                        else if (harmonizedOptional == null) {
346                            // remember this optional as the harmonized one
347                            harmonizedOptionals.put(optional.getMarkedTask(), optional);
348                        }
349                    }
350
351                    @Override
352                    public void visit(ISelectionInstance selectionInstance) {
353                        ITask childTaskBeforeUpdate = selectionInstance.getChild().getTask();
354                       
355                        super.visit(selectionInstance);
356                       
357                        ITask childTaskAfterUpdate = selectionInstance.getChild().getTask();
358                       
359                        if (childTaskBeforeUpdate != childTaskAfterUpdate) {
360                            // update the selection model if required.
361                            ISelection selection = selectionInstance.getSelection();
362                           
363                            boolean foundOtherInstanceWithOldChild = false;
364                           
365                            for (ITaskInstance instance : selection.getInstances()) {
366                                ITask child = ((ISelectionInstance) instance).getChild().getTask();
367                               
368                                if (child == childTaskBeforeUpdate) {
369                                    foundOtherInstanceWithOldChild = true;
370                                    break;
371                                }
372                            }
373                           
374                            if (!foundOtherInstanceWithOldChild) {
375                                taskBuilder.removeChild(selection, childTaskBeforeUpdate);
376                            }
377                           
378                            // remove and add the child to ensure to have it only once
379                            taskBuilder.removeChild(selection, childTaskAfterUpdate);
380                            taskBuilder.addChild(selection, childTaskAfterUpdate);
381                        }
382                    }
383
384                    @Override
385                    public void visit(ISequenceInstance sequenceInstance) {
386                        ISequence sequence = sequenceInstance.getSequence();
387                        int childIndex = 0;
388                       
389                        for (ITaskInstance child : sequenceInstance) {
390                            child.accept(this);
391                           
392                            ITask newChildTask = child.getTask();
393                           
394                            if (sequence.getChildren().get(childIndex) != newChildTask) {
395                                taskBuilder.setChild(sequenceInstance.getSequence(), childIndex,
396                                                     newChildTask);
397                            }
398                           
399                            childIndex++;
400                        }
401                    }
402                   
403                });
404
405            }
406           
407            // several subsequent instances, which had formerly different tasks, may now have
408            // the same. Hence, they need to be merged. But as everything else would be way too
409            // complex, we only perform the merge, if they occur next to each other on the
410            // same level
411            mergeSubsequentIdenticalMarkingTemporalRelationships(session);
412        }
413    }
414
415    /**
416     *
417     */
418    private void getMostSimilarTasks(RuleApplicationData appData) {
419        // determine the list of interesting tasks
420        Collection<ITask> allTasks = appData.getTaskModel().getTasks();
421        Iterator<ITask> taskIterator = allTasks.iterator();
422        List<ITask> taskList = new ArrayList<ITask>(allTasks.size());
423       
424        while (taskIterator.hasNext()) {
425            ITask task = taskIterator.next();
426           
427            // only Sequences need to be compared with each other. Iterations differ only in their
428            // child, i.e., in the child sequences.
429            if (task instanceof ISequence) {
430                taskList.add(task);
431            }
432        }
433       
434        if (taskList.size() > 1) {
435            List<SimilarTasks> mostSimilarTasks =
436                appData.getMostSimilarTasksDeterminer().getMostSimilarTasks
437                    (taskList, appData.getTaskModel());
438           
439            if (mostSimilarTasks.size() > 0) {
440                appData.setMostSimilarTasks(mostSimilarTasks);
441            }
442        }
443    }
444
445    /**
446     *
447     */
448    private void handleSimilarTasks(SimilarTasks similarTasks, RuleApplicationData appData) {
449        // we need at least one instance per similar task. If not, it will not work and also
450        // does not make sense. No instances anymore can be caused by merging and hence
451        // discarding tasks in preceding merges.
452       
453        // similarTasks.dump(System.out);
454       
455        if ((similarTasks.getLeftHandSide().getInstances().size() <= 0) ||
456            (similarTasks.getRightHandSide().getInstances().size() <= 0))
457        {
458            /*System.out.println("a task exists that has no instances");
459            System.out.println(similarTasks.getLeftHandSide() + "  " +
460                               similarTasks.getLeftHandSide().getInstances().size());
461            System.out.println(similarTasks.getRightHandSide() + "  " +
462                               similarTasks.getRightHandSide().getInstances().size());*/
463           
464            throw new RuntimeException
465                ("one and the same task seems to belong to several similar tasks");
466        }
467       
468        similarTasks = SimilarTasks.getMergableLevelOfSimilarity
469            (similarTasks, identTaskHandlStrat.getTaskComparator());
470       
471        if (similarTasks == null) {
472            // this may happen, if no mergable level of similarity can be found
473            return;
474        }
475       
476        // similarTasks.dump(System.out);
477
478        List<FlattenInstruction> flattenInstructions =
479            getFlattenInstructions(similarTasks, appData);
480       
481        // for (FlattenInstruction instruction : flattenInstructions) {
482        //     instruction.dump(System.out);
483        // }
484       
485        int noOfFlattenedInstances = similarTasks.getLeftHandSide().getInstances().size() +
486            similarTasks.getRightHandSide().getInstances().size();
487       
488        // >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
489        // >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> TEST IMPLEMENTATION >>>>>>>>>>>>>>>>>>>>>>>>>>>>>
490        List<TaskPath> excludes = new ArrayList<TaskPath>();
491       
492        for (FlattenInstruction instruction : flattenInstructions) {
493            //System.out.println("exclude " + instruction.path);
494            excludes.add(instruction.path);
495        }
496        // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
497        // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< TEST IMPLEMENTATION <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
498
499        Map<ITaskInstance, IUserSession> flattenedSessions =
500            new HashMap<ITaskInstance, IUserSession>(noOfFlattenedInstances);
501        flattenInstances
502            (similarTasks.getLeftHandSide(), flattenInstructions, flattenedSessions, excludes);
503        flattenInstances
504            (similarTasks.getRightHandSide(), flattenInstructions, flattenedSessions, excludes);
505
506        // >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
507        // >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> TEST IMPLEMENTATION >>>>>>>>>>>>>>>>>>>>>>>>>>>>>
508        /*for (IUserSession session : flattenedSessions.values()) {
509            System.out.println("user session {");
510           
511            for (ITaskInstance instance : session) {
512                System.out.println(instance);
513            }
514           
515            System.out.println("}");
516        }*/
517        // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
518        // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< TEST IMPLEMENTATION <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
519       
520        List<IUserSession> flattenedSessionList =
521            new LinkedList<IUserSession>(flattenedSessions.values());
522       
523        new SequenceForTaskDetectionRule
524            (TaskEquality.IDENTICAL, taskFactory, taskBuilder).apply(flattenedSessionList);
525       
526        Map<ITaskInstance, ITaskInstance> replacements = new HashMap<ITaskInstance, ITaskInstance>();
527        ITask replacementTask = null;
528       
529        for (Map.Entry<ITaskInstance, IUserSession> entry : flattenedSessions.entrySet()) {
530            // >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
531            // >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> TEST IMPLEMENTATION >>>>>>>>>>>>>>>>>>>>>>>>>>>>>
532            // the user sessions were sufficiently equal to have now only one common task as child
533           
534            if (entry.getValue().size() != 1) {
535                //new TaskTreeEncoder().encode(entry.getValue(), System.out, excludes);
536                throw new RuntimeException("flattened sessions were not combined as expected");
537            }
538           
539            if (replacementTask == null) {
540                replacementTask = entry.getValue().get(0).getTask();
541            }
542            else if (replacementTask != entry.getValue().get(0).getTask()) {
543                throw new RuntimeException("two separate replacement tasks were calculated as " +
544                                           "replacement, one for both tasks to be merged");
545            }
546           
547            // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
548            // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< TEST IMPLEMENTATION <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
549           
550            replacements.put(entry.getKey(), entry.getValue().get(0));
551        }
552       
553        // >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
554        // >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> TEST IMPLEMENTATION >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
555        // ((Task) replacementTask).setDescription
556        //     (replacementTask + " calculated as full replacement for " +
557        //      similarTasks.getLeftHandSide() + " and " + similarTasks.getRightHandSide());
558   
559        int allInstances = similarTasks.getLeftHandSide().getInstances().size() +
560            similarTasks.getRightHandSide().getInstances().size();
561       
562        if (replacements.size() != allInstances) {
563            throw new RuntimeException("number of replacements does not match number of instances");
564        }
565       
566        /*if (replacements.size() > 0) {
567            System.out.println("replacement task is calculated to be: ");
568            new TaskTreeEncoder().encode(replacements.values().iterator().next().getTask(),
569                                         System.out);
570        }*/
571       
572        // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
573        // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< TEST IMPLEMENTATION <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
574
575
576        for (IUserSession session : appData.getSessions()) {
577            replaceTaskInstances(session, replacements, similarTasks);
578        }
579       
580       
581        // >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
582        // >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> TEST IMPLEMENTATION >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
583        if (replacements.size() != 0) {
584            for (Map.Entry<ITaskInstance, ITaskInstance> entry : replacements.entrySet()) {
585                System.out.println
586                    ("did not replace instance " + entry.getKey() + " with " + entry.getValue());
587            }
588           
589            throw new RuntimeException();
590        }
591        // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
592        // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< TEST IMPLEMENTATION <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
593    }
594
595    /**
596     *
597     */
598    private List<FlattenInstruction> getFlattenInstructions(SimilarTasks        similarTasks,
599                                                            RuleApplicationData appData)
600    {
601        TaskTraversal leftHandSideTraversal = similarTasks.getLeftHandSideTraversal();
602        TaskTraversal rightHandSideTraversal = similarTasks.getRightHandSideTraversal();
603       
604        List<FlattenInstruction> result = new LinkedList<FlattenInstruction>();
605        TaskComparator comp = identTaskHandlStrat.getTaskComparator();
606       
607        // first create instructions for the deltas
608        for (Delta delta : similarTasks.getPatch().getDeltas()) {
609            if ((delta.getType() == Delta.TYPE.INSERT) ||
610                (delta.getType() == Delta.TYPE.DELETE))
611            {
612                // System.out.println("handling " + delta.getType());
613                Chunk chunk;
614                TaskPath insertAfterPath = null;
615                TaskPath insertBeforePath;
616               
617                if (delta.getType() == Delta.TYPE.INSERT) {
618                    chunk = delta.getRevised();
619                    int pos = delta.getOriginal().getPosition();
620                    // System.out.println(" position " + pos);
621                   
622                    if (pos > 0) {
623                        insertAfterPath = leftHandSideTraversal.getTraversalPaths()[pos - 1];
624                    }
625                    insertBeforePath = leftHandSideTraversal.getTraversalPaths()[pos];
626                }
627                else {
628                    chunk = delta.getOriginal();
629                    int pos = delta.getRevised().getPosition();
630                    if (pos > 0) {
631                        insertAfterPath = rightHandSideTraversal.getTraversalPaths()[pos - 1];
632                    }
633                    insertBeforePath = rightHandSideTraversal.getTraversalPaths()[pos];
634                }
635               
636                ITask child = getTaskForChunk(chunk, appData);
637                IOptional optional;
638               
639                if (child instanceof IOptional) {
640                    optional = (IOptional) child;
641                }
642                else {
643                    optional = taskFactory.createNewOptional();
644                    taskBuilder.setMarkedTask(optional, child);
645                    // ((Task) optional).setDescription(optional.getDescription() +
646                    //                                  " created for " + delta.getType());
647                    optional = (IOptional) appData.ensureUnique(optional);
648                    createReplacementInstructions(chunk, optional, null, result);
649                }
650
651                // create a flatten instruction for the non-occurrence of the optional
652                result.add(new FlattenInstruction(insertAfterPath, insertBeforePath, optional));
653               
654            }
655            else if (delta.getType() == Delta.TYPE.CHANGE) {
656                ITask child1;
657                ITask child2;
658               
659                // check, if the change covers the whole traversal. If so reuse the root task.
660                // Otherwise, create intermediate tasks if required representing both sides
661                // of changes
662                if ((delta.getOriginal().getPosition() == 0) &&
663                    (delta.getOriginal().size() == similarTasks.getLeftHandSideTraversal().size()))
664                {
665                    child1 = similarTasks.getLeftHandSide();
666                }
667                else {
668                    child1 = getTaskForChunk(delta.getOriginal(), appData);
669                }
670               
671                if ((delta.getRevised().getPosition() == 0) &&
672                    (delta.getRevised().size() == similarTasks.getRightHandSideTraversal().size()))
673                {
674                    child2 = similarTasks.getRightHandSide();
675                }
676                else {
677                    child2 = getTaskForChunk(delta.getRevised(), appData);
678                }
679               
680                // check if either of the variants is an iteration or optional of the respective
681                // other variant. If so, ensure, that the iteration or optional are preserved
682                ITask markedTask1 = (child1 instanceof IMarkingTemporalRelationship) ?
683                    ((IMarkingTemporalRelationship) child1).getMarkedTask() : null;
684               
685                ITask markedTask2 = (child2 instanceof IMarkingTemporalRelationship) ?
686                    ((IMarkingTemporalRelationship) child2).getMarkedTask() : null;
687               
688                if (comp.equals(markedTask1, child2)) {
689                    if (child1 instanceof IOptional) {
690                        createReplacementInstructions
691                            (delta.getRevised(), (IOptional) child1, null, result);
692                    }
693                    else {
694                        throw new java.lang.UnsupportedOperationException("not implemented yet");
695                    }
696                }
697                else if (comp.equals(markedTask2, child1)) {
698                    if (child2 instanceof IOptional) {
699                        createReplacementInstructions
700                            (delta.getOriginal(), (IOptional) child2, null, result);
701                    }
702                    else {
703                        throw new java.lang.UnsupportedOperationException("not implemented yet");
704                    }
705                }
706                else if ((markedTask1 != null) && (comp.equals(markedTask1, markedTask2))) {
707                    throw new java.lang.UnsupportedOperationException("not implemented yet");
708                }
709                else {
710                    // its time to create a selection of both variants. If one is already
711                    // a selection, it is reused and extended, if required.
712                   
713                    ITask expectedChild1 = null;
714                    ITask expectedChild2 = null;
715                   
716                    ISelection selection = null;
717                    if (child1 instanceof ISelection) {
718                        selection = (ISelection) child1;
719                    }
720               
721                    if (child2 instanceof ISelection) {
722                        if (selection == null) {
723                            // only child 2 is a selection --> extend it with child 1
724                            selection = (ISelection) child2;
725                            addSelectionChildIfRequired(selection, child1);
726                            expectedChild1 = child1;
727                        }
728                        else {
729                            // both are selections --> extend child 1 with variants of child2
730                            for (ITask child : ((ISelection) child2).getChildren()) {
731                                addSelectionChildIfRequired(selection, child);
732                            }
733                        }
734                    }
735                    else if (selection != null) {
736                        // only child 1 is a selection --> extend it with child 2
737                        addSelectionChildIfRequired(selection, child2);
738                        expectedChild2 = child2;
739                    }
740                    else if (selection == null) {
741                        // it may also be the case, that one is a child of a selection and occurs
742                        // only as such and nowhere else. Then the parent selection is reused and
743                        // extended.
744                        for (ITask candidate : appData.taskModel.getTasks()) {
745                            if (candidate instanceof ISelection) {
746                                selection = (ISelection) candidate;
747                                ITask existingChildTask = null;
748                               
749                                if (selection.getChildren().contains(child1)) {
750                                    existingChildTask = child1;
751                                }
752                                else if (selection.getChildren().contains(child2)) {
753                                    existingChildTask = child2;
754                               }
755                               
756                                if (existingChildTask != null) {
757                                    int noOfInstances = 0;
758                                   
759                                    for (ITaskInstance instance : selection.getInstances()) {
760                                        ITaskInstance childInstance =
761                                            ((ISelectionInstance) instance).getChild();
762                                           
763                                        if (childInstance.getTask() == existingChildTask) {
764                                            noOfInstances++;
765                                        }
766                                    }
767                                   
768                                    if (noOfInstances < existingChildTask.getInstances().size()) {
769                                        // not all instances of the existing child task are covered
770                                        // by the parent selection. Hence, throw selection away and
771                                        // search for another one
772                                        selection = null;
773                                    }
774                                    else {
775                                        // found a parent selection --> reuse it but add the new
776                                        // variant
777                                        if (child1 == existingChildTask) {
778                                            addSelectionChildIfRequired(selection, child2);
779                                        }
780                                        else {
781                                            addSelectionChildIfRequired(selection, child1);
782                                        }
783                                        expectedChild1 = child1;
784                                        expectedChild2 = child2;
785                                        break;
786                                    }
787                                }
788                                else {
789                                    selection = null;
790                                }
791                            }
792                        }
793                       
794                        if (selection == null) {
795                            // none of both is already a selection, so create a new one with both
796                            // of the children as variants
797                            selection = taskFactory.createNewSelection();
798                            // ((Task) selection).setDescription(selection.getDescription() +
799                            //                                   " created for " + delta.getType());
800                            taskBuilder.addChild(selection, child1);
801                            taskBuilder.addChild(selection, child2);
802                            expectedChild1 = child1;
803                            expectedChild2 = child2;
804                        }
805                    }
806
807                    selection = (ISelection) appData.ensureUnique(selection);
808               
809                    createReplacementInstructions
810                        (delta.getOriginal(), selection, expectedChild1, result);
811                    createReplacementInstructions
812                        (delta.getRevised(), selection, expectedChild2, result);
813                }
814            }
815        }
816       
817        // create instructions to harmonize marking temporal relationships for untraversed tasks
818        int leftHandSideIndex = 0;
819        int rightHandSideIndex = 0;
820       
821        OUTER:
822        while (leftHandSideIndex < leftHandSideTraversal.getTraversalPaths().length) {
823            for (Delta delta : similarTasks.getPatch().getDeltas()) {
824                if (delta.getOriginal().getPosition() == leftHandSideIndex) {
825                    if (delta.getType() == Delta.TYPE.INSERT) {
826                        rightHandSideIndex += delta.getRevised().size();
827                        // do not continue OUTER to ensure, that the left hand side and the
828                        // right hand side coming directly after the insert are handled
829                    }
830                    else if (delta.getType() == Delta.TYPE.DELETE) {
831                        leftHandSideIndex += delta.getOriginal().size();
832                        continue OUTER;
833                    }
834                    else if (delta.getType() == Delta.TYPE.CHANGE) {
835                        leftHandSideIndex += delta.getOriginal().size();
836                        rightHandSideIndex += delta.getRevised().size();
837                        continue OUTER;
838                    }
839                }
840            }
841           
842            TaskPath leftPath = leftHandSideTraversal.getTraversalPaths()[leftHandSideIndex];
843            TaskPath rightPath = rightHandSideTraversal.getTraversalPaths()[rightHandSideIndex];
844           
845            if (comp.equals(leftPath.getLast(), rightPath.getLast())) {
846                if (leftPath.getTask(leftPath.size() - 2) instanceof IOptional) {
847                    IOptional optional = (IOptional) leftPath.getTask(leftPath.size() - 2);
848                    result.add
849                        (new FlattenInstruction(leftPath.subPath(0, leftPath.size()), optional));
850
851                    result.add(new FlattenInstruction(rightPath, optional));
852                }
853                else if (rightPath.getTask(rightPath.size() - 2) instanceof IOptional) {
854                    IOptional optional = (IOptional) rightPath.getTask(rightPath.size() - 2);
855                    result.add
856                        (new FlattenInstruction(rightPath.subPath(0, rightPath.size()), optional));
857
858                    result.add(new FlattenInstruction(leftPath, optional));
859                }
860            }
861           
862            leftHandSideIndex++;
863            rightHandSideIndex++;
864        }
865       
866       
867        // then create instructions for what stays the same
868        OUTER:
869        for (TaskPath path : leftHandSideTraversal.getTraversalPaths()) {
870            for (FlattenInstruction instruction : result) {
871                if (instruction.matches(path)) {
872                    continue OUTER;
873                }
874            }
875           
876            result.add(new FlattenInstruction(path));
877        }
878
879        OUTER:
880        for (TaskPath path : rightHandSideTraversal.getTraversalPaths()) {
881            for (FlattenInstruction instruction : result) {
882                if (instruction.matches(path)) {
883                    continue OUTER;
884                }
885            }
886           
887            result.add(new FlattenInstruction(path));
888        }
889
890        return result;
891    }
892
893    /**
894     *
895     */
896    private void addSelectionChildIfRequired(ISelection selection, ITask child) {
897        for (ITask candidate : selection.getChildren()) {
898            if (identTaskHandlStrat.getTaskComparator().equals(candidate, child)) {
899                return;
900            }
901        }
902       
903        taskBuilder.addChild(selection, child);
904    }
905
906    /**
907     *
908     */
909    private ITask getTaskForChunk(Chunk chunk, RuleApplicationData appData) {
910        if (chunk.size() == 1) {
911            TaskPath path = (TaskPath) chunk.getLines().get(0);
912            return path.getTask(path.size() - 1);
913        }
914        else {
915            ISequence task = taskFactory.createNewSequence();
916            // ((Task) task).setDescription(task.getDescription() +
917            //                              " created to represent a chunk");
918
919            for (Object pathObj : chunk.getLines()) {
920                TaskPath path = (TaskPath) pathObj;
921                taskBuilder.addChild(task, path.getLast());
922            }
923           
924            return appData.ensureUnique(task);
925        }
926    }
927
928    /**
929     *
930     */
931    private void createReplacementInstructions(Chunk                    chunk,
932                                               ITask                    replacement,
933                                               ITask                    selectedChild,
934                                               List<FlattenInstruction> result)
935    {
936        // create a flatten instruction for the occurrence of the replacement
937        for (Object pathObj : chunk.getLines()) {
938            TaskPath path = (TaskPath) pathObj;
939           
940            if (replacement instanceof IOptional) {
941                result.add(new FlattenInstruction(path, (IOptional) replacement));
942            }
943            else if (replacement instanceof ISelection) {
944                result.add
945                    (new FlattenInstruction(path, (ISelection) replacement, selectedChild));
946            }
947        }
948    }
949
950    /**
951     *
952     */
953    private void flattenInstances(ITask                            task,
954                                  List<FlattenInstruction>         flattenInstructions,
955                                  Map<ITaskInstance, IUserSession> flattenedSessions,
956                                  List<TaskPath>                   excludes)
957    {
958        //int i = 0;
959        for (ITaskInstance instance : task.getInstances()) {
960            /*System.out.println("flattening instance " + i++ + " of task " + task);
961            new TaskTreeEncoder().encode(instance, System.out, excludes);*/
962           
963            TaskPath taskPath = new TaskPath();
964            taskPath.add(instance.getTask(), 0);
965            IUserSession session = taskFactory.createUserSession();
966            flattenInstance(instance, taskPath, flattenInstructions, session,
967                            new LinkedList<TaskPath>());
968           
969            //new TaskTreeEncoder().encode(session, System.out, excludes);
970           
971            flattenedSessions.put(instance, session);
972        }
973    }
974
975    /**
976     *
977     */
978    private void flattenInstance(ITaskInstance            instance,
979                                 TaskPath                 taskPath,
980                                 List<FlattenInstruction> flattenInstructions,
981                                 IUserSession             session,
982                                 List<TaskPath>           previousPaths)
983    {
984        boolean instructionApplied = false;
985       
986        TaskComparator comp = identTaskHandlStrat.getTaskComparator();
987       
988        //System.out.println("applying instructions on " + taskPath);
989       
990        for (FlattenInstruction instruction : flattenInstructions) {
991            if (instruction.matches(taskPath)) {
992                //System.out.print("found instruction ");
993                //instruction.dump(System.out);
994               
995                switch (instruction.getInstruction()) {
996                    case DONT_TRAVERSE: {
997                        if (instance != null) {
998                            taskBuilder.addTaskInstance(session, instance);
999                        }
1000                        instructionApplied = true;
1001                        break;
1002                    }
1003                    case MAKE_OPTIONAL: {
1004                        instructionApplied = true;
1005
1006                        if (instance == null) {
1007                            break;
1008                        }
1009                       
1010                        IOptional optional = instruction.getOptional();
1011
1012                        if (comp.equals(optional, instance.getTask())) {
1013                            // the instance is already an instance of the correct optional --> reuse
1014                            taskBuilder.addTaskInstance(session, instance);
1015                        }
1016                        else if (comp.equals(optional.getMarkedTask(), instance.getTask())) {
1017                            IOptionalInstance optionalInstance =
1018                                taskFactory.createNewTaskInstance(optional);
1019                            taskBuilder.setChild(optionalInstance, instance);
1020                            taskBuilder.addTaskInstance(session, optionalInstance);
1021                        }
1022                        else if (optional.getMarkedTask() instanceof ISequence) {
1023                            // first check, if the instance was already created, if not create it
1024                            ISequenceInstance sequenceInstance = ensureSequenceChildInstanceFor
1025                                (optional, (ISequence) optional.getMarkedTask(), session);
1026
1027                            taskBuilder.addChild(sequenceInstance, instance);
1028                        }
1029                        break;
1030                    }
1031                    case MAKE_SELECTION: {
1032                        instructionApplied = true;
1033
1034                        if (instance == null) {
1035                            break;
1036                        }
1037                       
1038                        ISelection selection = instruction.getSelection();
1039
1040                        if (comp.equals(instruction.getSelectedChild(), instance.getTask())) {
1041                            ISelectionInstance selectionInstance =
1042                                taskFactory.createNewTaskInstance(selection);
1043                            taskBuilder.setChild(selectionInstance, instance);
1044                            taskBuilder.addTaskInstance(session, selectionInstance);
1045                        }
1046                        else if (instruction.getSelectedChild() == null) {
1047                            // both variants were already selections. They will have been merged.
1048                            // Hence we can reuse the child instances of the existing selection
1049                            // instances.
1050                            if (comp.equals(instance.getTask(), selection)) {
1051                                taskBuilder.addTaskInstance(session, instance);
1052                            }
1053                            else {
1054                                ISelectionInstance selectionInstance =
1055                                    taskFactory.createNewTaskInstance(selection);
1056                                taskBuilder.setChild(selectionInstance,
1057                                                     ((ISelectionInstance) instance).getChild());
1058                                taskBuilder.addTaskInstance(session, selectionInstance);
1059                               
1060                                taskBuilder.discardTaskInstance(instance);
1061                            }
1062                        }
1063                        else if (instruction.getSelectedChild() instanceof ISequence) {
1064                            // first check, if the instance was already created, if not create it
1065                            ISequenceInstance sequenceInstance = ensureSequenceChildInstanceFor
1066                                (selection, (ISequence) instruction.getSelectedChild(),  session);
1067
1068                            taskBuilder.addChild(sequenceInstance, instance);
1069                        }
1070
1071                        break;
1072                    }
1073                    case INTEGRATE_OPTIONAL: {
1074                        TaskPath previousPath = previousPaths.size() > 0 ?
1075                            previousPaths.get(previousPaths.size() - 1) : null;
1076                       
1077                        if (pathsMatch(instruction.getPrecedingPath(), previousPath)) {
1078                            IOptional optional = instruction.getOptional();
1079                            IOptionalInstance optionalInstance =
1080                                    taskFactory.createNewTaskInstance(optional);
1081                            taskBuilder.addTaskInstance(session, optionalInstance);
1082                        }
1083                       
1084                        if (instance != null) {
1085                            taskBuilder.addTaskInstance(session, instance);
1086                        }
1087                       
1088                        instructionApplied = true;
1089                        break;
1090                    }
1091                    default : {
1092                        throw new RuntimeException("unknown instruction type");
1093                    }
1094                }
1095            }
1096           
1097            if (instructionApplied) {
1098                break;
1099            }
1100        }
1101       
1102        if (!instructionApplied) {
1103            ITask task = taskPath.getLast();
1104            if (task instanceof IIteration) {
1105                taskPath.add(((IIteration) task).getMarkedTask(), 0);
1106               
1107                if (instance != null) {
1108                    for (ITaskInstance child : (IIterationInstance) instance) {
1109                        flattenInstance
1110                            (child, taskPath, flattenInstructions, session, previousPaths);
1111                    }
1112                }
1113                else {
1114                    flattenInstance(null, taskPath, flattenInstructions, session, previousPaths);
1115                }
1116               
1117                taskPath.removeLast();
1118            }
1119            else if (task instanceof ISequence) {
1120                List<ITask> children = ((ISequence) task).getChildren();
1121                for (int i = 0; i < children.size(); i++) {
1122                    ITaskInstance child = null;
1123                    if (instance != null) {
1124                        child = ((ISequenceInstance) instance).get(i);
1125                    }
1126                    taskPath.add(children.get(i), i);
1127                    flattenInstance
1128                        (child, taskPath, flattenInstructions, session, previousPaths);
1129                    taskPath.removeLast();
1130                }
1131            }
1132            else if (task instanceof ISelection) {
1133                if (instance != null) {
1134                    taskPath.add(((ISelectionInstance) instance).getChild().getTask(), 0);
1135                    flattenInstance(((ISelectionInstance) instance).getChild(), taskPath,
1136                                    flattenInstructions, session, previousPaths);
1137                    taskPath.removeLast();
1138                }
1139                else {
1140                    // check if the selection has any child for which a rule must be considered
1141                    List<ITask> children = ((ISelection) task).getChildren();
1142                    for (int i = 0; i < children.size(); i++) {
1143                        taskPath.add(children.get(i), i);
1144                        flattenInstance
1145                            (null, taskPath, flattenInstructions, session, previousPaths);
1146                        taskPath.removeLast();
1147                    }
1148                }
1149            }
1150            else if (task instanceof IOptional) {
1151                taskPath.add(((IOptional) task).getMarkedTask(), 0);
1152                ITaskInstance child = null;
1153                if (instance != null) {
1154                    child = ((IOptionalInstance) instance).getChild();
1155                }
1156                flattenInstance(child, taskPath, flattenInstructions, session, previousPaths);
1157                taskPath.removeLast();
1158               
1159                if ((instance != null) && (child == null)) {
1160                    // add the empty optional instance
1161                    taskBuilder.addTaskInstance(session, instance);
1162                    previousPaths.add(new TaskPath(taskPath));
1163                }
1164            }
1165            else if (instance != null) {
1166                taskBuilder.addTaskInstance(session, instance);
1167                previousPaths.add(new TaskPath(taskPath));
1168            }
1169        }
1170        else {
1171            previousPaths.add(new TaskPath(taskPath));
1172        }
1173    }
1174
1175    /**
1176     *
1177     */
1178    private ISequenceInstance ensureSequenceChildInstanceFor(ITask        replacement,
1179                                                             ISequence    expectedChildSequence,
1180                                                             IUserSession session)
1181    {
1182        // first check, if there is already an instance of the expected sequence. If so, check if
1183        // its child is a sequence instance. If not create a new task instance with an appropriate
1184        // sequence instance
1185        ITaskInstance prevInstance =
1186            session.size() > 0 ? session.get(session.size() - 1) : null;
1187       
1188        ISequenceInstance sequenceInstance = null;
1189       
1190        if ((prevInstance != null) &&
1191            (identTaskHandlStrat.getTaskComparator().equals(prevInstance.getTask(), replacement)))
1192        {
1193            if ((prevInstance instanceof IOptionalInstance) &&
1194                (((IOptionalInstance) prevInstance).getChild() instanceof ISequenceInstance))
1195            {
1196                sequenceInstance =
1197                    (ISequenceInstance) ((IOptionalInstance) prevInstance).getChild();
1198            }
1199            else if ((prevInstance instanceof ISelectionInstance) &&
1200                    (((ISelectionInstance) prevInstance).getChild() instanceof ISequenceInstance))
1201            {
1202                sequenceInstance =
1203                    (ISequenceInstance) ((ISelectionInstance) prevInstance).getChild();
1204            }
1205        }
1206       
1207        // although we found a sequence instance as expected, this instance might already be fully
1208        // created and a new (iterated) one must be created. Check for it and handle correctly
1209        if ((sequenceInstance != null) &&
1210            (sequenceInstance.size() == expectedChildSequence.getChildren().size()))
1211        {
1212            sequenceInstance = null;
1213        }
1214       
1215        if (sequenceInstance == null) {
1216            //System.out.println("creating new sequence instance of selected child");
1217            sequenceInstance = taskFactory.createNewTaskInstance(expectedChildSequence);
1218               
1219            ITaskInstance replacementInstance = null;
1220           
1221            if (replacement instanceof IOptional) {
1222                replacementInstance = taskFactory.createNewTaskInstance((IOptional) replacement);
1223                taskBuilder.setChild((IOptionalInstance) replacementInstance, sequenceInstance);
1224            }
1225            else if (replacement instanceof ISelection) {
1226               
1227                /*System.out.println("replacement: ");
1228                new TaskTreeEncoder().encode(replacement, System.out);
1229               
1230                System.out.println("expectedChild: ");
1231                new TaskTreeEncoder().encode(expectedChildSequence, System.out);*/
1232               
1233                replacementInstance = taskFactory.createNewTaskInstance((ISelection) replacement);
1234                taskBuilder.setChild((ISelectionInstance) replacementInstance, sequenceInstance);
1235            }
1236           
1237            taskBuilder.addTaskInstance(session, replacementInstance);
1238        }
1239       
1240        return sequenceInstance;
1241    }
1242
1243    /**
1244     *
1245     */
1246    private void replaceTaskInstances(ITaskInstanceList                 taskInstanceList,
1247                                      Map<ITaskInstance, ITaskInstance> replacements,
1248                                      SimilarTasks                      similarTasks)
1249    {
1250        for (int i = 0; i < taskInstanceList.size(); i++) {
1251            ITaskInstance childInstance = taskInstanceList.get(i);
1252            ITaskInstance replacement = replacements.remove(childInstance);
1253           
1254            if (replacement != null) {
1255               
1256                // update the model for sequences (others are updated in the calling method)
1257                if (taskInstanceList instanceof ISequenceInstance) {
1258                    ISequence task = ((ISequenceInstance) taskInstanceList).getSequence();
1259                    taskBuilder.setChild(task, i, replacement.getTask());
1260                }
1261                else if (taskInstanceList instanceof IIterationInstance) {
1262                    IIteration task = ((IIterationInstance) taskInstanceList).getIteration();
1263                    taskBuilder.setMarkedTask(task, replacement.getTask());
1264                }
1265               
1266                // perform the actual replacement and throw away the instance
1267                taskBuilder.setTaskInstance(taskInstanceList, i, replacement);
1268                TaskPath path = new TaskPath();
1269                path.add(childInstance.getTask(), 0);
1270                discardTaskInstancesNotBelongingToTraversals(childInstance, path, similarTasks);
1271            }
1272            else {
1273                replaceTaskInstances(childInstance, replacements, similarTasks);
1274            }
1275        }
1276    }
1277
1278    /**
1279     *
1280     */
1281    private void replaceTaskInstances(IOptionalInstance                 optionalInstance,
1282                                      Map<ITaskInstance, ITaskInstance> replacements,
1283                                      SimilarTasks                      similarTasks)
1284    {
1285        ITaskInstance childInstance = optionalInstance.getChild();
1286       
1287        if (childInstance != null) {
1288            ITaskInstance replacement = replacements.remove(childInstance);
1289           
1290            if (replacement != null) {
1291                // do not update the model --> is updated in the calling method
1292               
1293                // perform the actual replacement and throw away the instance
1294                taskBuilder.setMarkedTask(optionalInstance.getOptional(), replacement.getTask());
1295                taskBuilder.setChild(optionalInstance, replacement);
1296                TaskPath path = new TaskPath();
1297                path.add(childInstance.getTask(), 0);
1298                discardTaskInstancesNotBelongingToTraversals(childInstance, path, similarTasks);
1299            }
1300            else {
1301                replaceTaskInstances(childInstance, replacements, similarTasks);
1302            }
1303        }
1304    }
1305
1306    /**
1307     *
1308     */
1309    private void replaceTaskInstances(ISelectionInstance                selectionInstance,
1310                                      Map<ITaskInstance, ITaskInstance> replacements,
1311                                      SimilarTasks                      similarTasks)
1312    {
1313        TaskComparator comparator = identTaskHandlStrat.getTaskComparator();
1314       
1315        ITaskInstance childInstance = selectionInstance.getChild();
1316       
1317        if (childInstance != null) {
1318            ITaskInstance replacement = replacements.remove(childInstance);
1319           
1320            if (replacement != null) {
1321               
1322                if (replacement instanceof ISelectionInstance) {
1323                    // if the replacement itself is a selection instance, we cannot add
1324                    // a selection instance as the child of the parent selection instance.
1325                    // therefore, we just use the child of the replacement as new child of the
1326                    // existing selection instance
1327                    taskBuilder.discardTaskInstance(replacement);
1328                    replacement = ((ISelectionInstance) replacement).getChild();
1329                }
1330               
1331                // update the model
1332                // we replace all instances of the merged tasks with instances of a new task.
1333                // hence, we also have to remove the task of the replaced children from the
1334                // available variants of the selection
1335                taskBuilder.removeChild(selectionInstance.getSelection(), childInstance.getTask());
1336
1337                boolean found = false;
1338                for (ITask child : selectionInstance.getSelection().getChildren()) {
1339                    if (comparator.equals(child, replacement.getTask())) {
1340                        found = true;
1341                        break;
1342                    }
1343                }
1344               
1345                if (!found) {
1346                    taskBuilder.addChild(selectionInstance.getSelection(), replacement.getTask());
1347                }
1348               
1349                // perform the actual replacement and throw away the instance
1350                taskBuilder.setChild(selectionInstance, replacement);
1351                TaskPath path = new TaskPath();
1352                path.add(childInstance.getTask(), 0);
1353                discardTaskInstancesNotBelongingToTraversals(childInstance, path, similarTasks);
1354            }
1355            else {
1356                replaceTaskInstances(childInstance, replacements, similarTasks);
1357            }
1358        }
1359    }
1360
1361    /**
1362     *
1363     */
1364    private void replaceTaskInstances(ITaskInstance                     childInstance,
1365                                      Map<ITaskInstance, ITaskInstance> replacements,
1366                                      SimilarTasks                      similarTasks)
1367    {
1368        if (childInstance instanceof IIterationInstance) {
1369            replaceTaskInstances((ITaskInstanceList) childInstance, replacements, similarTasks);
1370        }
1371        else if (childInstance instanceof IOptionalInstance) {
1372            replaceTaskInstances((IOptionalInstance) childInstance, replacements, similarTasks);
1373        }
1374        else if (childInstance instanceof ISelectionInstance) {
1375            replaceTaskInstances((ISelectionInstance) childInstance, replacements, similarTasks);
1376        }
1377        else if (childInstance instanceof ISequenceInstance) {
1378            replaceTaskInstances((ITaskInstanceList) childInstance, replacements, similarTasks);
1379        }
1380    }
1381
1382    /**
1383     *
1384     */
1385    private void discardTaskInstancesNotBelongingToTraversals(ITaskInstance instance,
1386                                                              TaskPath      pathToInstance,
1387                                                              SimilarTasks  similarTasks)
1388    {
1389        boolean discarded = false;
1390        for (TaskPath candidate : similarTasks.getLeftHandSideTraversal().getTraversalPaths()) {
1391            if (candidate.size() > pathToInstance.size()) {
1392                TaskPath potentialEqualSubPath = candidate.subPath(0, pathToInstance.size());
1393                if (pathsMatch(potentialEqualSubPath, pathToInstance)) {
1394                    taskBuilder.discardTaskInstance(instance);
1395                    discarded = true;
1396                    break;
1397                }
1398            }
1399        }
1400       
1401        if (!discarded) {
1402            for (TaskPath candidate : similarTasks.getRightHandSideTraversal().getTraversalPaths()) {
1403                if (candidate.size() > pathToInstance.size()) {
1404                    TaskPath potentialEqualSubPath = candidate.subPath(0, pathToInstance.size());
1405                    if (pathsMatch(potentialEqualSubPath, pathToInstance)) {
1406                        taskBuilder.discardTaskInstance(instance);
1407                        discarded = true;
1408                        break;
1409                    }
1410                }
1411            }
1412        }
1413       
1414        if (discarded) {
1415            // now also discard the children
1416            if (instance instanceof ISequenceInstance) {
1417                int index = 0;
1418                for (ITaskInstance childInstance : (ITaskInstanceList) instance) {
1419                    pathToInstance.add(childInstance.getTask(), index++);
1420                    discardTaskInstancesNotBelongingToTraversals
1421                        (childInstance, pathToInstance, similarTasks);
1422                    pathToInstance.removeLast();
1423                }
1424            }
1425            else if (instance instanceof IIterationInstance) {
1426                for (ITaskInstance childInstance : (ITaskInstanceList) instance) {
1427                    pathToInstance.add(childInstance.getTask(), 0);
1428                    discardTaskInstancesNotBelongingToTraversals
1429                        (childInstance, pathToInstance, similarTasks);
1430                    pathToInstance.removeLast();
1431                }
1432            }
1433            else if (instance instanceof IOptionalInstance) {
1434                ITaskInstance childInstance = ((IOptionalInstance) instance).getChild();
1435                if (childInstance != null) {
1436                    pathToInstance.add(childInstance.getTask(), 0);
1437                    discardTaskInstancesNotBelongingToTraversals
1438                        (childInstance, pathToInstance, similarTasks);
1439                    pathToInstance.removeLast();
1440                }
1441            }
1442            else if (instance instanceof ISelectionInstance) {
1443                ITaskInstance childInstance = ((ISelectionInstance) instance).getChild();
1444                pathToInstance.add(childInstance.getTask(), 0);
1445                discardTaskInstancesNotBelongingToTraversals
1446                    (childInstance, pathToInstance, similarTasks);
1447                pathToInstance.removeLast();
1448            }
1449        }
1450    }
1451   
1452    /**
1453     *
1454     */
1455    private void mergeSubsequentIdenticalMarkingTemporalRelationships(ITaskInstanceList list) {
1456        int index = 0;
1457        TaskComparator comparator = identTaskHandlStrat.getTaskComparator();
1458       
1459        while (index < (list.size() - 1)) {
1460            ITaskInstance instance1 = list.get(index);
1461            ITaskInstance instance2 = list.get(index + 1);
1462           
1463            if (comparator.equals(instance1.getTask(), instance2.getTask())) {
1464                if (instance1 instanceof IIterationInstance) {
1465                    // add the children of the second to the first iteration instance and discard
1466                    // the second
1467                    for (ITaskInstance child : (IIterationInstance) instance2) {
1468                        taskBuilder.addChild((IIterationInstance) instance1, child);
1469                    }
1470                   
1471                    taskBuilder.removeTaskInstance(list, index + 1);
1472                    taskBuilder.discardTaskInstance(instance2);
1473                }
1474                else if (instance1 instanceof IOptionalInstance) {
1475                    ITaskInstance optionalChildInstance1 =
1476                        ((IOptionalInstance) instance1).getChild();
1477                    ITaskInstance optionalChildInstance2 =
1478                            ((IOptionalInstance) instance2).getChild();
1479                       
1480                    if (optionalChildInstance1 == null) {
1481                        // independent of the second, just remove the first. The second will be the
1482                        // unique representation
1483                        taskBuilder.removeTaskInstance(list, index);
1484                    }
1485                    else if (optionalChildInstance2 == null) {
1486                        // remove the second. The first will be the unique representation
1487                        taskBuilder.removeTaskInstance(list, index + 1);
1488                    }
1489                    else if (optionalChildInstance1 instanceof IIterationInstance) {
1490                        // add all children of the second optional iteration instance to the
1491                        // first and discard the second
1492                        for (ITaskInstance child : (IIterationInstance) optionalChildInstance2) {
1493                            taskBuilder.addChild
1494                                ((IIterationInstance) optionalChildInstance1, child);
1495                        }
1496                       
1497                        taskBuilder.removeTaskInstance(list, index + 1);
1498                        taskBuilder.discardTaskInstance(instance2);
1499                    }
1500                    else {
1501                        // both optional children are no iterations --> create an iteration
1502                        // for them and add them both as children.
1503                        throw new java.lang.UnsupportedOperationException("not implemented yet");
1504                    }
1505                }
1506                else {
1507                    index++;
1508                }
1509            }
1510            else {
1511                index++;
1512            }
1513        }
1514       
1515        for (ITaskInstance child : list) {
1516            if (child instanceof ITaskInstanceList) {
1517                mergeSubsequentIdenticalMarkingTemporalRelationships((ITaskInstanceList) child);
1518            }
1519        }
1520    }
1521   
1522    /**
1523     *
1524     */
1525    private static boolean pathsMatch(TaskPath path1, TaskPath path2) {
1526        if (path1 == null) {
1527            return path2 == null;
1528        }
1529        else if ((path2 != null) && (path1.size() == path2.size())) {
1530            for (int i = 0; i < path1.size(); i++) {
1531                if (!path1.get(i).equals(path2.get(i))) {
1532                    return false;
1533                }
1534            }
1535            return true;
1536        }
1537        else {
1538            return false;
1539        }
1540    }
1541
1542    /**
1543     *
1544     */
1545    /*private boolean containsNewTask(ITask task, RuleApplicationData appData) {
1546        if (appData.isSelfCreatedTask(task)) {
1547            return true;
1548        }
1549        else if (task instanceof IStructuringTemporalRelationship) {
1550            for (ITask child : ((IStructuringTemporalRelationship) task).getChildren()) {
1551                if (containsNewTask(child, appData)) {
1552                    return true;
1553                }
1554            }
1555        }
1556        else if (task instanceof IMarkingTemporalRelationship) {
1557            return containsNewTask(((IMarkingTemporalRelationship) task).getMarkedTask(), appData);
1558        }
1559       
1560        return false;
1561    }*/
1562
1563    /**
1564     *
1565     */
1566    private class RuleApplicationData {
1567
1568        /**
1569         *
1570         */
1571        private List<IUserSession> sessions;
1572       
1573        /**
1574         *
1575         */
1576        private ITaskModel taskModel;
1577
1578        /**
1579         *
1580         */
1581        private MostSimilarTaskDeterminer mostSimilarTasksDeterminer =
1582            new MostSimilarTaskDeterminer(identTaskHandlStrat.getTaskComparator());
1583       
1584        /**
1585         *
1586         */
1587        private List<SimilarTasks> mostSimilarTasks;
1588       
1589        /**
1590         *
1591         */
1592        private List<ITask> newTasks = new LinkedList<ITask>();
1593       
1594        /**
1595         *
1596         */
1597        private RuleApplicationResult ruleApplicationResult = new RuleApplicationResult();
1598       
1599        /**
1600         *
1601         */
1602        private RuleApplicationData(List<IUserSession> sessions) {
1603            this.sessions = sessions;
1604        }
1605
1606        /**
1607         *
1608         */
1609        boolean isSelfCreatedTask(ITask task) {
1610            for (ITask candidate : newTasks) {
1611                if (candidate == task) {
1612                    return true;
1613                }
1614            }
1615           
1616            return false;
1617        }
1618
1619        /**
1620         * @return the mostSimilarTasksDeterminer
1621         */
1622        private MostSimilarTaskDeterminer getMostSimilarTasksDeterminer() {
1623            return mostSimilarTasksDeterminer;
1624        }
1625
1626        /**
1627         *
1628         */
1629        private void markAsAlreadyCondensed(ITask task1, ITask task2) {
1630            mostSimilarTasksDeterminer.addComparisonToSkip(task1, task2);
1631        }
1632
1633        /**
1634         *
1635         */
1636        private RuleApplicationResult finalizeRuleApplicationResult() {
1637            for (ITask newTask : newTasks) {
1638                ruleApplicationResult.addNewlyCreatedTask(newTask);
1639               
1640                if (newTask instanceof IOptional) {
1641                    if (isSelfCreatedTask(((IOptional) newTask).getMarkedTask()) &&
1642                        (((IOptional) newTask).getMarkedTask() instanceof ISequence))
1643                    {
1644                        ruleApplicationResult.addNewlyCreatedTask
1645                            (((IOptional) newTask).getMarkedTask());
1646                    }
1647                }
1648                else if (newTask instanceof ISelection) {
1649                    for (ITask child : ((ISelection) newTask).getChildren()) {
1650                        if (isSelfCreatedTask(child) && (child instanceof ISequence)) {
1651                            ruleApplicationResult.addNewlyCreatedTask(child);
1652                        }
1653                    }
1654                }
1655            }
1656           
1657           
1658            return ruleApplicationResult;
1659        }
1660
1661        /**
1662         * @return the tree
1663         */
1664        private List<IUserSession> getSessions() {
1665            return sessions;
1666        }
1667
1668        /**
1669         * @return the taskModel
1670         */
1671        private ITaskModel getTaskModel() {
1672            return taskModel;
1673        }
1674
1675        /**
1676         * @param taskModel the taskModel to set
1677         */
1678        private void setTaskModel(ITaskModel taskModel) {
1679            this.taskModel = taskModel;
1680        }
1681
1682        /**
1683         * @return the orderedDiffLevels
1684         */
1685        private List<SimilarTasks> getMostSimilarTasks() {
1686            return mostSimilarTasks;
1687        }
1688
1689        /**
1690         * @param orderedDiffLevels the orderedDiffLevels to set
1691         */
1692        private void setMostSimilarTasks(List<SimilarTasks> mostSimilarTasks) {
1693            this.mostSimilarTasks = mostSimilarTasks;
1694        }
1695       
1696        /**
1697         *
1698         */
1699        private ITask ensureUnique(ITask task) {
1700            // replacements done in this rule are either optionals or selections. So focus on them
1701            if (task instanceof IOptional) {
1702                for (ITask newTask : newTasks) {
1703                    if (newTask instanceof IOptional) {
1704                        ITask child1 = ((IOptional) task).getMarkedTask();
1705                        ITask child2 = ((IOptional) newTask).getMarkedTask();
1706                        if (createdChildEquals(child1, child2)) {
1707                            // System.out.println("reusing optional " + newTask + " for " + task);
1708                            return newTask;
1709                        }
1710                    }
1711                }
1712            }
1713            else if (task instanceof ISelection) {
1714                for (ITask newTask : newTasks) {
1715                    if (newTask instanceof ISelection) {
1716                        List<ITask> children1 = ((ISelection) task).getChildren();
1717                        List<ITask> children2 = ((ISelection) newTask).getChildren();
1718                        if (createdSelectionChildrenEqual(children1, children2)) {
1719                            /*System.out.println("reusing selection " + newTask + " for " + task);
1720                           
1721                            System.out.println("---------------------------- existing task");
1722                            new TaskTreeEncoder().encode(newTask, System.out);
1723                           
1724                            System.out.println("---------------------------- completely new task");
1725                            new TaskTreeEncoder().encode(task, System.out);*/
1726                           
1727                            return newTask;
1728                        }
1729                    }
1730                }
1731            }
1732            else if (task instanceof ISequence) {
1733                List<ISequence> allRelevant = new ArrayList<>();
1734               
1735                for (ITask candidate : newTasks) {
1736                    if (candidate instanceof ISequence) {
1737                        allRelevant.add((ISequence) candidate);
1738                    }
1739                }
1740               
1741                for (ITask candidate : taskModel.getTasks()) {
1742                    if (candidate instanceof ISequence) {
1743                        allRelevant.add((ISequence) candidate);
1744                    }
1745                }
1746               
1747                for (ISequence candidate : allRelevant) {
1748                    List<ITask> children1 = ((ISequence) task).getChildren();
1749                    List<ITask> children2 = ((ISequence) candidate).getChildren();
1750
1751                    boolean equal = false;
1752                    if (children1.size() == children2.size()) {
1753                        equal = true;
1754                        for (int i = 0; i < children1.size(); i++) {
1755                            if (children1.get(i) != children2.get(i)) {
1756                                equal = false;
1757                                break;
1758                            }
1759                        }
1760                    }
1761
1762                    if (equal) {
1763                        // System.out.println("reusing sequence " + candidate + " for " + task);
1764                        return candidate;
1765                    }
1766                }
1767            }
1768           
1769            newTasks.add(task);
1770           
1771            return task;
1772        }
1773
1774        /**
1775         *
1776         */
1777        private boolean createdSelectionChildrenEqual(List<ITask> children1, List<ITask> children2) {
1778            if (children1.size() != children2.size()) {
1779                return false;
1780            }
1781           
1782            for (ITask child1 : children1) {
1783                boolean found = false;
1784               
1785                for (ITask child2 : children2) {
1786                    if (createdChildEquals(child1, child2)) {
1787                        found = true;
1788                        break;
1789                    }
1790                }
1791               
1792                if (!found) {
1793                    return false;
1794                }
1795            }
1796           
1797            return true;
1798        }
1799
1800        /**
1801         *
1802         */
1803        private boolean createdChildEquals(ITask child1, ITask child2) {
1804            if (child1 == child2) {
1805                return true;
1806            }
1807            else if (!isSelfCreatedTask(child1) && !isSelfCreatedTask(child2)) {
1808                // the simple comparison can not work if the tasks are not self created
1809                return false;
1810            }
1811            else if ((child1 instanceof ISequence) && (child2 instanceof ISequence)) {
1812                ISequence sequence1 = (ISequence) child1;
1813                ISequence sequence2 = (ISequence) child2;
1814               
1815                if (sequence1.getChildren().size() != sequence2.getChildren().size()) {
1816                    return false;
1817                }
1818               
1819                for (int i = 0; i < sequence1.getChildren().size(); i++) {
1820                    if (sequence1.getChildren().get(i) != sequence2.getChildren().get(i)) {
1821                        return false;
1822                    }
1823                }
1824               
1825                return true;
1826            }
1827            else {
1828                return false;
1829            }
1830        }
1831    }
1832   
1833    /**
1834     *
1835     */
1836    private static class FlattenInstruction {
1837       
1838        /**
1839         *
1840         */
1841        private enum Instruction { DONT_TRAVERSE, MAKE_OPTIONAL, MAKE_SELECTION, INTEGRATE_OPTIONAL };
1842
1843        /** */
1844        private TaskPath path;
1845
1846        /** */
1847        private TaskPath precedingPath;
1848
1849        /** */
1850        private Instruction instruction;
1851
1852        /** */
1853        private IOptional optional = null;
1854
1855        /** */
1856        private ISelection selection = null;
1857
1858        /** */
1859        private ITask selectedChild = null;
1860
1861        /**
1862         *
1863         */
1864        private FlattenInstruction(TaskPath path) {
1865            this.path = path;
1866            this.instruction = Instruction.DONT_TRAVERSE;
1867        }
1868
1869        /**
1870         *
1871         */
1872        private FlattenInstruction(TaskPath path, IOptional optional) {
1873            this.path = path;
1874            this.instruction = Instruction.MAKE_OPTIONAL;
1875            this.optional = optional;
1876        }
1877
1878        /**
1879         *
1880         */
1881        private FlattenInstruction(TaskPath path, ISelection selection, ITask selectedChild) {
1882            this.path = path;
1883            this.instruction = Instruction.MAKE_SELECTION;
1884            this.selection = selection;
1885            this.selectedChild = selectedChild;
1886        }
1887
1888        /**
1889         *
1890         */
1891        private FlattenInstruction(TaskPath  precedingPath,
1892                                   TaskPath  path,
1893                                   IOptional optional)
1894        {
1895            this.path = path;
1896            this.precedingPath = precedingPath;
1897            this.instruction = Instruction.INTEGRATE_OPTIONAL;
1898            this.optional = optional;
1899        }
1900       
1901        /**
1902         *
1903         */
1904        IOptional getOptional() {
1905            return optional;
1906        }
1907
1908
1909        /**
1910         * @return the selection
1911         */
1912        ISelection getSelection() {
1913            return selection;
1914        }
1915
1916        /**
1917         * @return the selectedChild
1918         */
1919        ITask getSelectedChild() {
1920            return selectedChild;
1921        }
1922
1923        /**
1924         * @return the instruction
1925         */
1926        Instruction getInstruction() {
1927            return instruction;
1928        }
1929
1930        /**
1931         * @return the precedingPath
1932         */
1933        TaskPath getPrecedingPath() {
1934            return precedingPath;
1935        }
1936
1937        /**
1938         *
1939         */
1940        boolean matches(TaskPath path) {
1941            return pathsMatch(this.path, path);
1942        }
1943       
1944
1945//        /**
1946//         *
1947//         */
1948//        void dump(PrintStream out) {
1949//            for (int i = 0; i < path.size(); i++) {
1950//                out.print("-->");
1951//                out.print(path.getTask(i).getId());
1952//                out.print('(');
1953//                out.print(path.get(i).getIndex());
1954//                out.print(')');
1955//            }
1956//           
1957//            out.print("  ");
1958//            out.print(instruction);
1959//           
1960//            out.println();
1961//        }
1962       
1963    }
1964
1965}
Note: See TracBrowser for help on using the repository browser.