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

import java.util.ArrayList;
import java.util.List;

import de.lmu.ifi.dbs.elki.data.Clustering;
import de.lmu.ifi.dbs.elki.database.AssociationID;
import de.lmu.ifi.dbs.elki.utilities.ClassGenericsUtil;

/**
 * Utilities for handling result objects
 * 
 * @author Erich Schubert
 * 
 */
public class ResultUtil {
  /**
   * Set global meta association. It tries to replace an existing Association
   * first, then tries to insert in the first {@link MetadataResult} otherwise
   * creating a new {@link MetadataResult} if none was found.
   * 
   * @param <M> restriction class
   * @param result Result collection
   * @param meta Association
   * @param value Value
   */
  public static final <M> void setGlobalAssociation(MultiResult result, AssociationID<M> meta, M value) {
    ArrayList<MetadataResult> mrs = result.filterResults(MetadataResult.class);
    // first try to overwrite an existing result.
    for(MetadataResult mri : mrs) {
      M res = mri.getAssociation(meta);
      if(res != null) {
        mri.setAssociation(meta, value);
        return;
      }
    }
    // otherwise, set in first
    if(mrs.size() > 0) {
      mrs.get(0).setAssociation(meta, value);
      return;
    }
    // or create a new MetadataResult.
    MetadataResult mr = new MetadataResult();
    mr.setAssociation(meta, value);
    result.addResult(mr);
  }

  /**
   * Get first Association from a MultiResult.
   * 
   * @param <M> restriction class
   * @param result Result collection
   * @param meta Association
   * @return first match or null
   */
  public static final <M> M getGlobalAssociation(Result result, AssociationID<M> meta) {
    List<MetadataResult> mrs = getMetadataResults(result);
    for(MetadataResult mr : mrs) {
      M res = mr.getAssociation(meta);
      if(res != null) {
        return res;
      }
    }
    return null;
  }

  /**
   * (Try to) find an association of the given ID in the result.
   * 
   * @param <T> Association result type
   * @param result Result to find associations in
   * @param assoc Association
   * @return First matching annotation result or null
   */
  public static final <T> AnnotationResult<T> findAnnotationResult(Result result, AssociationID<T> assoc) {
    List<AnnotationResult<?>> anns = getAnnotationResults(result);
    return findAnnotationResult(anns, assoc);
  }

  /**
   * (Try to) find an association of the given ID in the result.
   * 
   * @param <T> Association result type
   * @param anns List of Results
   * @param assoc Association
   * @return First matching annotation result or null
   */
  @SuppressWarnings("unchecked")
  public static final <T> AnnotationResult<T> findAnnotationResult(List<AnnotationResult<?>> anns, AssociationID<T> assoc) {
    if(anns == null) {
      return null;
    }
    for(AnnotationResult<?> a : anns) {
      if(a.getAssociationID() == assoc) { // == okay to use: association IDs are unique objects
        return (AnnotationResult<T>) a;
      }
    }
    return null;
  }

  /**
   * Collect all Annotation results from a Result
   * 
   * @param r Result
   * @return List of all annotation results
   */
  public static List<AnnotationResult<?>> getAnnotationResults(Result r) {
    if (r instanceof AnnotationResult) {
      List<AnnotationResult<?>> anns = new ArrayList<AnnotationResult<?>>(1);
      anns.add((AnnotationResult<?>) r);
      return anns;
    }
    if(r instanceof MultiResult) {
      return ClassGenericsUtil.castWithGenericsOrNull(List.class, ((MultiResult)r).filterResults(AnnotationResult.class));
    }
    return null;
  }

  /**
   * Collect all ordering results from a Result
   * 
   * @param r Result
   * @return List of ordering results
   */
  public static List<OrderingResult> getOrderingResults(Result r) {
    if (r instanceof OrderingResult) {
      List<OrderingResult> ors = new ArrayList<OrderingResult>(1);
      ors.add((OrderingResult) r);
      return ors;
    }
    if(r instanceof MultiResult) {
      return ((MultiResult)r).filterResults(OrderingResult.class);
    }
    return null;
  }

  /**
   * Collect all clustering results from a Result
   * 
   * @param r Result
   * @return List of clustering results
   */
  public static List<Clustering<?>> getClusteringResults(Result r) {
    if (r instanceof Clustering) {
      List<Clustering<?>> crs = new ArrayList<Clustering<?>>(1);
      crs.add((Clustering<?>) r);
      return crs;
    }
    if(r instanceof MultiResult) {
      return ClassGenericsUtil.castWithGenericsOrNull(List.class, ((MultiResult)r).filterResults(Clustering.class));
    }
    return null;
  }

  /**
   * Return all Iterable results
   * 
   * @param r Result
   * @return List of iterable results
   */
  public static List<IterableResult<?>> getIterableResults(Result r) {
    if (r instanceof IterableResult) {
      List<IterableResult<?>> irs = new ArrayList<IterableResult<?>>(1);
      irs.add((IterableResult<?>) r);
      return irs;
    }
    if(r instanceof MultiResult) {
      return ClassGenericsUtil.castWithGenericsOrNull(List.class, ((MultiResult)r).filterResults(IterableResult.class));
    }
    return null;
  }
  
  /**
   * Return all Metadata results
   * 
   * @param r Result
   * @return List of metadata results
   */
  public static List<MetadataResult> getMetadataResults(Result r) {
    if (r instanceof MetadataResult) {
      List<MetadataResult> irs = new ArrayList<MetadataResult>(1);
      irs.add((MetadataResult) r);
      return irs;
    }
    if(r instanceof MultiResult) {
      return ClassGenericsUtil.castWithGenericsOrNull(List.class, ((MultiResult)r).filterResults(MetadataResult.class));
    }
    return null;
  }
}

@@ -4621,32 +4621,604 @@
 turn null;%0A  %7D%0A%0A
+  /**%0A   * Collect all collection results from a Result%0A   * %0A   * @param r Result%0A   * @return List of collection results%0A   */%0A  public static List%3CCollectionResult%3C?%3E%3E getCollectionResults(Result r) %7B%0A    if (r instanceof CollectionResult) %7B%0A      List%3CCollectionResult%3C?%3E%3E crs = new ArrayList%3CCollectionResult%3C?%3E%3E(1);%0A      crs.add((CollectionResult%3C?%3E) r);%0A      return crs;%0A    %7D%0A    if(r instanceof MultiResult) %7B%0A      return ClassGenericsUtil.castWithGenericsOrNull(List.class, ((MultiResult)r).filterResults(CollectionResult.class));%0A    %7D%0A    return null;%0A  %7D%0A%0A
   /**%0A   * Retur

add getCollectionResults