package yi.iu.processor.clc;

import java.util.*;

import yi.ai.cluster.*;
import yi.iu.processor.ort.*;
import yi.util.config.*;
import yi.util.io.*;

/**
 * Construct Length Consistent Line Cluster.
 */
public class CLC_Length extends CLC_Clustering
{

  /**
   * When doing histogram analysis (histogram based clustering), the histogram
   * will be first smoothed by Gussian.  This is the sigma used in Gussian
   * smoothing.
   */
  public double HIST_SMOOTH_GAUSSIAN_SIGMA = 4;

  /**
   * When finding the histogram peaks to clustering the data, we only pick up
   * the peaks having high quality.  This is the quality threshold
   */
  public double HIST_PEAK_QUALITY_THRESHOLD = 0;


  public CLC_Length() {
    Configuration.configParameters(this);
  }

  public boolean DEMO_LENGTH_CLUSTERING = false;

  public String[] getParameterNames() {
    return super.getParameterNames(new String[] {
      "HIST_SMOOTH_GAUSSIAN_SIGMA",
      "DEMO_LENGTH_CLUSTERING",
    });
  }


  /**
   * Clustering the lines using their length information.
   * @param lines
   * @param rgb
   * @param width
   * @param height
   * @return
   */
  public LineClusterSets getClusters(LineClusterSet lines, int[] rgb, int width, int height) {

    // use DistanceCluster to cluster the lines according to their length

    // new length array of the lines
    int[][] lengths = new int[lines.size()][1];
    Iterator i = lines.iterator();
    int count = 0;
    while (i.hasNext()) {
      ORTLine l = (ORTLine)i.next();
      lengths[count++][0] = (int)Math.round(l.Length);
    }

    // clustering using DistanceCluster
    DistanceCluster clustering = new DistanceCluster();
    Clusters clusters = clustering.clustering(lengths, 1, 4);
    int[] cluster_map = clusters.getClusterMap();

    // new line cluster sets
    LineClusterSets line_clusters = new LineClusterSets(width, height);
    i = lines.iterator();
    count = 0;
    while (i.hasNext()) {
      ORTLine l = (ORTLine)i.next();
      line_clusters.add(new Integer(cluster_map[count++]), l);
    }

//    // OneDHistBasedCluster to cluster the lines according to their length
//
//    // construct the histogram of the length of the lines
//    double[] hist = constructLengthHist(lines);
//    OneDClusters clusters = OneDHistBasedCluster.localMaximaGuidedHistClustering(
//      hist, HIST_SMOOTH_GAUSSIAN_SIGMA, HIST_PEAK_QUALITY_THRESHOLD, false);
//    DataRange[] ranges = clusters.getClusters();
//
//    // new line cluster sets
//    LineClusterSets line_clusters = new LineClusterSets();
//
//    Iterator i = lines.iterator();
//    while (i.hasNext()) {
//      ORTLine l = (ORTLine)i.next();
//      int length = lengthHistBinNum(l);
//      // which cluster the line belongs to
//      int label = clusters.getLabel(length);
//      if (label < 0) continue;  // it doesn't belong to any cluster
//      // put it in
//      line_clusters.add(ranges[label], l);
//    }

    // filter the result
    line_clusters.filter(
      CLCConfig.getMinQualifiedLineLen(),
      CLCConfig.getMinQualifiedCLCLineLenSum(width, height));

    // inherit the properties from the parent (clustered from)
    line_clusters.inheritProperties(lines);

    // demo the consistent line clusters before roughly orientation clustering
    if (DEMO_LENGTH_CLUSTERING) {
      int[] lineimg = lines.demo();
      String img_name = Configuration.getStringParameter("SOURCE_NAME", "unknown");
      OutputResult.outputGIFImage(img_name + ".length_clustering", lineimg, width, height, true);
    }

    // demo the roughly orientation consistent line clusters
    if (DEMO_LENGTH_CLUSTERING) {
      int[] lineimg = line_clusters.demo(width, height);
      String img_name = Configuration.getStringParameter("SOURCE_NAME", "unknown");
      OutputResult.outputGIFImage(img_name + ".length_clustering", lineimg, width, height, true);
    }

    return line_clusters;
  }

  /**
   * Construct the length histogram of given lines
   * @param lines
   * @return
   */
  double[] constructLengthHist(LineClusterSet lines) {

    // the histogram
    int bin_num = lengthHistBinNum(lines.getMaxLengthLine()) + 1;
    double[] hist = new double[bin_num];

    Iterator i = lines.iterator();
    while (i.hasNext()) {
      ORTLine l = (ORTLine)i.next();

      // quatilize the angle of the line
      int bin_index = lengthHistBinNum(l);

      hist[bin_index] ++;
    }
    return hist;
  }

  /**
   * Return the bin number for the given line in the length histogram
   * @param l
   * @return
   */
  int lengthHistBinNum(ORTLine l) {

    int length = (int)Math.round(l.Length);

    return length;
  }

}