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

import java.util.*;
import yi.ds.sum.*;
import yi.stat.hist.*;

/**
 * NeighboringLabelInfo gethers the informatin of neighboring regions of two
 * labels.  For example, an image is first labeled according to their color.
 * The information of the connecting relationship of labeled i regions and
 * labeled j regions includes: the number of the neighboring pixels, the
 * total distance between those neighboring pixels, the number and the area of
 * regions having label-i and neighbor regions having label-j
 */

public class NeighboringLabelInfo {

  public int neighboringInstNumber;
  public double neighboringInstDist;
  public int regionNum, regionArea;
  public int neighborAreaSum;

  public NeighboringLabelInfo() {
  }

  public NeighboringLabelInfo(
    int neighboringInstNumber, double neighboringInstDist,
    int regionNum, int regionArea, int neighborAreaSum) {
    this.neighboringInstNumber = neighboringInstNumber;
    this.neighboringInstDist = neighboringInstDist;
    this.regionNum = regionNum;
    this.regionArea = regionArea;
    this.neighborAreaSum = neighborAreaSum;
  }

  public static NeighboringLabelInfo[][] getNeighboringLabelInfo(
      int[] labels, int[] cc_labels, NeighboringCCInfo[] cc_dists, int small_area_threshold) {

    // the number of labels
    int label_num = yi.stat.StatUtil.maximum(labels) + 1;
    int cclabel_num = cc_dists.length;

    // the cc_labels -> labels map
    int[] cc_label_map = new int[cclabel_num];
    for (int i = 0; i < cc_labels.length; i++) {
      cc_label_map[cc_labels[i]] = labels[i];
    }


    NeighboringLabelInfo[][] neighbor_infos = new NeighboringLabelInfo[label_num][label_num];
    for (int i = 0; i < label_num; i++) {
      for (int j = 0; j < label_num; j++) {
        neighbor_infos[i][j] = new NeighboringLabelInfo();
      }
    }

    for (int i = 0; i < cclabel_num; i++) {

      int label_from = cc_label_map[i];

      HashSet connecting_labels = new HashSet();

      NeighboringCCInfo dists = cc_dists[i];

      for (Iterator it = dists.keySet().iterator(); it.hasNext(); ) {

        // the label of the region merged to
        Integer key = (Integer) it.next();
        int merge_to = key.intValue();

        DoubleSummationStruct dist_sum = (DoubleSummationStruct) dists.get(key);

        int label_to = cc_label_map[merge_to];

        neighbor_infos[label_from][label_to].neighboringInstNumber += dist_sum.counter;
        neighbor_infos[label_from][label_to].neighboringInstDist += dist_sum.total;
        int neighbor_size = cc_dists[merge_to].size;
        if (neighbor_size > small_area_threshold) neighbor_size = small_area_threshold;
        neighbor_infos[label_from][label_to].neighborAreaSum += neighbor_size;
        connecting_labels.add(new Integer(label_to));
      }

      // deal with connecting labels
      for (Iterator it = connecting_labels.iterator(); it.hasNext(); ) {
        int label_to = ((Integer)it.next()).intValue();
        neighbor_infos[label_from][label_to].regionNum ++;
        neighbor_infos[label_from][label_to].regionArea += dists.size;
      }
    }

    return neighbor_infos;
  }

}