package yi.iu.ft.local;

import java.util.*;
import yi.stat.hist.Hist;
import weka.core.Attribute;

/**
 * A simple implementation of globalization template (class GlobalizationTempl)
 */
public class GlobalizationTemplImpl implements GlobalizationTempl {
  public final static String ALL  = "ALL";
  public final static String NONE = "NONE";
  /**
   * number of attributes
   */
  public int m_attributeNum;
  /**
   * minimum value of the attributes
   */
  public double[]   m_mins;
  /**
   * bin size of the attributes
   */
  public double[]   m_binSizes;
  /**
   *
   */
  public int[]   m_binNums;
  /**
   *
   */
  public Vector[] m_histStats;

  public GlobalizationTemplImpl() {
  }


  public GlobalizationTemplImpl(int anum) {
    m_attributeNum = anum;
    m_mins = new double[anum];
    m_binNums = new int[anum];
    m_binSizes = new double[anum];
    m_histStats = new Vector[anum*anum];
  }

  public Iterator listStatsOn(int a1, int a2) {
    Vector stats = m_histStats[indexOfPair(a1, a2, m_attributeNum)];
    if (stats == null) return null;
    return stats.iterator();
  }

  /**
   * Add statistical calculation on a pair of attributes.  The first attribute
   * is for the base of the histogram; the second one is for the statistics.
   * For example, Hist.MEAN on x, y attribute pair is a good measure for region
   * position.  (150,200), (160, 170), (155, 185) on a 200*200 image, if based
   * on x with 4 bins, the histogram is (-, -, -, 185)
   * @param a1 the index of the first attribute (for histogram base)
   * @param a2 the index of the second attribute (for statistics)
   * @param stat the information type. (Globalization.ALL, Globalization.NONE,
   *             Hist.COUNT, Hist.MAX, Hist.MIN, Hist.MEAN, Hist.STERR)
   */
  public void addStatsOn(int a1, int a2, String stat) {
    Vector stats = m_histStats[indexOfPair(a1, a2, m_attributeNum)];
    if (stats == null) stats = new Vector();
    if (stat.compareTo(ALL)==0) {
      stats.add(Hist.COUNT);
      stats.add(Hist.MAX);
      stats.add(Hist.MIN);
      stats.add(Hist.MEAN);
      stats.add(Hist.STERR);
    }
    else if (stat.compareTo(NONE)!=0) {
      stats.add(stat);
    }
    m_histStats[indexOfPair(a1, a2, m_attributeNum)] = stats;
  }

  public double getMinOn(int a) {
    return m_mins[a];
  }

  public int getBinNumOn(int a) {
    return m_binNums[a];
  }

  public double getBinSizeOn(int a) {
    return m_binSizes[a];
  }

  /**
   * Set the histogram property for an attribute.  For example, to set the third
   * attribute (index =2, 0-based) to make a histogram with 4 bins of [0,64),
   * [64,128),[128,192), and [192,256), use:
   * setAttributeOn(2, 0, 64, 4)
   * @param a the index of the attribute
   * @param min the minmum value of the attribute
   * @param bsize the size of one bin
   * @param bnum the number of bins.
   */
  public void setAttributeOn(int a, double min, double bsize, int bnum) {
    m_mins[a] = min;
    m_binNums[a] = bnum;
    m_binSizes[a] = bsize;
  }

  public int getNumHistAttr() {
    int sum = 0;
    for (int i=0; i<m_attributeNum; i++) {
      for (int j=0; j<m_attributeNum; j++) {
        sum += m_histStats[indexOfPair(i, j, m_attributeNum)].size() * m_binNums[i];
      }
    }
    return sum;
  }

  public Vector getHistAttrNames(Vector localAttrs) {
    Vector names = new Vector();
    for (int i=0; i<m_attributeNum; i++) {
      String i_str = ((Attribute)localAttrs.get(i)).name();
      for (int j=0; j<m_attributeNum; j++) {
        String j_str = ((Attribute)localAttrs.get(j)).name();
        Vector stats = m_histStats[indexOfPair(i, j, m_attributeNum)];
        for (int k=0; k<stats.size(); k++) {
          String stat_str = (String)stats.get(k);
          for (int l=0; l<m_binNums[i]; l++) {
            if (i==j && stat_str.compareTo(Hist.COUNT) == 0) {
              // abbreviate for count case
              names.add(i_str + '_' + l*m_binSizes[i]);
            } else {
              names.add(i_str + '_' + l*m_binSizes[i] + '_' + j_str + '_' + stat_str);
            }
          }
        }
      }
    }
    return names;
  }

  /**
   * Make an integer index for an integer pair (a, b).  Known the size of the
   * second dimension, the index = a*bsize+b;
   * @param a
   * @param b
   * @param bsize
   * @return
   */
  int indexOfPair(int a, int b, int bsize) {
    return (a * bsize + b);
  }

  public int getAttributeNum() { return m_attributeNum;}
  public void setAttributeNum(int anum) {
    m_attributeNum = anum;
  }
  public double[] getMins() { return m_mins;}
  public void setMins(double[] mins) {m_mins = mins;}
  public int[] getBinNums() { return m_binNums;}
  public void setBinNums(int[] binNums) {m_binNums = binNums;}
  public double[] getBinSizes() { return m_binSizes;}
  public void setBinSizes(double[] binSizes) {m_binSizes = binSizes;}
  public Vector[] getHistStats() { return m_histStats;}
  public void setHistStats(Vector[] histStats) {m_histStats = histStats;}

}