Index: trunk/autoquest-core-tasktrees/src/main/java/de/ugoe/cs/autoquest/tasktrees/treeimpl/TaskModel.java
===================================================================
--- trunk/autoquest-core-tasktrees/src/main/java/de/ugoe/cs/autoquest/tasktrees/treeimpl/TaskModel.java	(revision 1287)
+++ trunk/autoquest-core-tasktrees/src/main/java/de/ugoe/cs/autoquest/tasktrees/treeimpl/TaskModel.java	(revision 1423)
@@ -21,4 +21,14 @@
 import java.util.Map;
 
+import de.ugoe.cs.autoquest.tasktrees.treeifc.IEventTask;
+import de.ugoe.cs.autoquest.tasktrees.treeifc.IEventTaskInstance;
+import de.ugoe.cs.autoquest.tasktrees.treeifc.IIteration;
+import de.ugoe.cs.autoquest.tasktrees.treeifc.IIterationInstance;
+import de.ugoe.cs.autoquest.tasktrees.treeifc.IMarkingTemporalRelationship;
+import de.ugoe.cs.autoquest.tasktrees.treeifc.IOptional;
+import de.ugoe.cs.autoquest.tasktrees.treeifc.IOptionalInstance;
+import de.ugoe.cs.autoquest.tasktrees.treeifc.ISelection;
+import de.ugoe.cs.autoquest.tasktrees.treeifc.ISelectionInstance;
+import de.ugoe.cs.autoquest.tasktrees.treeifc.IStructuringTemporalRelationship;
 import de.ugoe.cs.autoquest.tasktrees.treeifc.ITask;
 import de.ugoe.cs.autoquest.tasktrees.treeifc.ITaskInstance;
@@ -27,9 +37,11 @@
 import de.ugoe.cs.autoquest.tasktrees.treeifc.ITaskInfo;
 import de.ugoe.cs.autoquest.tasktrees.treeifc.IUserSession;
+import de.ugoe.cs.autoquest.tasktrees.treeifc.TaskMetric;
 
 /**
  * <p>
  * this is the default implementation of the interface {@link ITaskModel}. It
- * does not do anything fancy except implementing the interface.
+ * does not do anything fancy except implementing the interface. It also calculates on
+ * initialisations the measures for diverse metrics of the task belonging to the model
  * </p>
  * 
@@ -44,4 +56,15 @@
      */
     private static final long serialVersionUID = 1L;
+    
+    /**
+     * <p>
+     * all metrics calculated by this type of task model
+     * </p>
+     */
+    private static final TaskMetric[] taskMetrics = new TaskMetric[]
+        { TaskMetric.COUNT,
+          TaskMetric.DEPTH,
+          TaskMetric.EVENT_COVERAGE,
+          TaskMetric.EVENT_COVERAGE_RATIO };
 
     /**
@@ -54,10 +77,9 @@
     /**
      * <p>
-     * the tasks contained in the user session belonging to the model as well as statistical infos
-     * about them
-     * </p>
-     */
-    private Map<ITask, TaskInfo> taskMap = new HashMap<ITask, TaskInfo>();
-
+     * index for effectively accessing the model and calculating statistics about it
+     * </p>
+     */
+    private transient TaskModelIndex index = null;
+    
     /**
      * <p>
@@ -73,10 +95,4 @@
         
         this.userSessions = userSessions;
-        
-        for (IUserSession session : this.userSessions) {
-            for (ITaskInstance taskInstance : session) {
-                addTasksToMap(taskInstance);
-            }
-        }
     }
 
@@ -87,4 +103,5 @@
     @Override
     public List<IUserSession> getUserSessions() {
+        ensureInitialized();
         return Collections.unmodifiableList(userSessions);
     }
@@ -96,5 +113,6 @@
     @Override
     public Collection<ITask> getTasks() {
-        return Collections.unmodifiableCollection(taskMap.keySet());
+        ensureInitialized();
+        return Collections.unmodifiableCollection(index.taskMap.keySet());
     }
 
@@ -105,6 +123,16 @@
     @Override
     public ITaskInfo getTaskInfo(ITask task) {
-        return taskMap.get(task);
-    }
+        ensureInitialized();
+        return index.taskMap.get(task);
+    }
+
+    /* (non-Javadoc)
+     * @see de.ugoe.cs.autoquest.tasktrees.treeifc.ITaskModel#getAllMetrics()
+     */
+    @Override
+    public TaskMetric[] getAllMetrics() {
+        return taskMetrics;
+    }
+
 
     /* (non-Javadoc)
@@ -116,48 +144,228 @@
     }
 
-
-    /**
-     * <p>
-     * internal convenience method to recursively add the tasks of a task instance and its
-     * children to the task model
-     * </p>
-     *
-     * @param taskInstance the task instance of which the tasks shall be added
-     */
-    private void addTasksToMap(ITaskInstance taskInstance) {
-        addTaskToMap(taskInstance.getTask());
-        
-        if (taskInstance instanceof ITaskInstanceList) {
-            for (ITaskInstance child : (ITaskInstanceList) taskInstance) {
-                addTasksToMap(child);
-            }
-        }
-    }
-
-    
-    /**
-     * <p>
-     * internal convenience method to build the task model during initialization
-     * </p>
-     */
-    private void addTaskToMap(ITask task) {
-        TaskInfo taskInfo = taskMap.get(task);
-
-        if (taskInfo == null) {
-            taskInfo = new TaskInfo(task);
-            taskMap.put(task, taskInfo);
-        }
-
-        taskInfo.increaseCount();
-
-        /*if (task instanceof IStructuringTemporalRelationship) {
-            for (ITask child : ((IStructuringTemporalRelationship) task).getChildren()) {
-                addTaskToMap(child);
-            }
-        }
-        else if (task instanceof IMarkingTemporalRelationship) {
-            addTaskToMap(((IMarkingTemporalRelationship) task).getMarkedTask());
+    /**
+     * <p>
+     * internal convenience method that initializes the internal index and calculates all measures
+     * for metrics available for the tasks
+     * </p>
+     */
+    private synchronized void ensureInitialized() {
+        if (index == null) {
+            index = new TaskModelIndex();
+            
+            for (IUserSession session : this.userSessions) {
+                for (ITaskInstance taskInstance : session) {
+                    index.handleTaskInstance(taskInstance, null);
+                }
+            }
+            
+            // count all events covered
+            int allEventsCovered = 0;
+            Collection<ITask> tasks = getTasks();
+            for (ITask task : tasks) {
+                if (task instanceof IEventTask) {
+                    allEventsCovered += task.getInstances().size();
+                }
+            }
+            
+            // add some further measures
+            for (ITask task : tasks) {
+                TaskInfo info = index.taskMap.get(task);
+                info.addMeasure(TaskMetric.EVENT_COVERAGE_RATIO);
+                
+                int coveredEvents = info.getMeasureValue(TaskMetric.EVENT_COVERAGE);
+                
+                if (allEventsCovered > 0) {
+                    info.setCount(TaskMetric.EVENT_COVERAGE_RATIO, null,
+                                  ((coveredEvents * 1000) / allEventsCovered));
+                }
+            }
+            
+            //index.dumpToCSV(System.out);
+            /*try {
+                OutputStream stream = new FileOutputStream(new File("tasks.csv"));
+                index.dumpToCSV(new PrintStream(stream));
+                stream.close();
+            }
+            catch (FileNotFoundException e) {
+                e.printStackTrace();
+            }*/
+        }
+        
+    }
+
+    /**
+     * <p>
+     * the index of task infos used internally. The index is created once and while that filled
+     * with task infos for each observed task containing all measures for metrics belonging
+     * to the tasks. 
+     * </p>
+     * 
+     * @author Patrick Harms
+     */
+    private static class TaskModelIndex {
+
+        /**
+         * <p>
+         * the tasks contained in the user session belonging to the model as well as statistical
+         * infos about them
+         * </p>
+         */
+        private Map<ITask, TaskInfo> taskMap = new HashMap<ITask, TaskInfo>();
+
+        /**
+         * <p>
+         * called on initialization to fill the index with infos about the given task instance
+         * as well as to calculate the appropriate metrics
+         * </p>
+         */
+        private int[] handleTaskInstance(ITaskInstance taskInstance, ITask context) {
+            int eventTaskInstancesCovered = 0;
+            int depth = 0;
+            
+            if (taskInstance instanceof ITaskInstanceList) {
+                for (ITaskInstance child : (ITaskInstanceList) taskInstance) {
+                    int[] measures = handleTaskInstance(child, taskInstance.getTask());
+                    eventTaskInstancesCovered += measures[0];
+                    depth = Math.max(depth, measures[1]);
+                }
+                
+                if ((((ITaskInstanceList) taskInstance).size() == 0) &&
+                    (taskInstance instanceof IIterationInstance))
+                {
+                    // ensure also empty task infos for unselected variants
+                    ensureTaskInfo(((IIteration) taskInstance.getTask()).getMarkedTask(), context);
+                }
+            }
+            else if (taskInstance instanceof ISelectionInstance) {
+                ITaskInstance child = ((ISelectionInstance) taskInstance).getChild();
+                int[] measures = handleTaskInstance(child, taskInstance.getTask());
+                eventTaskInstancesCovered += measures[0];
+                depth = Math.max(depth, measures[1]);
+                
+                // ensure also empty task infos for unselected variants
+                for (ITask otherChildTask : ((ISelection) taskInstance.getTask()).getChildren()) {
+                    ensureTaskInfo(otherChildTask, context);
+                }
+            }
+            else if (taskInstance instanceof IOptionalInstance) {
+                ITaskInstance child = ((IOptionalInstance) taskInstance).getChild();
+                if (child != null) {
+                    int[] measures = handleTaskInstance(child, taskInstance.getTask());
+                    eventTaskInstancesCovered += measures[0];
+                    depth = Math.max(depth, measures[1]);
+                }
+                else {
+                    // ensure also empty task infos for unselected variants
+                    ensureTaskInfo(((IOptional) taskInstance.getTask()).getMarkedTask(), context);
+                }
+            }
+            else if (taskInstance instanceof IEventTaskInstance) {
+                eventTaskInstancesCovered = 1;
+            }
+            
+            depth++;
+            
+            ensureTaskInfo(taskInstance.getTask(), context, eventTaskInstancesCovered, depth);
+            
+            return new int[] { eventTaskInstancesCovered, depth };
+        }
+        
+        /**
+         * <p>
+         * internal convenience method to build the task model during initialization
+         * </p>
+         */
+        private void ensureTaskInfo(ITask task, ITask context) {
+            ensureTaskInfo(task, context, 0, 0);
+            
+            if (task instanceof IStructuringTemporalRelationship) {
+                for (ITask child : ((IStructuringTemporalRelationship) task).getChildren()) {
+                    ensureTaskInfo(child, task);
+                }
+            }
+            else if (task instanceof IMarkingTemporalRelationship) {
+                ensureTaskInfo(((IMarkingTemporalRelationship) task).getMarkedTask(), task);
+            }
+        
+        }
+        
+        /**
+         * <p>
+         * internal convenience method to build the task model during initialization. Adds a new
+         * task info object to the map for the provided task and fills it with measures. If there
+         * are already some task infos for the task, the contained measures are updated according
+         * to the parameters.
+         * </p>
+         */
+        private void ensureTaskInfo(ITask task,
+                                    ITask context,
+                                    int   eventTaskInstancesCovered,
+                                    int   depth)
+        {
+            TaskInfo taskInfo = taskMap.get(task);
+
+            if (taskInfo == null) {
+                taskInfo = new TaskInfo(task);
+                taskInfo.addMeasure(TaskMetric.COUNT);
+                taskInfo.addMeasure(TaskMetric.EVENT_COVERAGE);
+                taskInfo.addMeasure(TaskMetric.DEPTH);
+                taskMap.put(task, taskInfo);
+                
+                taskInfo.setCount(TaskMetric.DEPTH, null, getDepth(task));
+            }
+
+            taskInfo.increaseCount(TaskMetric.COUNT, context, 1);
+            taskInfo.increaseCount(TaskMetric.EVENT_COVERAGE, context, eventTaskInstancesCovered);
+
+            taskInfo.setCount(TaskMetric.DEPTH, context, depth);
+        }
+
+        /**
+         * <p>
+         * internal convenience method to calculate the maximum depth of a task
+         * </p>
+         */
+        private int getDepth(ITask task) {
+            if (task instanceof IMarkingTemporalRelationship) {
+                return getDepth(((IMarkingTemporalRelationship) task).getMarkedTask()) + 1;
+            }
+            else if (task instanceof IStructuringTemporalRelationship) {
+                int maxDepth = 0;
+                
+                for (ITask child : ((IStructuringTemporalRelationship) task).getChildren()) {
+                    maxDepth = Math.max(maxDepth, getDepth(child));
+                }
+                
+                return maxDepth + 1;
+            }
+            else {
+                // event tasks
+                return 1;
+            }
+        }
+
+        /**
+         *
+         */
+        /*private void dumpToCSV(PrintStream out) {
+            out.println("taskid;depth;count;eventcoverage;eventcoverageratio");
+            
+            for (Map.Entry<ITask, TaskInfo> entry : taskMap.entrySet()) {
+                out.print(entry.getKey().getId());
+                out.print(';');
+                out.print(entry.getValue().getMeasureValue(TaskMetric.DEPTH));
+                out.print(';');
+                out.print(entry.getValue().getMeasureValue(TaskMetric.COUNT));
+                out.print(';');
+                out.print(entry.getValue().getMeasureValue(TaskMetric.EVENT_COVERAGE));
+                out.print(';');
+                out.print(entry.getValue().getMeasureValue(TaskMetric.EVENT_COVERAGE_RATIO));
+                out.println();
+            }
         }*/
-    }
+
+    }
+
 
 }
