package de.lmu.ifi.dbs.elki.data;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import de.lmu.ifi.dbs.elki.data.cluster.Cluster;
import de.lmu.ifi.dbs.elki.data.model.Model;
import de.lmu.ifi.dbs.elki.result.Result;

/**
 * Result class for clusterings. Can be used for both hierarchical and non-hierarchical clusterings.
 * 
 * The class does not enforce or rely on clusterings to be a tree or DAG, instead they can be an arbitrary
 * forest of directed graphs that COULD contain cycles.
 * 
 * @author Erich Schubert
 *
 * @param <M> Model type
 */
public class Clustering<M extends Model> implements Result {
  /**
   * Keep a list of top level clusters.
   */
  private List<Cluster<M>> toplevelclusters;

  /**
   * Constructor with a list of top level clusters
   * 
   * @param toplevelclusters Top level clusters
   */
  public Clustering(List<Cluster<M>> toplevelclusters) {
    super();
    this.toplevelclusters = toplevelclusters;
  }

  /**
   * Constructor for an empty clustering
   */
  public Clustering() {
    this(new ArrayList<Cluster<M>>());
  }

  /**
   * Add a cluster to the clustering.
   * 
   * @param n new cluster
   */
  public void addCluster(Cluster<M> n) {
    toplevelclusters.add(n);
  }

  /**
   * Return top level clusters
   * 
   * @return top level clusters
   */
  public List<Cluster<M>> getToplevelClusters() {
    return toplevelclusters;
  }

  /**
   * Collect all clusters (recursively) into a List.
   * 
   * @return List of all clusters.
   */
  public List<Cluster<M>> getAllClusters() {
    Set<Cluster<M>> clu = new HashSet<Cluster<M>>();
    for(Cluster<M> rc : toplevelclusters) {
      if(!clu.contains(rc)) {
        clu.add(rc);
        clu = rc.getDescendants(clu);
      }
    }
    // Note: we canNOT use TreeSet above, because this comparator is only partial!
    ArrayList<Cluster<M>> res = new ArrayList<Cluster<M>>(clu);
    Collections.sort(res, new Cluster.PartialComparator());
    return res;
  }

  @Override
  public String getName() {
    return "clustering";
  }
}

@@ -112,16 +112,43 @@
 ashSet;%0A
+import java.util.Iterator;%0A
 import j
@@ -396,16 +396,19 @@
 ical and
+%0A *
  non-hie
@@ -507,16 +507,19 @@
  or DAG,
+%0A *
  instead
@@ -543,19 +543,16 @@
 rbitrary
-%0A *
  forest 
@@ -588,16 +588,19 @@
  contain
+%0A *
  cycles.
@@ -632,16 +632,17 @@
 ubert%0A *
+ 
 %0A * @par
@@ -721,19 +721,42 @@
 s Result
+, Iterable%3CCluster%3CM%3E%3E
  %7B%0A
+%0A
   /**%0A  
@@ -1950,16 +1950,23 @@
  is only
+%0A    //
  partial
@@ -2180,11 +2180,111 @@
 ng%22;%0A  %7D
+%0A%0A  @Override%0A  public Iterator%3CCluster%3CM%3E%3E iterator() %7B%0A    return getAllClusters().iterator();%0A  %7D
 %0A%7D%0A

make a clustering iterable (via getAllClusters())