Index: trunk/autoquest-plugin-html/src/main/java/de/ugoe/cs/autoquest/plugin/html/commands/CMDcondenseHTMLGUIModel.java
===================================================================
--- trunk/autoquest-plugin-html/src/main/java/de/ugoe/cs/autoquest/plugin/html/commands/CMDcondenseHTMLGUIModel.java	(revision 1286)
+++ trunk/autoquest-plugin-html/src/main/java/de/ugoe/cs/autoquest/plugin/html/commands/CMDcondenseHTMLGUIModel.java	(revision 1334)
@@ -15,4 +15,5 @@
 package de.ugoe.cs.autoquest.plugin.html.commands;
 
+import java.io.PrintStream;
 import java.util.Arrays;
 import java.util.Comparator;
@@ -73,6 +74,9 @@
  *         \-- html
  *               \-- body
- *                     |-- div (id = menu)
- *                     |     \-- ...
+ *                     |-- group (common)
+ *                     |     |-- div (id = menu)
+ *                     |     |     \-- ...
+ *                     |     \-- div (id = footer)
+ *                     |           \-- ...
  *                     |-- group (document1)
  *                     |     \-- div (id = textcontent)
@@ -81,6 +85,4 @@
  *                     |     \-- div (id = imagecontent)
  *                     |           \-- ...
- *                     \-- div (id = footer)
- *                           \-- ...
  * </pre>
  * This now allows the menu and the footer to be treated as identical over several pages.
@@ -146,8 +148,8 @@
         GUIElementsCluster rootCluster = getSimilarElementClusterHierarchy(server, model);
 
-        //rootCluster.dump(System.out, "");
-            
-        Console.traceln(Level.FINE, "merging GUI elements in same clusters and creating groups");
-        mergeGUIElementsAccordingToClusters(rootCluster, model, "");
+        rootCluster.dump(System.out, "");
+            
+        Console.traceln(Level.FINE, "grouping GUI elements according to clusters");
+        groupGUIElementsAccordingToClusters(rootCluster, model, "");
             
         //model.dump(System.out, "UTF-8");
@@ -157,31 +159,33 @@
     /**
      * <p>
-     * determines clusters of similar GUI elements being children of the provided parent. For this,
-     * the method creates a cluster containing all children of the provided parent as similar
-     * GUI elements. Usually, these are all documents on the same server. It then initiates
-     * creating the cluster hierarchy by calling the recursive method
+     * determines clusters of similar GUI elements being children of the provided server. For this,
+     * the method creates a cluster containing all children of the provided server as similar
+     * GUI elements. Usually, these are all documents on the server. It then initiates creating
+     * the cluster hierarchy by calling the recursive method
      * {@link #addChildClusters(GUIElementsCluster, GUIModel, String)}.
      * </p>
      *
-     * @param parent the parent GUI element for which the clusters of similar children shall be
-     *               determined (usually an HTML server)
+     * @param server the server for which the clusters of similar children shall be determined
      * @param model  the GUI model required for identifying children and sub children
      * 
-     * @return a list of GUI element clusters of the children.
-     */
-    private GUIElementsCluster getSimilarElementClusterHierarchy(IGUIElement parent, GUIModel model)
+     * @return a GUI element cluster representing the server.
+     */
+    private GUIElementsCluster getSimilarElementClusterHierarchy(HTMLServer server, GUIModel model)
     {
         GUIElementsCluster cluster = new GUIElementsCluster();
         
-        List<IGUIElement> children = model.getChildren(parent);
+        List<IGUIElement> children = model.getChildren(server);
         
         SimilarGUIElements similarGuiElements = new SimilarGUIElements();
         
         for (IGUIElement child : children) {
-            // when starting with the root, the cluster parent is the child itself
+            // when starting with the root, the cluster parent is the child itself, i.e. the
+            // document. We expect all documents to be similar.
             similarGuiElements.add(new SimilarGUIElement(child, child));
         }
         
         cluster.addSimilarGUIElements(similarGuiElements);
+        
+        // create the cluster structure
         addChildClusters(cluster, model, "");
         
@@ -209,5 +213,5 @@
         }
         
-        createClusterHierachies(cluster.childClusters);
+        createClusterHierachies(cluster);
     }
     
@@ -216,5 +220,5 @@
      * for a set of similar GUI elements, it identifies similar children and clusters them. For
      * each identified cluster, it adds a new child cluster to the provided parent cluster. GUI
-     * elements having no further children are added to a default cluster.
+     * elements having no further children are ignored.
      * </p>
      *
@@ -235,46 +239,29 @@
                 for (IGUIElement child : children) {
                     addToClusterOfSimilarElements
-                        (child, similarGuiElement.mainClusterParent, parentCluster.childClusters,
+                        (child, similarGuiElement.mainClusterParent, parentCluster,
                          similarGuiElements, model);
                 }
             }
-            else {
-                // search for a default cluster to add all elements to, which have no children
-                GUIElementsCluster defaultCluster = null;
-                
-                for (GUIElementsCluster candidate : parentCluster.childClusters) {
-                    if (candidate.similarChildrenGUIElements.size() == 0) {
-                        defaultCluster = candidate;
-                        break;
-                    }
-                }
-                
-                if (defaultCluster == null) {
-                    defaultCluster = new GUIElementsCluster();
-                    parentCluster.addChildCluster(defaultCluster);
-                }
-                
-                defaultCluster.clusteredGUIElements.add(similarGuiElement);
-            }
-        }
-    }
-
-    /**
-     * <p>
-     * for a given GUI element, searches the list of known clusters and adds the GUI element to
-     * the cluster, if the cluster already contains a similar GUI element. If not, a new cluster is
-     * created and added to the list of known clusters.
+        }
+    }
+
+    /**
+     * <p>
+     * for a given GUI element, searches the list of child clusters of the parent cluster and adds
+     * the GUI element to the cluster, if the cluster already contains a similar GUI element. If
+     * not, a new cluster is created and added to the list of known clusters.
      * </p>
      *
-     * @param child         the child for which the cluster is to be determined
-     * @param clusterParent the GUI element for 
-     * @param parents
-     * @param model
-     */
-    private void addToClusterOfSimilarElements(IGUIElement              child,
-                                               IGUIElement              clusterParent,
-                                               List<GUIElementsCluster> knownClusters,
-                                               SimilarGUIElements       similarGuiElements,
-                                               GUIModel                 model)
+     * @param child              the child for which the cluster is to be determined
+     * @param clusterParent      the root GUI element of the parent cluster
+     * @param parentCluster      the parent cluster whose child clusters shall be filled
+     * @param similarGuiElements the similar GUI elements currently matched to each other
+     * @param model              the GUI model required to determine children of GUI elements
+     */
+    private void addToClusterOfSimilarElements(IGUIElement        child,
+                                               IGUIElement        clusterParent,
+                                               GUIElementsCluster parentCluster,
+                                               SimilarGUIElements similarGuiElements,
+                                               GUIModel           model)
     {
         SimilarGUIElements matchingParents = new SimilarGUIElements();
@@ -294,5 +281,5 @@
         GUIElementsCluster cluster = null;
         
-        for (GUIElementsCluster clusterCandidate : knownClusters) {
+        for (GUIElementsCluster clusterCandidate : parentCluster.childClusters) {
             if (clusterCandidate.isClusterOf(matchingParents)) {
                 cluster = clusterCandidate;
@@ -303,5 +290,5 @@
         if (cluster == null) {
             cluster = new GUIElementsCluster();
-            knownClusters.add(cluster);
+            parentCluster.addChildCluster(cluster);
             cluster.setClusteredGUIElements(matchingParents);
         }
@@ -315,13 +302,15 @@
      * each other. This is, e.g., the case if one cluster contains all elements being part of
      * document1 and document2 and a further cluster contains all elements of document 1 only. In
-     * this case, the cluster of document1 is added as a child to the other cluster.
+     * this case, the cluster of document1 is added as a child to the other cluster. In this case
+     * it is furthermore required, that a common cluster as child of the document1/document2 cluster
+     * is created carrying the common GUI elements for both clusters.
      * </p>
      *
-     * @param clusters the clusters, for which the child hierarchies shall be created
-     *                 (in-out parameter, as it is changed)
-     */
-    private void createClusterHierachies(List<GUIElementsCluster> clusters) {
-        GUIElementsCluster[] clustersCopy =
-            clusters.toArray(new GUIElementsCluster[clusters.size()]);
+     * @param parentCluster the parent cluster for whose children the child hierarchies shall be
+     *                      created (in-out parameter, as it is changed)
+     */
+    private void createClusterHierachies(GUIElementsCluster parentCluster) {
+        GUIElementsCluster[] clustersCopy = parentCluster.childClusters.toArray
+            (new GUIElementsCluster[parentCluster.childClusters.size()]);
         
         // sort the array starting with the shortest cluster and ending with the longest
@@ -333,5 +322,5 @@
         });
         
-        List<GUIElementsCluster> subClustersToHandle = new LinkedList<GUIElementsCluster>();
+        Set<GUIElementsCluster> subClustersToHandle = new HashSet<GUIElementsCluster>();
         
         // now add smaller clusters to larger ones, if they are parents
@@ -346,7 +335,7 @@
                     subClustersToHandle.add(clustersCopy[j]);
                     
-                    for (int k = 0; k < clusters.size(); k++) {
-                        if (clusters.get(k) == potentialChild) {
-                            clusters.remove(k);
+                    for (int k = 0; k < parentCluster.childClusters.size(); k++) {
+                        if (parentCluster.childClusters.get(k) == potentialChild) {
+                            parentCluster.childClusters.remove(k);
                             break;
                         }
@@ -358,43 +347,18 @@
         }
         
-        // finally, for all subclusters that were changed, ensure the creation of their internal
-        // hierarchy as well
-        for (GUIElementsCluster subClusterToHandle : subClustersToHandle) {
-            createClusterHierachies(subClusterToHandle.childClusters);
-        }
-    }
-
-    /**
-     * <p>
-     * called for each cluster to merge similar GUI elements depending on the clusters and to
-     * create GUI element groups if required. Calls itself recursively to be also applied on
-     * child clusters.
-     * </p>
-     *
-     * @param cluster the cluster of which the similar children shall be merged
-     * @param model   the model to be adapted through the merge
-     */
-    private void mergeGUIElementsAccordingToClusters(GUIElementsCluster cluster,
-                                                     GUIModel           model,
-                                                     String             indent)
-    {
-        //System.out.println(indent + "handling " + cluster);
-        
-        for (SimilarGUIElements similarGUIElements : cluster.similarChildrenGUIElements) {
-            mergeGUIElements(similarGUIElements, model, indent + "  ");
-        }
-        
-        if (cluster.childClusters.size() > 0) {
-            //System.out.println(indent + "  handling child clusters");
-            
-            for (GUIElementsCluster childCluster : cluster.childClusters) {
-                if (cluster.isDefault() || cluster.clusterParentsMatch(childCluster)) {
-                    // for default cluster or children not creating subgroups, just traverse the
-                    // cluster hierarchy
-                    mergeGUIElementsAccordingToClusters(childCluster, model, indent + "    ");
-                }
-                else {
-                    createClusterGroup(childCluster, model, indent + "    ");
-                }
+        if (subClustersToHandle.size() > 0) {
+            // finally, for all subclusters that were changed, ensure the creation of their internal
+            // hierarchy as well
+            for (GUIElementsCluster subClusterToHandle : subClustersToHandle) {
+                // we need a dedicated common cluster --> add it
+                createClusterHierachies(subClusterToHandle);
+                
+                GUIElementsCluster commonCluster = new GUIElementsCluster();
+                //commonCluster.setClusteredGUIElements(subClusterToHandle.clusteredGUIElements);
+                commonCluster.similarChildrenGUIElements.addAll
+                    (subClusterToHandle.similarChildrenGUIElements);
+                
+                subClusterToHandle.similarChildrenGUIElements.clear();
+                subClusterToHandle.childClusters.add(0, commonCluster);
             }
         }
@@ -416,6 +380,6 @@
 
         while (similarGUIElements.size() > 1) {
-            //System.out.println(indent + "merging " + mergeResult + " and " +
-            //                   similarGUIElements.get(1).similarGUIElement);
+            System.out.println(indent + "merging " + mergeResult + " and " +
+                               similarGUIElements.get(1).similarGUIElement);
             mergeResult = model.mergeGUIElements
                 (mergeResult, similarGUIElements.remove(1).similarGUIElement, false);
@@ -432,7 +396,10 @@
      * @param model   the model to be used for creating the groups
     */
-    private void createClusterGroup(GUIElementsCluster cluster, GUIModel model, String indent) {
-        //System.out.println(indent + "creating group for " + cluster);
-
+    private void groupGUIElementsAccordingToClusters(GUIElementsCluster cluster,
+                                                     GUIModel           model,
+                                                     String             indent)
+    {
+        System.out.println(indent + "handling " + cluster);
+        
         List<IGUIElement> guiElementsToGroup = new LinkedList<IGUIElement>();
         
@@ -442,30 +409,46 @@
         }
         
-        //System.out.println(indent + "  iterating child clusters of " + cluster);
+        List<IGUIElement> subgroups = new LinkedList<IGUIElement>();
+
+        
+        System.out.println(indent + "iterating child clusters of " + cluster);
         for (GUIElementsCluster childCluster : cluster.childClusters) {
-            if (cluster.isDefault() || cluster.clusterParentsMatch(childCluster)) {
-                // for default cluster or children not creating subgroups, just traverse the
-                // cluster hierarchy
-                mergeGUIElementsAccordingToClusters(childCluster, model, indent + "  ");
-            }
-            else {
-                createClusterGroup(childCluster, model, indent + "  ");
-            }
-            
-            if (childCluster.getGroup() != null) {
-                if (cluster.isSubCluster(childCluster)) {
-                    guiElementsToGroup.add(childCluster.getGroup());
-                }
-                else {
-                    guiElementsToGroup.add(childCluster.getGroup().getParent());
-                }
-            }
-        }
-        
-        //System.out.println(indent + "grouping: " + guiElementsToGroup);
-        IGUIElement group = model.groupGUIElements(guiElementsToGroup, getGroupName(cluster));
-        //System.out.println(indent + "  created group for " + cluster + ": " + group);
-        
-        cluster.setGroup(group);
+            groupGUIElementsAccordingToClusters(childCluster, model, indent + "  ");
+            
+            if (cluster.childClusters.size() > 1) {
+                List<IGUIElement> childGuiElemsToGroup = new LinkedList<IGUIElement>();
+                
+                for (SimilarGUIElements similarGUIElems : childCluster.similarChildrenGUIElements) {
+                    childGuiElemsToGroup.addAll(similarGUIElems.toGUIElementList());
+                }
+                
+                for (GUIElementsCluster subsubcluster : childCluster.childClusters) {
+                    if (subsubcluster.getGroup() != null) {
+                        childGuiElemsToGroup.add(subsubcluster.getGroup());
+                    }
+                }
+                
+                if (childGuiElemsToGroup.size() > 0) {
+                    System.out.println(indent + "  grouping: " + childGuiElemsToGroup);
+                    IGUIElement group = model.groupGUIElements
+                        (childGuiElemsToGroup, getGroupName(childCluster));
+                    System.out.println
+                        (indent + "    created group for " + childCluster + ": " + group);
+
+                    if (group != null) {
+                        childCluster.setGroup(group);
+                        if (cluster.isSubCluster(childCluster)) {
+                            subgroups.add(childCluster.getGroup());
+                        }
+                        else {
+                            subgroups.add(childCluster.getGroup().getParent());
+                        }
+                    }
+                }
+            }
+            
+            System.out.println();
+        }
+        
     }
 
@@ -484,11 +467,16 @@
         name.append("group_");
         
-        for (SimilarGUIElement guiElement : cluster.clusteredGUIElements) {
-            if (guiElement.mainClusterParent instanceof HTMLDocument) {
-                name.append(((HTMLDocument) guiElement.mainClusterParent).getPath());
-            }
-            else {
-                name.append(guiElement.mainClusterParent.getStringIdentifier());
-            }
+        if (cluster.clusteredGUIElements.size() > 0) {
+            for (SimilarGUIElement guiElement : cluster.clusteredGUIElements) {
+                if (guiElement.mainClusterParent instanceof HTMLDocument) {
+                    name.append(((HTMLDocument) guiElement.mainClusterParent).getPath());
+                }
+                else {
+                    name.append(guiElement.mainClusterParent.getStringIdentifier());
+                }
+            }
+        }
+        else {
+            name.append("common");
         }
         
@@ -557,42 +545,4 @@
         /**
          * <p>
-         * checks, if the main cluster parents, i.e., the documents of this and the provided cluster
-         * match
-         * </p>
-         *
-         * @param other the other cluster of which the main cluster parents shall be compared to
-         *              this
-         *              
-         * @return true if they match, false else
-         */
-        private boolean clusterParentsMatch(GUIElementsCluster other) {
-            // cluster parent may already be merged and therefore equals --> use system identity
-            // hash code for uniqueness
-            Set<Integer> mainClusterParents1 = new HashSet<Integer>();
-            for (SimilarGUIElement clusteredElem1 : clusteredGUIElements) {
-                mainClusterParents1.add(System.identityHashCode(clusteredElem1.mainClusterParent));
-            }
-            
-            Set<Integer> mainClusterParents2 = new HashSet<Integer>();
-            for (SimilarGUIElement clusteredElem2 : other.clusteredGUIElements) {
-                mainClusterParents2.add(System.identityHashCode(clusteredElem2.mainClusterParent));
-            }
-            
-            return mainClusterParents1.equals(mainClusterParents2);
-        }
-
-        /**
-         * <p>
-         * returns true, if this cluster is a default cluster
-         * </p>
-         *
-         * @return
-         */
-        public boolean isDefault() {
-            return clusteredGUIElements.size() <= 0;
-        }
-
-        /**
-         * <p>
          * sets the GUI element group created for this cluster
          * </p>
@@ -710,11 +660,17 @@
             
             if (clusteredGUIElements.size() > 0) {
+                ret.append(clusteredGUIElements.get(0).similarGUIElement);
+                ret.append(" [");
+                
+                int length = ret.length();
                 for (SimilarGUIElement similarGUIElement : clusteredGUIElements) {
-                    if (ret.length() > "cluster(".length()) {
+                    if (ret.length() > length) {
                         ret.append(", ");
                     }
 
-                    ret.append(similarGUIElement);
-                }
+                    ret.append(similarGUIElement.mainClusterParent);
+                }
+                
+                ret.append(']');
             }
             else {
@@ -732,51 +688,48 @@
          * </p>
          */
-//        private void dump(PrintStream out, String indent) {
-//            out.print(indent);
-//            out.print(getName());
-//            out.print(" { ");
-//            
-//            if (similarChildrenGUIElements.size() > 0) {
-//                out.println();
-//                out.print(indent);
-//                out.println("  similar children {");
-//
-//                for (SimilarGUIElements similarGuiElements : similarChildrenGUIElements) {
-//                    similarGuiElements.dump(out, indent + "    ");
-//                }
-//
-//                out.print(indent);
-//                out.println("  }");
-//
-//                if (childClusters.size() > 0) {
-//                    out.print(indent);
-//                    out.println("  child clusters {");
-//
-//                    for (GUIElementsCluster childCluster : childClusters) {
-//                        childCluster.dump(out, indent + "    ");
-//                    }
-//
-//                    out.print(indent);
-//                    out.println("  }");
-//                }
-//
-//                out.print(indent);
-//            }
-//            else if (clusteredGUIElements.size() > 0) {
-//                out.println();
-//                out.print(indent);
-//                out.println("  clustered GUIElements {");
-//
-//                for (SimilarGUIElement clusteredGUIElement : clusteredGUIElements) {
-//                    clusteredGUIElement.dump(out, indent + "    ");
-//                }
-//
-//                out.print(indent);
-//                out.println("  }");
-//                out.print(indent);
-//            }
-//            
-//            out.println("}");
-//        }
+        private void dump(PrintStream out, String indent) {
+            out.print(indent);
+            out.print(getName());
+            out.println(" { ");
+            
+            if (clusteredGUIElements.size() > 0) {
+                out.print(indent);
+                out.println("  clustered GUIElements {");
+
+                for (SimilarGUIElement clusteredGUIElement : clusteredGUIElements) {
+                    clusteredGUIElement.dump(out, indent + "    ");
+                }
+
+                out.print(indent);
+                out.println("  }");
+            }
+
+            if (similarChildrenGUIElements.size() > 0) {
+                out.print(indent);
+                out.println("  similar children {");
+
+                for (SimilarGUIElements similarGuiElements : similarChildrenGUIElements) {
+                    similarGuiElements.dump(out, indent + "    ");
+                }
+
+                out.print(indent);
+                out.println("  }");
+            }
+
+            if (childClusters.size() > 0) {
+                out.print(indent);
+                out.println("  child clusters {");
+
+                for (GUIElementsCluster childCluster : childClusters) {
+                    childCluster.dump(out, indent + "    ");
+                }
+
+                out.print(indent);
+                out.println("  }");
+            }
+            
+            out.print(indent);
+            out.println("}");
+        }
 
     }
@@ -834,17 +787,17 @@
          * </p>
          */
-//        private void dump(PrintStream out, String indent) {
-//            out.print(indent);
-//            out.print("{ ");
-//            
-//            for (int i = 0; i < super.size(); i++) {
-//                if (i > 0) {
-//                    out.print(", ");
-//                }
-//                out.print(super.get(i));
-//            }
-//            
-//            out.println(" }");
-//        }
+        private void dump(PrintStream out, String indent) {
+            out.print(indent);
+            out.print("{ ");
+            
+            for (int i = 0; i < super.size(); i++) {
+                if (i > 0) {
+                    out.print(", ");
+                }
+                out.print(super.get(i));
+            }
+            
+            out.println(" }");
+        }
     }
     
@@ -886,8 +839,8 @@
          * </p>
          */
-//        private void dump(PrintStream out, String indent) {
-//            out.print(indent);
-//            out.println(this);
-//        }
+        private void dump(PrintStream out, String indent) {
+            out.print(indent);
+            out.println(this);
+        }
 
         /* (non-Javadoc)
