package yi.iu.processor.texture.reg;

import java.io.*;
import java.io.File;

import yi.iu.ft.local.*;
import yi.iu.region.*;
import yi.stat.hist.*;
import yi.util.config.*;
import yi.util.io.*;
import yi.util.io.input.*;
import yi.ds.sort.*;
import java.util.*;



public class DS_ChromaticGaborTextureRegions extends DS_GaborTextureRegions {

  final static String[] QUANTIZER_IDS = new String[] {"quan", "quan1", "quan2"};

  QuantizeTemplate m_quantizeTemplate = new QuantizeTemplate(
    // quantized bin numbers
    new int[]{
      5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,
      5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,
      5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,
      4 ,4 ,4 ,4 ,9,
      2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,2 ,
      2 ,2 ,2 ,2 ,2 ,2 ,166,166,166,166,
    },
    // bin name prefixs
    new String[]{
      "g01", "g02", "g03", "g04", "g05", "g06", "g07", "g08", "g09", "g10",
      "g11", "g12", "g13", "g14", "g15", "g16", "g17", "g18", "g19", "g20",
      "g21", "g22", "g23", "g24", "g25", "g26", "g27", "g28", "g29", "g30",
      "x", "y", "l", "o", "s",
      "c01", "c02", "c03", "c04", "c05", "c06", "c07", "c08", "c09", "c10",
      "c11", "c12", "c13", "c14", "c15", "c16", "dc1", "dc2", "dc3", "mc",
    },
    // quantizer short name
    "ctext",
    // quantizer id name: quan
    QUANTIZER_IDS[0]
  );

  QuantizeTemplate m_quantizeTemplate1 = new QuantizeTemplate(
    // quantized bin numbers
    new int[]{
      5 ,5 ,5 ,5 ,5 ,
      4 ,4 ,4 ,4 ,4,
      16,
    },
    // bin name prefixs
    new String[]{
      "g01", "g02", "g03", "g04", "g05",
      "x", "y", "l", "o", "s",
      "dc",
    },
    // quantizer short name
    "ctext",
    // quantizer id name: quan1
    QUANTIZER_IDS[1]
  );

  QuantizeTemplate m_quantizeTemplate2 = new QuantizeTemplate(
    // quantized bin numbers
    new int[]{
      10 ,10 ,10 ,10 ,10 ,10 ,10 ,10 ,10 ,10 ,
      10 ,10 ,
      4 ,4 ,4 ,4 ,4,
      16,
    },
    // bin name prefixs
    new String[]{
      "g01", "g02", "g03", "g04", "g05", "g06", "g07", "g08", "g09", "g10",
      "g11", "g12",
      "x", "y", "l", "o", "s",
      "dc",
    },
    // quantizer short name
    "ctext",
    // quantizer id name: quan
    QUANTIZER_IDS[2]
  );

  public double COLOR_HIST_THRESHOLD = 0.3;

  public DS_ChromaticGaborTextureRegions() {
    super();
  }

  public DS_ChromaticGaborTextureRegions(DS_GaborTextureRegions gabor_texture_regions) {
    super(
      gabor_texture_regions.m_imgWidth,
      gabor_texture_regions.m_imgHeight,
      gabor_texture_regions.m_scale,
      gabor_texture_regions.m_gaborTextureRegions);
  }

  public QuantizeTemplate getQuantizeTemplate(String quantizer_id) {
    if (quantizer_id.compareToIgnoreCase(QUANTIZER_IDS[0]) == 0) {
      return m_quantizeTemplate;
    }
    if (quantizer_id.compareToIgnoreCase(QUANTIZER_IDS[1]) == 0) {
      return m_quantizeTemplate1;
    }
    if (quantizer_id.compareToIgnoreCase(QUANTIZER_IDS[2]) == 0) {
      return m_quantizeTemplate2;
    }
    System.err.println("quantize method is not defined in DS_ChromaticGaborTextureRegions: " + quantizer_id);
    return null;
  }

  public QuantizedFeature getQuantized(String quantizer_id) {
    if (quantizer_id.compareToIgnoreCase(QUANTIZER_IDS[0]) == 0) {
      return getQuantized();
    }
    if (quantizer_id.compareToIgnoreCase(QUANTIZER_IDS[1]) == 0) {
      return getQuantized1();
    }
    if (quantizer_id.compareToIgnoreCase(QUANTIZER_IDS[2]) == 0) {
      return getQuantized2();
    }
    System.err.println("quantize method is not defined in DS_ChromaticGaborTextureRegions: " + quantizer_id);
    return null;
  }

  /**
   * Return the quantized feature instances for one case.
   * @return
   */
  public QuantizedFeature getQuantized() {
    if (m_gaborTextureRegions == null) return new QuantizedFeature(0, ATTRIBUTE_NUM);

    Quantizer gaborQuantizer = new yi.stat.hist.LogarithmicQuantizer(2, QUANTIZED_BIN_NUMS[0]);

    Quantizer[] quantizers = new Quantizer[ATTRIBUTE_NUM];
    for (int i=0; i<30; i++) quantizers[i] = gaborQuantizer;  // for Gabor data
    quantizers[30] = new LinearQuantizer(
      0, m_imgWidth/QUANTIZED_BIN_NUMS[30], QUANTIZED_BIN_NUMS[30], true); // for centroid_x;
    quantizers[31] = new LinearQuantizer(
      0, m_imgHeight/QUANTIZED_BIN_NUMS[31], QUANTIZED_BIN_NUMS[31], true); // for centroid_y;
    quantizers[32] = new LinearQuantizer(
      0, Math.max(m_imgHeight, m_imgWidth)/QUANTIZED_BIN_NUMS[32], QUANTIZED_BIN_NUMS[32], true); // for elongation;
    quantizers[33] = new LinearQuantizer(
      -Math.PI/8, Math.PI/QUANTIZED_BIN_NUMS[33], QUANTIZED_BIN_NUMS[33], true, true); // for direction;
    quantizers[34] = new LinearQuantizer(
      0, m_imgHeight * m_imgWidth/QUANTIZED_BIN_NUMS[34], QUANTIZED_BIN_NUMS[34], true); // for size;

    Quantizer color_hist_quantizer = new LinearQuantizer(0, COLOR_HIST_THRESHOLD, 2, true); // for color histogram
    for (int i=35; i<51; i++) quantizers[i] = color_hist_quantizer;  // for color histogram

    Quantizer dummy_quarter = new DummyQuantizer();
    for (int i=51; i<55; i++) quantizers[i] = dummy_quarter;  // for major colors and mean color

    // quantize each line
    QuantizedFeature quantized = new QuantizedFeature(m_gaborTextureRegions.length, ATTRIBUTE_NUM);
    for (int i = 0; i<m_gaborTextureRegions.length; i++) {
      GaborTextureRegion region = m_gaborTextureRegions[i];
      double[] gabor_data = region.getGabor();
      double[] values = new double[ATTRIBUTE_NUM];
      Region r = region.getRegion();
      for (int j=0; j<gabor_data.length; j++) values[j] = gabor_data[j];
      values[30] = r.m_centroidX;
      values[31] = r.m_centroidY;
      values[32] = r.m_majLength;
      values[33] = r.m_majAngle;
      values[34] = r.m_size;

      // deal with the color part
      if (region instanceof ChromaticGaborTextureRegion) {
        ChromaticGaborTextureRegion color_region = (ChromaticGaborTextureRegion) region;
        // the color histogram
        int[] chromaticHist = color_region.m_chromaticHist;
        for (int j=0; j<chromaticHist.length; j++) {
          values[35 + j] = (double)chromaticHist[j]/r.m_size;
        }

        // the dominant colors (major colors)
        int[] color_hist = color_region.m_colorHist;
        TopKeeper top3 = new TopKeeper(3);
        for (int j=0; j<color_hist.length; j++) {
          top3.insert(new Integer(j), color_hist[j]);
        }
        Vector tops = top3.getTopObjects();
        for (int j=0; j<Math.min(tops.size(), 3); j++) {
          int color_index = ((Integer)tops.elementAt(j)).intValue();
          values[51 + j] = color_index;
        }

        // the mean color
        int rgb = color_region.m_meanColor;
        int mean_color_index = yi.iu.processor.color.quan.SmithColorQuantization.quantize(rgb);
        values[54] = mean_color_index;
      }

      // set the result
      for (int j=0; j<values.length; j++) {
        quantized.setQuantized(i, j, quantizers[j].quantize(values[j]));
      }

    }
    return quantized;
  }

  /**
   * Return the quantized feature instances for one case.
   * @return
   */
  public QuantizedFeature getQuantized1() {

    int ATTRIBUTE_NUM = m_quantizeTemplate1.getAttributeNum();
    int[] QUANTIZED_BIN_NUMS = m_quantizeTemplate1.getQuantizedBinNums();

    if (m_gaborTextureRegions == null) return new QuantizedFeature(0, ATTRIBUTE_NUM);

    // set the quantizers first
    Quantizer[] quantizers = new Quantizer[ATTRIBUTE_NUM];

    // for Gabor data
    Quantizer gaborQuantizer = new yi.stat.hist.LogarithmicQuantizer(2, QUANTIZED_BIN_NUMS[0]);
    for (int i=0; i<5; i++) quantizers[i] = gaborQuantizer;

    quantizers[5] = new LinearQuantizer(
      0, m_imgWidth/QUANTIZED_BIN_NUMS[5], QUANTIZED_BIN_NUMS[5], true); // for centroid_x;
    quantizers[6] = new LinearQuantizer(
      0, m_imgHeight/QUANTIZED_BIN_NUMS[6], QUANTIZED_BIN_NUMS[6], true); // for centroid_y;
    quantizers[7] = new LinearQuantizer(
      0, Math.max(m_imgHeight, m_imgWidth)/QUANTIZED_BIN_NUMS[7], QUANTIZED_BIN_NUMS[7], true); // for elongation;
    quantizers[8] = new LinearQuantizer(
      -Math.PI/8, Math.PI/QUANTIZED_BIN_NUMS[8], QUANTIZED_BIN_NUMS[8], true, true); // for direction;
    quantizers[9] = new LinearQuantizer(
      0, m_imgHeight * m_imgWidth/QUANTIZED_BIN_NUMS[9], QUANTIZED_BIN_NUMS[9], true); // for size;
    quantizers[10] = new DummyQuantizer();

    // quantize each region
    QuantizedFeature quantized = new QuantizedFeature(m_gaborTextureRegions.length, ATTRIBUTE_NUM);
    for (int i = 0; i<m_gaborTextureRegions.length; i++) {

      // the values to be quantized
      double[] values = new double[ATTRIBUTE_NUM];

      ChromaticGaborTextureRegion region = (ChromaticGaborTextureRegion)m_gaborTextureRegions[i];
      Region r = region.getRegion();
      double[] gabor_data = region.getGabor();

      // quantize Gabor data.  One data per Scale (combine orientation)
      int count = 0;
      for (int s=0; s<5; s++) { // scale = 5
        double max = 0;
        for (int o=0; o<6; o++, count++) { // orientation
          if (max < gabor_data[count]) max = gabor_data[count];
        }
        values[s] = max;
      }

      values[5] = r.m_centroidX;  // x
      values[6] = r.m_centroidY;  // y
      values[7] = r.m_majLength;  // length
      values[8] = r.m_majAngle;   // orientation
      values[9] = r.m_size;       // size

      // color
      int[] color_hist = region.m_chromaticHist;
      int major_color = 0;
      int color_count = 0;
      for (int j=0; j<color_hist.length; j++) {
        if (color_hist[j] > color_count) {
          color_count = color_hist[j];
          major_color = j;
        }
      }
      if (color_count == 0) { // no color qualify for the color hist, use mean color
        ColorGuidedTextureSeg colo_quantizer = new ColorGuidedTextureSeg();
        major_color = colo_quantizer.quantizeRgb(region.m_meanColor);
      }
      values[10] = major_color;

      // set the result
      for (int j=0; j<values.length; j++) {
        int quantized_value = quantizers[j].quantize(values[j]);
        quantized.setQuantized(i, j, quantized_value);
        if (j!=0) System.out.print(",");
        System.out.print(Double.toString(values[j]) + "->" + quantized_value);
      }
      System.out.println();

    }
    return quantized;
  }

  /**
   * Return the quantized feature instances for one case.
   * @return
   */
  public QuantizedFeature getQuantized2() {

    int ATTRIBUTE_NUM = m_quantizeTemplate2.getAttributeNum();
    int[] QUANTIZED_BIN_NUMS = m_quantizeTemplate2.getQuantizedBinNums();

    if (m_gaborTextureRegions == null) return new QuantizedFeature(0, ATTRIBUTE_NUM);

    // set the quantizers first
    Quantizer[] quantizers = new Quantizer[ATTRIBUTE_NUM];

    // for Gabor data
    Quantizer gaborQuantizer = new LinearQuantizer(0, 1.0/3, QUANTIZED_BIN_NUMS[0], true);
    for (int i=0; i<12; i++) quantizers[i] = gaborQuantizer;

    quantizers[12] = new LinearQuantizer(
      0, m_imgWidth/QUANTIZED_BIN_NUMS[12], QUANTIZED_BIN_NUMS[12], true); // for centroid_x;
    quantizers[13] = new LinearQuantizer(
      0, m_imgHeight/QUANTIZED_BIN_NUMS[13], QUANTIZED_BIN_NUMS[13], true); // for centroid_y;
    quantizers[14] = new LinearQuantizer(
      0, Math.max(m_imgHeight, m_imgWidth)/QUANTIZED_BIN_NUMS[14], QUANTIZED_BIN_NUMS[14], true); // for elongation;
    quantizers[15] = new LinearQuantizer(
      -Math.PI/8, Math.PI/QUANTIZED_BIN_NUMS[15], QUANTIZED_BIN_NUMS[15], true, true); // for direction;
    quantizers[16] = new LinearQuantizer(
      0, m_imgHeight * m_imgWidth/QUANTIZED_BIN_NUMS[16], QUANTIZED_BIN_NUMS[16], true); // for size;
    quantizers[17] = new DummyQuantizer();

    // quantize each region
    QuantizedFeature quantized = new QuantizedFeature(m_gaborTextureRegions.length, ATTRIBUTE_NUM);
    for (int i = 0; i<m_gaborTextureRegions.length; i++) {

      // the values to be quantized
      double[] values = new double[ATTRIBUTE_NUM];

      ChromaticGaborTextureRegion region = (ChromaticGaborTextureRegion)m_gaborTextureRegions[i];
      Region r = region.getRegion();
      double[] gabor_data = region.getGabor();

      // quantize Gabor data.
      for (int j=0; j<gabor_data.length; j++) values[j] = gabor_data[j];

      values[12] = r.m_centroidX;  // x
      values[13] = r.m_centroidY;  // y
      values[14] = r.m_majLength;  // length
      values[15] = r.m_majAngle;   // orientation
      values[16] = r.m_size;       // size

      // color
      int[] color_hist = region.m_chromaticHist;
      int major_color = 0;
      int color_count = 0;
      for (int j=0; j<color_hist.length; j++) {
        if (color_hist[j] > color_count) {
          color_count = color_hist[j];
          major_color = j;
        }
      }
      if (color_count == 0) { // no color qualify for the color hist, use mean color
        ColorGuidedTextureSeg colo_quantizer = new ColorGuidedTextureSeg();
        major_color = colo_quantizer.quantizeRgb(region.m_meanColor);
      }
      values[17] = major_color;

      // set the result
      for (int j=0; j<values.length; j++) {
        int quantized_value = quantizers[j].quantize(values[j]);
        quantized.setQuantized(i, j, quantized_value);
        if (j!=0) System.out.print(",");
        System.out.print(Double.toString(values[j]) + "->" + quantized_value);
      }
      System.out.println();

    }
    return quantized;
  }

  public static class Quantize {
    public static void main(String[] args) {
      // init configuration
      Configuration.init(args);

      // get the image name
      String img_name = ReadArgu.getOption('i', args);

      // get the quantizer id
      String quantizer_id = ReadArgu.getOption('q', args);
      if (quantizer_id == null) quantizer_id = QUANTIZER_IDS[0];


      if (img_name != null) {

        img_name = img_name + ".s256";

        Configuration.setParameter("SOURCE_NAME", img_name);

        String globalization_file_name = img_name + ".DS_ChromaticGaborTextureRegions." + quantizer_id;

        DS_ChromaticGaborTextureRegions dummy = new DS_ChromaticGaborTextureRegions();

        // check whether need redo
        if (!dummy.REDO_QUANTIZE) {
          File globalization_file = new File(globalization_file_name);
          if (globalization_file.exists()) {
            System.out.println(globalization_file_name + " exists.  Skip");
            System.exit(0);
          }
        }

        try {
          // get local features
          DS_GaborTextureRegions rst = (DS_GaborTextureRegions)DIU.in(
            DIU.INPUT_XML,
            "ColorGuidedTextureSeg",
            "DS_GaborTextureRegions",
            Class.forName("yi.iu.processor.texture.reg.DS_GaborTextureRegions"));

          // convert DS_GaborTextureRegions to DS_ChromaticGaborTextureRegion
          DS_ChromaticGaborTextureRegions color_rst = new DS_ChromaticGaborTextureRegions(rst);
          // get global histogram
          QuantizedFeature quan = color_rst.getQuantized(quantizer_id);

          ObjectOutputStream out = new ObjectOutputStream(
            new BufferedOutputStream(new FileOutputStream(globalization_file_name)));
          out.writeObject(quan);
          out.close();

          System.out.println(quan);
        }
        catch (Exception e) {
          System.err.println("broken in generating " + globalization_file_name);
          e.printStackTrace();
        }
      }
      System.exit(0);
    }
  }

  int getHistogramIndex(int[] bin_index, int[] bin_nums) {
    int index = 0;
    int base = 1;
    for (int i = bin_nums.length - 1; i >= 0; i --) {
      index += bin_index[i] * base;
      base *= bin_nums[i];
    }
    return index;
  }

  public static int FTH1_BIN_NUM = 16 * 25 * 4 * 4; // color, texture, size, orientation

  public GlobalHistogram getGlobalized_FTH1(){

//    // output the feature for considering the quantiz
//    for (int i = 0; i<m_gaborTextureRegions.length; i++) {
//      GaborTextureRegion region = m_gaborTextureRegions[i];
//      double[] gabor_data = region.getGabor();
//      for (int j=0; j<gabor_data.length; j++) System.out.print("\t" + gabor_data[j]);
//      System.out.println();
//    }

    // store the histogram
    int[] region_num = new int[FTH1_BIN_NUM];

    double[] values = new double[5];

    Quantizer[] quantizers = new Quantizer[] {
      new DummyQuantizer(), // color
      new yi.stat.hist.LogarithmicQuantizer(2, 5),  // g1
      new yi.stat.hist.LogarithmicQuantizer(2, 5),  // g2
      new LinearQuantizer(-Math.PI/8, Math.PI/4, 4, true, true), // for direction;
      new LinearQuantizer(0, m_imgHeight * m_imgWidth/4, 4, true), // for size;
    };

    int[] quantized = new int[5];

    int[] bin_nums = new int[] {16, 5, 5, 4, 4};

    // construct the histogram
    for (int i = 0; i<m_gaborTextureRegions.length; i++) {
      ChromaticGaborTextureRegion region = (ChromaticGaborTextureRegion)m_gaborTextureRegions[i];
      // color
      int[] color_hist = region.m_chromaticHist;
      int major_color = 0;
      int color_count = 0;
      for (int j=0; j<color_hist.length; j++) {
        if (color_hist[j] > color_count) {
          color_count = color_hist[j];
          major_color = j;
        }
      }
      if (color_count == 0) { // no color qualify for the color hist, use mean color
        ColorGuidedTextureSeg colo_quantizer = new ColorGuidedTextureSeg();
        major_color = colo_quantizer.quantizeRgb(region.m_meanColor);
      }
      values[0] = major_color;

      double[] gabor_data = region.getGabor();
      // gabor data for scale 1
      double g1 = gabor_data[0];
      for (int j=0; j<6; j++) if (g1 < gabor_data[j]) g1 = gabor_data[j];
      // gabor data for scale 2
      double g2 = gabor_data[6];
      for (int j=6; j<12; j++) if (g2 < gabor_data[j]) g2 = gabor_data[j];
      values[1] = g1;
      values[2] = g2;

      values[3] = region.getRegion().m_majAngle;
      values[4] = region.getRegion().m_size;

      // set the result
      for (int j=0; j<values.length; j++) {
        quantized[j] = quantizers[j].quantize(values[j]);
        if (j!=0) System.out.print(",");
        System.out.print(Double.toString(values[j]) + "->" + quantized[j]);
      }
      int index = getHistogramIndex(quantized, bin_nums);
      System.out.println(" ==> " + index);
      region_num[index] ++;
    }

    // construct the global histogram
    GlobalHistogram global_hist = new GlobalHistogram();
    for (int j=0; j<FTH1_BIN_NUM; j++) {
      global_hist.add(new Integer(region_num[j]));
    }
    return global_hist;
  }
/*
  public static class Globalize {
    public static void main(String[] args) {
      // init configuration
      Configuration.init(args);

      // get the image name
      String img_name = ReadArgu.getOption('i', args);
      if (img_name == null) {
        System.err.println("Usage: -i image_name");
        System.exit(1);
      }

      img_name = img_name + ColorGuidedTextureSeg.ResizeFirst.RESIZED_FILE_SUFFIX +
        ColorGuidedTextureSeg.ResizeFirst.IMAGE_RESIZED;

      Configuration.setParameter("SOURCE_NAME", img_name);

      try {
        // get local features
        DS_GaborTextureRegions rst = (DS_GaborTextureRegions)DIU.in(
            DIU.INPUT_XML,
            "ColorGuidedTextureSeg",
            "DS_GaborTextureRegions",
            Class.forName("yi.iu.processor.texture.reg.DS_GaborTextureRegions"));

        // convert DS_GaborTextureRegions to DS_ChromaticGaborTextureRegion
        DS_ChromaticGaborTextureRegions color_rst = new DS_ChromaticGaborTextureRegions(rst);

        // get global histogram
        GlobalHistogram g = color_rst.getGlobalized();
        PrintStream out = new PrintStream (
          new FileOutputStream(img_name + ".DS_ChromaticGaborTextureRegions." +
                               rst.GLOBALIZE_SUFFIX[rst.GLOBALIZE_METHOD]));
        g.output(out);
        out.close();
      }
      catch (Exception e) {
        e.printStackTrace();
      }
      System.exit(0);
    }
  }
      */
}