Index: trunk/autoquest-core-usability/src/main/java/de/ugoe/cs/autoquest/usability/RequiredInefficientActionsRule.java
===================================================================
--- trunk/autoquest-core-usability/src/main/java/de/ugoe/cs/autoquest/usability/RequiredScrollRule.java	(revision 1335)
+++ trunk/autoquest-core-usability/src/main/java/de/ugoe/cs/autoquest/usability/RequiredInefficientActionsRule.java	(revision 1493)
@@ -15,17 +15,16 @@
 package de.ugoe.cs.autoquest.usability;
 
-import java.text.DecimalFormat;
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.Map;
 
-import de.ugoe.cs.autoquest.eventcore.IEventType;
+import org.apache.commons.math3.stat.descriptive.DescriptiveStatistics;
+
+import de.ugoe.cs.autoquest.eventcore.Event;
 import de.ugoe.cs.autoquest.eventcore.gui.Scroll;
+import de.ugoe.cs.autoquest.tasktrees.treeifc.DefaultTaskInstanceTraversingVisitor;
+import de.ugoe.cs.autoquest.tasktrees.treeifc.IEventTask;
 import de.ugoe.cs.autoquest.tasktrees.treeifc.IEventTaskInstance;
-import de.ugoe.cs.autoquest.tasktrees.treeifc.IIterationInstance;
-import de.ugoe.cs.autoquest.tasktrees.treeifc.IOptionalInstance;
-import de.ugoe.cs.autoquest.tasktrees.treeifc.ISelectionInstance;
-import de.ugoe.cs.autoquest.tasktrees.treeifc.ISequence;
-import de.ugoe.cs.autoquest.tasktrees.treeifc.ISequenceInstance;
+import de.ugoe.cs.autoquest.tasktrees.treeifc.IMarkingTemporalRelationship;
 import de.ugoe.cs.autoquest.tasktrees.treeifc.ITask;
 import de.ugoe.cs.autoquest.tasktrees.treeifc.ITaskInstance;
@@ -38,5 +37,5 @@
  * @author 2012, last modified by $Author: pharms$
  */
-public class RequiredScrollRule implements UsabilityEvaluationRule {
+public class RequiredInefficientActionsRule implements UsabilityEvaluationRule {
 
     /*
@@ -47,8 +46,8 @@
     @Override
     public UsabilityEvaluationResult evaluate(ITaskModel taskModel) {
-        Map<ITask, Integer> smellingTasks = getTasksStartingWithScroll(taskModel.getTasks());
+        UsabilityEvaluationResult results = new UsabilityEvaluationResult(taskModel);
 
-        UsabilityEvaluationResult results = new UsabilityEvaluationResult();
-        analyzeTasksStartingWithScroll(smellingTasks, results);
+        Map<ITask, double[]> smellingTasks = getInefficientActionStatistics(taskModel.getTasks());
+        analyzeTasksWithInefficientActions(smellingTasks, results, taskModel);
 
         return results;
@@ -58,31 +57,24 @@
      *
      */
-    private void analyzeTasksStartingWithScroll(Map<ITask, Integer>       smellingTasks,
-                                                UsabilityEvaluationResult results)
+    private void analyzeTasksWithInefficientActions(Map<ITask, double[]>      smellingTasks,
+                                                    UsabilityEvaluationResult results,
+                                                    ITaskModel                taskModel)
     {
 
-        for (Map.Entry<ITask, Integer> entry : smellingTasks.entrySet()) {
-            float ratio = entry.getValue() / (float) entry.getKey().getInstances().size();
+        for (Map.Entry<ITask, double[]> entry : smellingTasks.entrySet()) {
+            DescriptiveStatistics stats = new DescriptiveStatistics(entry.getValue());
+            
+            int ratio = (int) (1000 * stats.getMean());
 
-            UsabilityDefectSeverity severity = null;
-            if (ratio > 0.9) {
-                severity = UsabilityDefectSeverity.HIGH;
-            }
-            else if (ratio > 0.6) {
-                severity = UsabilityDefectSeverity.MEDIUM;
-            }
-            else if (ratio > 0.4) {
-                severity = UsabilityDefectSeverity.LOW;
-            }
-            else if (ratio > 0.2) {
-                severity = UsabilityDefectSeverity.INFO;
-            }
+            UsabilityDefectSeverity severity = UsabilityDefectSeverity.getSeverity
+                (ratio, 500, 300, 200, 100, entry.getKey(), taskModel);
 
             if (severity != null) {
-                Map<String, String> parameters = new HashMap<String, String>();
-                parameters.put("task", entry.getKey().toString());
-                parameters.put("scrollRatio", DecimalFormat.getInstance().format(ratio * 100));
+                Map<String, Object> parameters = new HashMap<String, Object>();
+                parameters.put("task", entry.getKey());
+                parameters.put("ratio", (ratio / 10));
 
-                results.addDefect(severity, UsabilityDefectDescription.SCROLL_REQUIRED, parameters);
+                results.addDefect
+                    (severity, UsabilityDefectDescription.INEFFICIENT_ACTIONS, parameters);
             }
         }
@@ -92,18 +84,22 @@
      * 
      */
-    private Map<ITask, Integer> getTasksStartingWithScroll(Collection<ITask> tasks) {
-        Map<ITask, Integer> scrollCounts = new HashMap<ITask, Integer>();
+    private Map<ITask, double[]> getInefficientActionStatistics(Collection<ITask> tasks) {
+        Map<ITask, double[]> inefficientActionRatios = new HashMap<ITask, double[]>();
         
         for (ITask task : tasks) {
-            // only sequences are important for required scrolls
-            if (task instanceof ISequence) {
-                int count = countInstancesStartingWithScroll(task);
-                if (count > 0) {
-                    scrollCounts.put(task, count);
+            if (taskMustBeChecked(task))  {
+                double[] ratios = getRatiosOfInefficientActionsInInstances(task);
+                
+                for (int i = 0; i < ratios.length; i++) {
+                    if (ratios[i] > 0) {
+                        // there is at least on inefficient action
+                        inefficientActionRatios.put(task, ratios);
+                        break;
+                    }
                 }
             }
         }
         
-        return scrollCounts;
+        return inefficientActionRatios;
     }
 
@@ -111,15 +107,14 @@
      *
      */
-    private int countInstancesStartingWithScroll(ITask task) {
-        Collection<ITaskInstance> instances = task.getInstances();
-        
-        int counter = 0;
-        for (ITaskInstance instance : instances) {
-            if (startsWithScroll(instance)) {
-                counter++;
-            }
+    private boolean taskMustBeChecked(ITask task) {
+        if ((task instanceof IEventTask) || (task instanceof IMarkingTemporalRelationship)) {
+            // event tasks are not considered
+            // marking temporal relationships have a child, that is more important, but it will
+            // be checked independently as all tasks of a task model are checked separately
+            return false;
         }
-        
-        return counter;
+        else {
+            return true;
+        }
     }
 
@@ -127,79 +122,44 @@
      *
      */
-    private boolean startsWithScroll(ITaskInstance instance) {
-        if (instance instanceof ISequenceInstance) {
-            ITaskInstance firstChild = ((ISequenceInstance) instance).size() > 1 ?
-                ((ISequenceInstance) instance).get(0) : null;
-
-            if (firstChild == null) {
-                throw new IllegalArgumentException
-                    ("instance of a sequence must have at least two children");
-            }
-
-            if (startsWithScroll(firstChild)) {
-                return true;
-            }
-        }
-        else if (instance instanceof ISelectionInstance) {
-            ITaskInstance child = ((ISelectionInstance) instance).getChild();
-            
-            if (child != null) {
-                return startsWithScroll(child);
-            }
-            else {
-                throw new IllegalArgumentException("instance of a selection must have a child");
-            }
-        }
-        else if (instance instanceof IIterationInstance) {
-            ITaskInstance firstChild = ((IIterationInstance) instance).size() > 0 ?
-                ((IIterationInstance) instance).get(0) : null;
-
-            if (firstChild == null) {
-                throw new IllegalArgumentException
-                    ("instance of an iteration must have at least one child");
-            }
-
-            if (startsWithScroll(firstChild)) {
-                return true;
-            }
-        }
-        else if (instance instanceof IOptionalInstance) {
-            ITaskInstance child = ((IOptionalInstance) instance).getChild();
-            
-            if (child != null) {
-                return startsWithScroll(child);
-            }
-        }
-        else if (isScroll(instance)) {
-            return true;
+    private double[] getRatiosOfInefficientActionsInInstances(ITask task) {
+        Collection<ITaskInstance> instances = task.getInstances();
+        
+        double[] ratios = new double[instances.size()];
+        int index = 0;
+        for (ITaskInstance instance : instances) {
+            ratios[index++] = getRatioOfInefficientActionsInInstance(instance);
         }
         
-        return false;
+        return ratios;
     }
 
     /**
-     * @param firstChild
-     * @return
+     *
      */
-    private boolean isScroll(ITaskInstance instance) {
-        ITaskInstance instanceToCheck = instance;
+    private double getRatioOfInefficientActionsInInstance(ITaskInstance instance) {
+        final int[] count = new int[2];
+        count[0] = 0;
+        count[1] = 0;
         
-        if (instanceToCheck instanceof IIterationInstance) {
-            instanceToCheck = ((IIterationInstance) instanceToCheck).size() > 0 ?
-                ((IIterationInstance) instanceToCheck).get(0) : null;
+        instance.accept(new DefaultTaskInstanceTraversingVisitor() {
+            @Override
+            public void visit(IEventTaskInstance eventTaskInstance) {
+                if (isInefficientAction(eventTaskInstance.getEvent())) {
+                    count[0]++;
+                }
+                
+                count[1]++;
+            }
+            
+        });
+        
+        return (double) count[0] / count[1];
+    }
 
-            if (instanceToCheck == null) {
-                throw new IllegalArgumentException
-                    ("instance of an iteration must have at least one child");
-            }
-        }
-        
-        if (instanceToCheck instanceof IEventTaskInstance) {
-            IEventType type = ((IEventTaskInstance) instanceToCheck).getEvent().getType();
-            
-            return (type instanceof Scroll);
-        }
-        
-        return false;
+    /**
+     *
+     */
+    private boolean isInefficientAction(Event event) {
+        return (event.getType() instanceof Scroll);
     }
 
