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

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