package yi.iu.processor.color.reg.merge;

import yi.iu.img.*;
import java.awt.*;
import yi.ds.sum.*;
import yi.stat.hist.*;

/**
 * NeighboringCCInfo stores the neighboring information of a connected component
 * to others
 */

public class NeighboringCCInfo extends IndexedDoubleSummationHashMap{

  public int size;

  public NeighboringCCInfo() {
    super();
  }

  public NeighboringCCInfo(int size) {
    this();
    this.size = size;
  }

  /**
   * Return the distances of the neighboring CC.  For example, the neighboring
   * CC of a CC and the distance between them.
   * @param cc_labels
   * @param diffs
   * @param d
   * @param from_size_threshold the region (neighboring from) size threshold.
   *        use -1 if it should be ignored (only the regions with area < this
   *        threshold are considered)
   * @param to_size_threshold the region (neighboring to) size threshold.
   *        use -1 if it should be ignored (only the regions with area < this
   *        threshold are considered)
   * @return the array is indexed by the label of cc.  Each element of the array
   *         is a HashMap in which the key is the lable of the neighoring cc and
   *         value is the number of neighboring pixels and the total distance.
   *         For example,
   *         rst[3] = {4=>{4, 20.5}, 6=>{2, 15.3}} means cc3 is neighboring cc4
   *         and they have 4 neighboring pixels and the total distance is 20.5;
   *         cc3 is neighboring cc6 and they have 2 neighboring pixels and the
   *         total distance is 15.3
   */
  public static NeighboringCCInfo[] getNeighboringCCInfos(int[] cc_labels,
      DifferentialImage diffs, Dimension d, int from_size_threshold, int to_size_threshold) {
    // the number of labels
    int cc_label_num = yi.stat.StatUtil.maximum(cc_labels) + 1;


    // calculate the size of each connected component if size_threshold is
    // specified
    SimpleHistogram hist = new SimpleHistogram(cc_labels);
    int[] cc_sizes = hist.getHistogram();

    // the results
    NeighboringCCInfo[] results = new NeighboringCCInfo[cc_label_num];
    for (int i=0; i<results.length; i++) results[i] = new NeighboringCCInfo(cc_sizes[i]);

    // horizontal
    for (int y=0; y<d.height; y++) {
      for (int x=0, ptr=y*d.width; x<d.width-1; x++, ptr++) {
        double dist = diffs.getHorizontalDistance(x, y);
        int cc_label1 = cc_labels[ptr], cc_label2 = cc_labels[ptr + 1];
        int cc_size1 = results[cc_label1].size, cc_size2 = results[cc_label2].size;
        if ((from_size_threshold < 0 ||  cc_size1 < from_size_threshold) &&
            (to_size_threshold < 0 ||  cc_size2 < to_size_threshold)) {
          results[cc_label1].putToSum(cc_label2, dist);
        }
        if ((from_size_threshold < 0 ||  cc_size2 < from_size_threshold) &&
            (to_size_threshold < 0 ||  cc_size1 < to_size_threshold)) {
          results[cc_label2].putToSum(cc_label1, dist);
        }
      }
    }

    // vertical
    for (int y=0, ptr=0; y<d.height-1; y++) {
      for (int x=0; x<d.width; x++, ptr++) {
        double dist = diffs.getVerticalDistance(x, y);
        int cc_label1 = cc_labels[ptr], cc_label2 = cc_labels[ptr+d.width];
        int cc_size1 = results[cc_label1].size, cc_size2 = results[cc_label2].size;
        if ((from_size_threshold < 0 ||  cc_size1 < from_size_threshold) &&
            (to_size_threshold < 0 ||  cc_size2 < to_size_threshold)) {
          results[cc_label1].putToSum(cc_label2, dist);
        }
        if ((from_size_threshold < 0 ||  cc_size2 < from_size_threshold) &&
            (to_size_threshold < 0 ||  cc_size1 < to_size_threshold)) {
          results[cc_label2].putToSum(cc_label1, dist);
        }
      }
    }
    return results;
  }

}