package yi.iu.ft;

import yi.util.config.*;
import yi.util.io.*;
import java.io.*;
import java.util.*;
import yi.util.data.*;
import yi.stat.hist.*;

public class Combine4Learning {
  static String USAGE = "Usage: -i image_list_file_name -f feature_list_file_name -t target_object_for_learning -o output_root";
  static String IS_TARGET_OBJECT = new String("1");
  static String IS_NOT_TARGET_OBJECT = new String("0");

  /**
   * Return the categories of all the given images.  If an image is positive
   * (has at least one of the target objects), the corresponding returning
   * string is as defined in IS_TARGET_OBJECT; otherwise, IS_NOT_TARGET_OBJECT
   * @param img_names
   * @param targets
   * @return
   * @throws IOException
   */
  static String[] readCategories(String[] img_names, String targets){
    String[] categories = new String[img_names.length];

    String[] target_objs = StringUtil.getDeliminatedStrings(targets, ",", true);

    // for each image
    for (int i=0; i<img_names.length; i++) {
      String short_name = yi.util.io.File.getShortName(img_names[i]);
      // the description file
      String description_file = yi.util.io.File.getPath(img_names[i]) + '/' + "descriptions.txt";
      // read decription file
      String[] descriptions = null;

      categories[i] = IS_NOT_TARGET_OBJECT;
      try {
        descriptions = ReadArgu.readStrings(description_file);
      } catch (IOException e) { // descriptions.txt not exist
        System.out.println("can't find " + description_file);
        continue;
      }

      for (int j=0; j<descriptions.length; j++) {
        // find the line corresponding to the image
        if (descriptions[j].toUpperCase().indexOf(short_name.toUpperCase()) >= 0) {
          int index_of_colon = descriptions[j].indexOf(":");
          if (index_of_colon < 0) {
            continue;
          }
          String objects_line = descriptions[j].substring(index_of_colon + 1);
          System.out.println(objects_line);
          String[] objects = StringUtil.getDeliminatedStrings(objects_line, ",", true);
          // search all the target strings
          boolean found = false;
          for (int k=0; k<target_objs.length; k++) {
            for (int l=0; l<objects.length; l++) {
              if (objects[l].compareToIgnoreCase(target_objs[k]) == 0) {
                categories[i] = IS_TARGET_OBJECT;
                System.out.print(objects[l] + " ");
                found = true;
                break;
              }
            }
            if (found) break;
          }
          System.out.println(categories[i]);
          break;
        }
      }
      if (categories[i] == null) {
        System.out.println("Can't find the descriptions for " + img_names[i]);
      }
    }
    return categories;
  }

  /**
   * Output data file for features learning.
   * @param out
   * @param img_names
   * @param ft_names
   * @param categories
   * @param feature_length the feature length.  If the length is set to 0, then
   *        the value will be learned from feature files; otherwise, it will be
   *        compared with each feature's real length and the mismatches will be
   *        reported
   * @return
   */
  static int outputDataFile(PrintStream out, String[] img_names, String[] ft_names, String[] categories, int feature_length) {

    // for each image
    for (int i=0; i<img_names.length; i++) {
      int current_feature_length = 0;

      // for each features
      for (int j=0; j<ft_names.length; j++) {
        // image feature file
        String img_ft_file_name = img_names[i] + '.' + ft_names[j];
        // read in the data
        String[] features = null;

        try {
          features = yi.util.io.ReadArgu.readStrings(img_ft_file_name);
        } catch (IOException e) {
          System.err.println("Can't read from file: " + img_ft_file_name);
          e.printStackTrace();
          continue;
        }

        // output
        if (j !=0) out.print(',');
        out.print(features[0]);

        // feature length
        StringTokenizer tokenizer = new StringTokenizer(features[0], ",");
        current_feature_length += tokenizer.countTokens();
      }
      // output category
      out.println(',' + categories[i]);

      // feature length
      if (feature_length == 0) feature_length = current_feature_length;
      else if (feature_length != current_feature_length) {
        System.err.println("the feature length is not the same: " + current_feature_length + ", should be: " + feature_length);
        System.err.println("  " + img_names[i]);
      }
    }
    return feature_length;

  }

  /**
   * Output data file for features learning.
   * @param out
   * @param img_names
   * @param ft_names
   * @param categories
   * @param feature_length the feature length.  If the length is set to 0, then
   *        the value will be learned from feature files; otherwise, it will be
   *        compared with each feature's real length and the mismatches will be
   *        reported
   * @return
   */
  static int outputDataFile(PrintStream out, String[] img_names, String[] ft_names, String[] categories, int feature_length, boolean[] picked) {

    // for each image
    for (int i=0; i<img_names.length; i++) {
      int current_feature_length = 0;

      // for each features
      for (int j=0; j<ft_names.length; j++) {
        if (j!=2) continue;
        // image feature file
        String img_ft_file_name = img_names[i] + '.' + ft_names[j];
        // read in the data
        String[] features = null;

        try {
          features = yi.util.io.ReadArgu.readStrings(img_ft_file_name);
        } catch (IOException e) {
          System.err.println("Can't read from file: " + img_ft_file_name);
          e.printStackTrace();
          continue;
        }

        // output
        if (j != 2) {
          if (j !=0) out.print(',');
          out.print(features[0]);
          // feature length
          StringTokenizer tokenizer = new StringTokenizer(features[0], ",");
          current_feature_length += tokenizer.countTokens();
        } else {  // j=2 for feature combination
          StringTokenizer tokenizer = new StringTokenizer(features[0], ",");
          int count = 0;
          boolean firstOne = true;

          while (tokenizer.hasMoreTokens()) {
            String str = tokenizer.nextToken();
            if (picked[count]) {
              if (!firstOne) out.print(',');
              out.print(str);
              current_feature_length ++;
              firstOne = false;
            }
            count ++;
          }
        }
      }
      // output category
      out.println(',' + categories[i]);

      // feature length
      if (feature_length == 0) feature_length = current_feature_length;
      else if (feature_length != current_feature_length) {
        System.err.println("the feature length is not the same: " + current_feature_length + ", should be: " + feature_length);
        System.err.println("  " + img_names[i]);
      }
    }
    return feature_length;

  }

  static String[] getAttributeNames(String[] img_names, String[] ft_names) throws IOException{

      int current_feature_length = 0;

      ArrayList attr_names = new ArrayList();

      // for each features
      for (int j=0; j<ft_names.length; j++) {

        // read from attribute name file
        String att_name_file_name = ft_names[j] + '.' + "aname";
        boolean readFromAttrNameFile = true;
        try {
          String[] att_names_current = yi.util.io.ReadArgu.readStrings(att_name_file_name);
          for (int i=0; i<att_names_current.length; i++) attr_names.add(att_names_current[i]);
          current_feature_length += att_names_current.length;
        } catch (IOException e) { // read from attribute name file failed
          readFromAttrNameFile = false;
        }

        if (!readFromAttrNameFile) {

          // image feature file
          String img_ft_file_name = img_names[0] + '.' + ft_names[j];
          // read in the data
          String[] features = yi.util.io.ReadArgu.readStrings(img_ft_file_name);

          // feature length
          StringTokenizer tokenizer = new StringTokenizer(features[0], ",");
          int feature_length = tokenizer.countTokens();
          for (int i=0; i<feature_length; i++) attr_names.add(ft_names[j] + '.' + i);
          current_feature_length += feature_length;

          System.out.println("histogram length of " + img_ft_file_name + " = " + tokenizer.countTokens());
        }
      }
      return yi.util.data.Conversion.toStringArray(attr_names);
  }

  static String[] getAttributeNames(String[] img_names, String[] ft_names, boolean[] picked) throws IOException{

      int current_feature_length = 0;

      ArrayList attr_names = new ArrayList();

      // for each features
      for (int j=0; j<ft_names.length; j++) {
        if (j!=2) continue;

        // read from attribute name file
        String att_name_file_name = ft_names[j] + '.' + "aname";
        boolean readFromAttrNameFile = true;
        try {
          String[] att_names_current = yi.util.io.ReadArgu.readStrings(att_name_file_name);
          for (int i=0; i<att_names_current.length; i++) {
            if (j != 2 || picked[i]) {
              attr_names.add(att_names_current[i]);
              current_feature_length ++;
            }
          }
        } catch (IOException e) { // read from attribute name file failed
          readFromAttrNameFile = false;
        }

        if (!readFromAttrNameFile) {

          // image feature file
          String img_ft_file_name = img_names[0] + '.' + ft_names[j];
          // read in the data
          String[] features = yi.util.io.ReadArgu.readStrings(img_ft_file_name);

          // feature length
          StringTokenizer tokenizer = new StringTokenizer(features[0], ",");
          int feature_length = tokenizer.countTokens();
          for (int i=0; i<feature_length; i++) {
            if (j != 2 || picked[i]) {
              attr_names.add(ft_names[i] + '.' + i);
              current_feature_length ++;
            }
          }

          System.out.println("histogram length of " + img_ft_file_name + " = " + tokenizer.countTokens());
        }
      }
      return yi.util.data.Conversion.toStringArray(attr_names);
  }

  static void outputNameFile(PrintStream out, int feature_length) {
    // categories
    out.print(IS_TARGET_OBJECT);
    out.print(',');
    out.print(IS_NOT_TARGET_OBJECT);
    out.println('.');
    for (int i=0; i<feature_length; i++) {
      out.println(
        "p" + i + ": " + "continuous" + ".");
    }
  }

  public static class J48 {
    static void outputArff(PrintStream out, String[] attribute_names, String[] img_names, String[] ft_names, String[] categories, String relation){

      // title
      // @relation
      out.println("@relation " + relation);
      out.println();

      // attributes
      // @attribute p0 real
      for (int i=0; i<attribute_names.length; i++) {
        out.println("@attribute " + attribute_names[i] + " real");
      }
      out.println("@attribute object {" + IS_TARGET_OBJECT + "," + IS_NOT_TARGET_OBJECT + "}");
      out.println();

      //data
      out.println("@data");
      outputDataFile(out, img_names, ft_names, categories, attribute_names.length);
    }

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

      // get the image list file name
      String img_name = ReadArgu.getOption('i', args);
      if (img_name == null) {
        System.err.println(USAGE);
        System.exit(1);
      }

      // get the feature list file name
      String ft_name = ReadArgu.getOption('f', args);
      if (ft_name == null) {
        System.err.println(USAGE);
        System.exit(1);
      }

      // get the target_object_for_learning
      String target_object = ReadArgu.getOption('t', args);
      if (target_object == null) {
        System.err.println(USAGE);
        System.exit(1);
      }

      // get the target_object_for_learning
      String output_root = ReadArgu.getOption('o', args);
      if (output_root == null) {
        output_root = target_object.replace(',', '.').replace(' ', '_').toLowerCase() + '.' + ft_name.toLowerCase();
      }

      try {
        // reading from files
        String[] img_names = ReadArgu.readStrings(img_name);
        String[] ft_names = ReadArgu.readStrings(ft_name);

        // reading categories
        String[] categories = readCategories(img_names, target_object);

        // output t.data
        PrintStream arff_file = new PrintStream (new FileOutputStream(output_root + ".arff"));
        String[] attribute_names = getAttributeNames(img_names, ft_names);
        outputArff(arff_file, attribute_names, img_names, ft_names, categories, output_root);
        arff_file.close();
      } catch (java.io.IOException e) {
        e.printStackTrace();
      }

      System.exit(0);
    }
  }

  static int[] getFeature(String img_name, String ft_name) throws IOException{

    // image feature file
    String img_ft_file_name = img_name + '.' + ft_name;
    // read in the data
    String[] features = null;

    features = yi.util.io.ReadArgu.readStrings(img_ft_file_name);

    // feature length
    StringTokenizer tokenizer = new StringTokenizer(features[0], ",");
    int feature_length = tokenizer.countTokens();

    // read the data
    int[] data = new int[feature_length];
    int count = 0;
    while (tokenizer.hasMoreTokens()) {
      String data_str = tokenizer.nextToken();
      try {
        data[count] = Integer.parseInt(data_str);
      } catch (NumberFormatException e) {
        try {
          data[count] = (int)Math.round(Double.parseDouble(data_str));
        } catch (NumberFormatException e2) {
          System.err.println("Can't parse " + data_str + " from " + img_ft_file_name);
          data[count] = 0;
        }
      }
      count ++;
    }

    return data;

  }


  public static class J48Pick2DHist {

    static void outputProb(HashBasedHist prob) {
      int i1 = prob.getMinimum();
      int i2 = prob.getMaximum();
      for (int i=i1; i<=i2; i++) {
        int p = prob.get(i);
        if (p != 0) {
          System.out.print("(" + i + "):" + p + " ");
        }
      }
      System.out.println();
    }

    static void outputProbs(HashBasedHist prob1, HashBasedHist prob2, HashBasedHist prob_comb) {
      outputProb(prob1);
      outputProb(prob2);
      outputProb(prob_comb);
    }

    static void addHistToHistProb(HashBasedHist hist_probs_comb, int[] hist_comb){
      for (int i=0; i<hist_comb.length; i++) {
        if (hist_comb[i] != 0) {
          hist_probs_comb.put(i, hist_comb[i]);
        }
      }
    }

    static boolean[] pickup(String[] img_names, String[] ft_names, String[] categories) {
      HashBasedHist hist_probs1 = new HashBasedHist();
      HashBasedHist hist_probs2 = new HashBasedHist();
      HashBasedHist hist_probs_comb = new HashBasedHist();
      int hist1_len = 0;
      int hist2_len = 0;
      int hist_comb_len = 0;
      for (int i=0; i<img_names.length; i++) {
        System.out.println(Integer.toString(i) + "/" + img_names.length + " : " + img_names[i]);
        try {
          // histogram 1
          int[] hist1 = getFeature(img_names[i], ft_names[0]);
          // histogram 2
          int[] hist2 = getFeature(img_names[i], ft_names[1]);
          // 2D histogram from (feature1, feature2)
          int[] hist_comb = getFeature(img_names[i], ft_names[2]);

          hist1_len = hist1.length; hist2_len = hist2.length;
          hist_comb_len = hist_comb.length;
          if (categories[i].compareToIgnoreCase(IS_TARGET_OBJECT) == 0) {
            addHistToHistProb(hist_probs1, hist1);
            addHistToHistProb(hist_probs2, hist2);
            addHistToHistProb(hist_probs_comb, hist_comb);
          }
        } catch (IOException e) {
          e.printStackTrace();
        }
      }

      System.out.println("hist prob total 1 = " +  hist_probs1.getTotal());
      System.out.println("hist prob total 2 = " +  hist_probs2.getTotal());
      System.out.println("hist prob total comb = " +  hist_probs_comb.getTotal());
      int total = hist_probs1.getTotal();
      int count = 0;
      boolean[] picked = new boolean[hist_comb_len];
      java.util.Arrays.fill(picked, false);
      for (int i=0; i<hist1_len; i++) {
        for (int j=0; j<hist2_len; j++, count++) {
          if (hist_probs_comb.get(count)==0) continue;
          int p1 = hist_probs1.get(i);
          int p2 = hist_probs2.get(j);
          int p12 = hist_probs_comb.get(count);
          double predicted = (double)p1*p2/total;
          if (p12 > predicted * 2) {
            System.out.println("(" + i + ", " + j + "): " + p12 + "/" + ((double)p1*p2/total)+ "(" + p1 + " * " + p2 + ")");
            picked[count] = true;
          }
        }
      }
      return picked;
    }
  }

  public static class J48Pick1DHist {


    static int outputDataFile(PrintStream out, String[] img_names, String[] ft_names, String[] categories, int feature_length, boolean[] picked) {

      // for each image
      for (int i=0; i<img_names.length; i++) {
        int current_feature_length = 0;

        // for each features
        for (int j=0; j<ft_names.length; j++) {
          if (j!=0) continue;
          // image feature file
          String img_ft_file_name = img_names[i] + '.' + ft_names[j];
          // read in the data
          String[] features = null;

          try {
            features = yi.util.io.ReadArgu.readStrings(img_ft_file_name);
          } catch (IOException e) {
            System.err.println("Can't read from file: " + img_ft_file_name);
            e.printStackTrace();
            continue;
          }

          // output
          {
            StringTokenizer tokenizer = new StringTokenizer(features[0], ",");
            int count = 0;
            boolean firstOne = true;

            while (tokenizer.hasMoreTokens()) {
              String str = tokenizer.nextToken();
              if (picked[count]) {
                if (!firstOne) out.print(',');
                out.print(str);
                current_feature_length ++;
                firstOne = false;
              }
              count ++;
            }
          }
        }
        // output category
        out.println(',' + categories[i]);

        // feature length
        if (feature_length == 0) feature_length = current_feature_length;
        else if (feature_length != current_feature_length) {
          System.err.println("the feature length is not the same: " + current_feature_length + ", should be: " + feature_length);
          System.err.println("  " + img_names[i]);
        }
      }
      return feature_length;

    }

    static String[] getAttributeNames(String[] img_names, String[] ft_names, boolean[] picked) throws IOException{

        int current_feature_length = 0;

        ArrayList attr_names = new ArrayList();

        // for each features
        for (int j=0; j<ft_names.length; j++) {
          if (j!=0) continue;

          // read from attribute name file
          String att_name_file_name = ft_names[j] + '.' + "aname";
          boolean readFromAttrNameFile = true;
          try {
            String[] att_names_current = yi.util.io.ReadArgu.readStrings(att_name_file_name);
            for (int i=0; i<att_names_current.length; i++) {
              if (picked[i]) {
                attr_names.add(att_names_current[i]);
                current_feature_length ++;
              }
            }
          } catch (IOException e) { // read from attribute name file failed
            readFromAttrNameFile = false;
          }

          if (!readFromAttrNameFile) {

            // image feature file
            String img_ft_file_name = img_names[0] + '.' + ft_names[j];
            // read in the data
            String[] features = yi.util.io.ReadArgu.readStrings(img_ft_file_name);

            // feature length
            StringTokenizer tokenizer = new StringTokenizer(features[0], ",");
            int feature_length = tokenizer.countTokens();
            for (int i=0; i<feature_length; i++) {
              if (picked[i]) {
                attr_names.add(ft_names[i] + '.' + i);
                current_feature_length ++;
              }
            }

            System.out.println("histogram length of " + img_ft_file_name + " = " + tokenizer.countTokens());
          }
        }
        return yi.util.data.Conversion.toStringArray(attr_names);
    }

    static void outputProb(HashBasedHist prob) {
      int i1 = prob.getMinimum();
      int i2 = prob.getMaximum();
      for (int i=i1; i<=i2; i++) {
        int p = prob.get(i);
        if (p != 0) {
          System.out.print("(" + i + "):" + p + " ");
        }
      }
      System.out.println();
    }

    static void outputProbs(HashBasedHist prob1, HashBasedHist prob2, HashBasedHist prob_comb) {
      outputProb(prob1);
      outputProb(prob2);
      outputProb(prob_comb);
    }

    static void addHistToHistProb(HashBasedHist hist_probs_comb, int[] hist_comb){
      for (int i=0; i<hist_comb.length; i++) {
        if (hist_comb[i] != 0) {
          hist_probs_comb.put(i, hist_comb[i]);
        }
      }
    }

    static boolean[] pickup(String[] img_names, String[] ft_names, String[] categories) {
      HashBasedHist hist_probs1 = new HashBasedHist();
      HashBasedHist hist_probs_neg = new HashBasedHist();
      HashBasedHist hist_probs_total = new HashBasedHist();
      int hist1_len = 0;
      int positive_case_num = 0;
      int negative_case_num = 0;
      for (int i=0; i<img_names.length; i++) {
        System.out.println(Integer.toString(i) + "/" + img_names.length + " : " + img_names[i]);
        try {
          // histogram 1
          int[] hist1 = getFeature(img_names[i], ft_names[0]);

          hist1_len = hist1.length;
          if (categories[i].compareToIgnoreCase(IS_TARGET_OBJECT) == 0) {
            addHistToHistProb(hist_probs1, hist1);
            positive_case_num ++;
          } else {
            addHistToHistProb(hist_probs_neg, hist1);
            negative_case_num ++;
          }
          addHistToHistProb(hist_probs_total, hist1);
        } catch (IOException e) {
          e.printStackTrace();
        }
      }

      System.out.println("positive_case_num = " +  positive_case_num);
      System.out.println("negative_case_num = " +  negative_case_num);
      System.out.println("hist prob total 1 = " +  hist_probs1.getTotal());
      System.out.println("hist prob total neg = " +  hist_probs_neg.getTotal());
      System.out.println("hist prob total total = " +  hist_probs_total.getTotal());
      int positive_total = hist_probs1.getTotal();
      int negative_total = hist_probs_neg.getTotal();
      int total = hist_probs_total.getTotal();
      int count = 0;
      boolean[] picked = new boolean[hist1_len];
      java.util.Arrays.fill(picked, false);
      for (int i=0; i<hist1_len; i++) {
          int p1 = hist_probs1.get(i);
          int p2 = hist_probs_neg.get(i);
//          if ((double)p1/positive_case_num > (double)p2/negative_case_num * 1.5) {
//            System.out.println("(" + i + "): " + (((double)p1/positive_case_num) / ((double)p2/negative_case_num))+
//             "(" + p1 + " / " + positive_case_num + "," + p2 + " / " + negative_case_num + ")");
//            picked[count] = true;
//          }
          if ((double)p1/positive_total > (double)p2/negative_total * 1.5) {
            System.out.println("(" + i + "): " + ((double)p1/positive_total) + "/" + ((double)p2/negative_total)+
             "(" + p1 + " / " + positive_total + "," + p2 + " / " + negative_total + ")");
            picked[count] = true;
          }
//          if ((double)p1/positive_total * 1.2 < (double)p2/negative_total) {
//            System.out.println("(" + i + "): " + ((double)p1/positive_total) + "/" + ((double)p2/negative_total)+
//             "(" + p1 + " / " + positive_total + "," + p2 + " / " + negative_total + ")");
//            picked[count] = true;
//          }
          count ++;
//          if ((double)p1/positive_total * 1.2 < (double)p2/negative_total) {
//            picked[count] = true;
//          }
      }
      return picked;
    }

    static void outputArff(PrintStream out, String[] attribute_names, String[] img_names,
      String[] ft_names, String[] categories, String relation, boolean[] picked){

      // title
      // @relation
      out.println("@relation " + relation);
      out.println();

      // attributes
      // @attribute p0 real
      for (int i=0; i<attribute_names.length; i++) {
        out.println("@attribute " + attribute_names[i] + " real");
      }
      out.println("@attribute object {" + IS_TARGET_OBJECT + "," + IS_NOT_TARGET_OBJECT + "}");
      out.println();

      //data
      out.println("@data");
      outputDataFile(out, img_names, ft_names, categories, attribute_names.length, picked);
    }


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

      // get the image list file name
      String img_name = ReadArgu.getOption('i', args);
      if (img_name == null) {
        System.err.println(USAGE);
        System.exit(1);
      }

      // get the feature list file name
      String ft_name = ReadArgu.getOption('f', args);
      if (ft_name == null) {
        System.err.println(USAGE);
        System.exit(1);
      }

      // get the target_object_for_learning
      String target_object = ReadArgu.getOption('t', args);
      if (target_object == null) {
        System.err.println(USAGE);
        System.exit(1);
      }

      // get the target_object_for_learning
      String output_root = ReadArgu.getOption('o', args);
      if (output_root == null) {
        output_root = target_object.replace(',', '.').replace(' ', '_').toLowerCase() + '.' + ft_name.toLowerCase();
      }

      try {
        // reading from files
        String[] img_names = ReadArgu.readStrings(img_name);
        // reading categories
        String[] categories = readCategories(img_names, target_object);

        // attribute names
        String[] ft_names = ReadArgu.readStrings(ft_name);

        // pick up the attribute
        boolean[] picked = pickup(img_names, ft_names, categories);

        // output t.data
        PrintStream arff_file = new PrintStream (new FileOutputStream(output_root + ".arff"));
        String[] attribute_names = getAttributeNames(img_names, ft_names, picked);
        outputArff(arff_file, attribute_names, img_names, ft_names, categories, output_root, picked);
        arff_file.close();
      } catch (java.io.IOException e) {
        e.printStackTrace();
      }

      System.exit(0);
    }
  }

  public static class HtmlAlbum {
    static String USAGE = "Usage: -i image_list_file_name -t target_object_for_learning -o output_root -c col_num -r row_num";


    /**
     * Given an image name, return its thumb image name.
     * @param image_name
     * @return
     */
    static String thumbImageName(String image_name) {
      if (image_name.indexOf("groundtruth") >= 0) {
        return yi.util.data.StringUtil.replace(image_name, "groundtruth", "groundtruth.THUMB");
      }
      if (image_name.indexOf("yi_pictures") >= 0) {
        return yi.util.data.StringUtil.replace(image_name, "yi_pictures", "yi_pictures.THUMB");
      }
      return image_name;
    }

    /**
     * Generate the html albums for the positive and negative cases
     * @param args
     */
    public static void main(String[] args) {
      // init configuration
      Configuration.init(args);

      // get the image list file name
      String img_name = ReadArgu.getOption('i', args);
      if (img_name == null) {
        System.err.println(USAGE);
        System.exit(1);
      }

      // get the target_object_for_learning
      String target_object = ReadArgu.getOption('t', args);
      if (target_object == null) {
        System.err.println(USAGE);
        System.exit(1);
      }

      // get the target_object_for_learning
      String output_root = ReadArgu.getOption('o', args);
      if (output_root == null) {
        output_root = target_object.replace(',', '.').replace(' ', '_').toLowerCase();
      }

       // column number
      String col_num_str = ReadArgu.getOption('c', args);
      if (col_num_str == null) {
        System.err.println(USAGE);
        System.exit(1);
      }

      // row number
      String row_num_str = ReadArgu.getOption('r', args);
      if (row_num_str == null) {
        System.err.println(USAGE);
        System.exit(1);
      }

      int col_num = Integer.parseInt(col_num_str);
      int row_num = Integer.parseInt(row_num_str);

      try {
          // reading from files
          String[] img_names = ReadArgu.readStrings(img_name);

          // reading categories
          String[] categories = readCategories(img_names, target_object);

          // count positive cases
          int positive_num = 0;
          for (int i=0; i<categories.length; i++) {
            if (categories[i].compareToIgnoreCase(IS_TARGET_OBJECT) == 0) positive_num ++;
          }
          int negative_num = img_names.length - positive_num;

          String[] positive_cases = new String[positive_num];
          String[] negative_cases = new String[negative_num];
          int positive_count = 0, negative_count = 0;
          for (int i=0; i<categories.length; i++) {
            if (categories[i].compareToIgnoreCase(IS_TARGET_OBJECT) == 0) {
              positive_cases[positive_count++] = img_names[i];
            } else {
              negative_cases[negative_count++] = img_names[i];
            }
          }

          // thumb image linkes
          String[] positive_cases_thumbs = new String[positive_num];
          for (int i=0; i<positive_cases_thumbs.length; i++) {
            positive_cases_thumbs[i] = thumbImageName(positive_cases[i]);
          }
          String[] negative_cases_thumbs = new String[negative_num];
          for (int i=0; i<negative_cases_thumbs.length; i++) {
            negative_cases_thumbs[i] = thumbImageName(negative_cases[i]);
          }

          // positive cases html album
          String positive_album = yi.net.html.HtmlAlbum.generateHtmlAlbum(
            target_object + "(positive:" +  positive_num + "/" + img_names.length + ")", positive_cases_thumbs, positive_cases, col_num, row_num, false);

          PrintStream out = new PrintStream (new FileOutputStream(output_root + ".positive.html"));
          out.print(positive_album);
          out.close();

          String negative_album = yi.net.html.HtmlAlbum.generateHtmlAlbum(
            target_object + "(negative:" + negative_num + "/" + img_names.length + ")", negative_cases_thumbs, negative_cases, col_num, row_num, false);

          out = new PrintStream (new FileOutputStream(output_root + ".negative.html"));
          out.print(negative_album);
          out.close();
      } catch (java.io.IOException e) {
        e.printStackTrace();
      }

      System.exit(0);

    }
  }

  public static class Categorize {
    static String USAGE = "Usage: -i image_list_file_name -t target_object_for_learning";

    /**
     * Generate the html albums for the positive and negative cases
     * @param args
     */
    public static void main(String[] args) {
      // init configuration
      Configuration.init(args);

      // get the image list file name
      String img_name = ReadArgu.getOption('i', args);
      if (img_name == null) {
        System.err.println(USAGE);
        System.exit(1);
      }

      // get the target_object_for_learning
      String target_object = ReadArgu.getOption('t', args);
      if (target_object == null) {
        System.err.println(USAGE);
        System.exit(1);
      }

      try {
          // reading from files
          String[] img_names = ReadArgu.readStrings(img_name);

          // reading categories
          String[] categories = readCategories(img_names, target_object);

          // count positive cases
          int positive_num = 0;
          for (int i=0; i<categories.length; i++) {
            if (categories[i].compareToIgnoreCase(IS_TARGET_OBJECT) == 0) positive_num ++;
          }
          int negative_num = img_names.length - positive_num;

          String[] positive_cases = new String[positive_num];
          String[] negative_cases = new String[negative_num];
          int positive_count = 0, negative_count = 0;
          for (int i=0; i<categories.length; i++) {
            if (categories[i].compareToIgnoreCase(IS_TARGET_OBJECT) == 0) {
              positive_cases[positive_count++] = img_names[i];
            } else {
              negative_cases[negative_count++] = img_names[i];
            }
          }

          System.out.println("total case number: " + img_names.length);
          System.out.println("positive case number: " + positive_num);
          System.out.println("negative case number: " + img_names.length);
          System.out.println("positive cases:");
          for (int i=0; i<positive_cases.length; i++) {
            System.out.println(positive_cases[i]);
          }
          System.out.println("negative cases:");
          for (int i=0; i<negative_cases.length; i++) {
            System.out.println(negative_cases[i]);
          }

      } catch (java.io.IOException e) {
        e.printStackTrace();
      }

      System.exit(0);

    }
  }



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

    // get the image list file name
    String img_name = ReadArgu.getOption('i', args);
    if (img_name == null) {
      System.err.println(USAGE);
      System.exit(1);
    }

    // get the feature list file name
    String ft_name = ReadArgu.getOption('f', args);
    if (ft_name == null) {
      System.err.println(USAGE);
      System.exit(1);
    }

    // get the target_object_for_learning
    String target_object = ReadArgu.getOption('t', args);
    if (target_object == null) {
      System.err.println(USAGE);
      System.exit(1);
    }

    // get the target_object_for_learning
    String output_root = ReadArgu.getOption('o', args);
    if (output_root == null) {
      System.err.println(USAGE);
      System.exit(1);
    }

    try {
      // reading from files
      String[] img_names = ReadArgu.readStrings(img_name);
      String[] ft_names = ReadArgu.readStrings(ft_name);

      // reading categories
      String[] categories = readCategories(img_names, target_object);

      // output t.data
      PrintStream data_file = new PrintStream (new FileOutputStream(output_root + ".data"));
      System.out.println("output_root" + output_root);
      int feature_length = outputDataFile(data_file, img_names, ft_names, categories, 0);
      data_file.close();

      // output t.names
      PrintStream name_file = new PrintStream (new FileOutputStream(output_root + ".names"));
      outputNameFile(name_file, feature_length);
      name_file.close();
    } catch (java.io.IOException e) {
      e.printStackTrace();
    }

    System.exit(0);
  }
}