package yi.iu.imgdb.learn.em;

import java.util.*;
import yi.util.data.*;
import yi.stat.em.*;
import yi.iu.imgdb.learn.*;
import yi.ds.hash.*;
import yi.util.io.*;
import yi.util.config.*;
import org.jmat.gui.*;
import java.util.HashMap;
import java.text.*;
import yi.stat.*;
import yi.ds.fold.*;

/**
 * Image database learning adapter using mixture models
 */
public abstract class MixtureModelAdapter extends StatModelAdapter implements FeatureScoringCapable
{
  /**
   * This adapter only learns on one feature
   */
  String m_feature = null;

  /**
   * Store the mapping from image to its object list.  The key is the name of
   * the image and the value is a String collection
   */
  HashMap m_imgObjList = new HashMap();

  /**
   * Store the mapping from image to its feature vector list.  The key is the
   * name of the image and the value is a double[] collection
   */
  HashMap m_imgFvList = new HashMap();

  MixtureModel m_model = null;

  static final long serialVersionUID = 7892453260133436278L;
  /**
   * Construct the mixture model
   * @param data_center
   * @param img_list
   * @param ft_list
   * @param obj_list
   */
  public MixtureModelAdapter(ImgDataCenter data_center, LinkedList img_list,
                       LinkedList ft_list, LinkedList obj_list) {
    super(data_center, img_list, ft_list, obj_list);

    // this method only learns on one feature
    m_feature = (String) m_featureList.getFirst();

    int feature_len = data_center.getFeatureLength(m_feature);

    // get the image list
    if (img_list == null)
      img_list = data_center.getImageList();

    // get the object list
    if (obj_list == null) obj_list = data_center.getObjectList();
    HashSet obj_set = new HashSet(obj_list);

    // get the feature vector list and the keyword list for each image
    for (Iterator i = img_list.iterator(); i.hasNext(); ) {
      String img_name = (String) i.next();
      // get the image feature vectors
      double[][] feature_vects = data_center.getImgFeatureList(img_name,
          m_feature).as2DDoubleArray();
      LinkedList ft_vt_list = Conversion.toLinkedList(feature_vects);
      m_imgFvList.put(img_name, ft_vt_list);

      // get the image description keywords
      LinkedList desc_list = (LinkedList) data_center.getImgDescriptions(
          img_name).clone();
      for (Iterator j = desc_list.iterator(); j.hasNext(); ) {
        String desc = (String) j.next();
        // check whether the description is in the object list to learn
        // if not, just remove it
        if (!obj_set.contains(desc))
          j.remove();
      }
      m_imgObjList.put(img_name, desc_list);
    }

    m_model = createMixtureModel(m_imgFvList, m_imgObjList);

    System.out.println("use " + m_model.getClass().getName());
    m_model.learnTheModel();
  }

  /**
   * Create the mixture model.  This method is intended to be overrided to use
   * different mixture model
   * @param fvList
   * @param objList
   * @return
   */
  protected abstract MixtureModel createMixtureModel(HashMap fvList, HashMap objList);

  public MixtureModel getMixtureModel() {
    return m_model;
  }

  /**
   * Given a feature vector, return its score of the given object.  This method
   * is required by the definition of StatModelAdapter.  Therefore, we can't
   * explicitely use "log" in the name since other adapter may not use the log
   * score.  But do remember that the score returned here is LOG version.
   * @param object
   * @param feature
   * @return
   */
  public double getFeatureScore(double[] feature, Object obj) {
    HashMap probs = m_model.getDensitiesUnderComponents(feature);
    double prob = ((Double)probs.get(obj)).doubleValue();
    double log_prob = Math.log(prob);
    return log_prob;
  }

  public final static int COMBINING_MAX = 0;
  public final static int COMBINING_MEAN = 1;
  public int COMBINING_FUNC = COMBINING_MAX;
  /**
   * Given the feature vectors of an image, return the probabilities of
   * that image containing different objects.  Basically use each feature
   * vector to get the p(obj|f) and then combining them somehow to get
   * p(obj|{f1, f2, ...})
   * @param features
   * @return
   */
  public DoubleScoreHashMap getProbabilities(Collection features) {
    // to store the probability for each object
    DoubleScoreHashMap rsts = new DoubleScoreHashMap();

    for (Iterator i = features.iterator(); i.hasNext(); ) {

      // for each feature vector, get p(obj|f)
      double[] feature = (double[]) i.next();
      HashMap probs = m_model.getDensitiesUnderComponents(feature);
      for (Iterator j = probs.keySet().iterator(); j.hasNext(); ) {
        Object obj = j.next();
        double prob = ( (Double) probs.get(obj)).doubleValue();
        double log_prob = (prob == 0) ? -Double.MAX_VALUE : Math.log(prob);
        /** @todo compare sum and max */
        if (COMBINING_FUNC == COMBINING_MAX) {
          rsts.putScoreOnCondition(obj, log_prob, true);
        } else { // COMBINING_MEAN
          double old_score = (rsts.containsKey(obj)) ? rsts.getScore(obj) : 0;
          rsts.putScore(obj, old_score + log_prob);
        }
      }
    }
    if (COMBINING_FUNC == COMBINING_MEAN) {
      // average the score
      for (Iterator i = rsts.keySet().iterator(); i.hasNext(); ) {
        Object obj = i.next();
        double old_score = (rsts.containsKey(obj)) ? rsts.getScore(obj) : 0;
        rsts.putScore(obj, old_score/features.size());
      }
    }
    return rsts;
  }


  /**
   * Given a set of image, return the probability of p(obj|image).  The returned
   * results is a map of map: obj -> image -> p(obj|image)
   * @param imgs
   * @return
   */
  public StatTestRst test(LinkedList imgs) {
    StatTestRst rst = new StatTestRst();
    for (Iterator j = imgs.iterator(); j.hasNext(); ) {
      String img = (String)j.next();
//      System.out.println(img);
      FeatureRepresentationList fr_list = m_imgDataCenter.getImgFeatureList(img, m_feature);
      LinkedList feature_list = Conversion.toLinkedList(fr_list.as2DDoubleArray());
      DoubleScoreHashMap prob = getProbabilities(feature_list);
      for (Iterator o = prob.keySet().iterator(); o.hasNext(); ) {
        Object object = o.next();
        double d = prob.getScore(object);
        rst.putScore(object, img, d);
      }
    }
    return rst;
  }

  /**
   * Locate the object in each of the image.  Probably some demo images are
   * written to the disk and a html index file is generated
   * @param imgs
   * @return StatTestRst
   */
  public boolean locateObject(LinkedList imgs, LinkedList obj_list,
                              FeatureDescriptor ft_desc, RepresentationDescriptor rp_desc,
                              String exp_name) throws Exception{

    // draw the demo image
    String represent_path = Configuration.getParameter(
        "REPRESENTATION_PATH", "");
    String learn_path = Configuration.getParameter("LEARNING_PATH", "");
    String image_path = Configuration.getParameter("IMAGE_PATH", "");

    NumberFormat nf = NumberFormat.getNumberInstance();
    nf.setMaximumFractionDigits(1);

    // currently, only can consider one feature case
    String feature = StringUtil.getClassShortName(ft_desc.generator);

    // get the uniformed distribution density
    double[][] all_data = m_imgDataCenter.groupFeatureVectors(m_imgDataCenter.getImageList(),
        feature);
    double uniform_dist = yi.stat.StatUtil.getUniformDistributionDensity(all_data);
    double log_uniform_dist = Math.log(uniform_dist);
    System.err.println("log uniformed distribution = " + log_uniform_dist);

    int i_index = 0;
    for (Iterator i = imgs.iterator(); i.hasNext(); i_index++) {
      String img = (String) i.next();

      // get the feature vectors
      FeatureRepresentationList features = m_imgDataCenter.
          getImgFeatureList(
          img, // image name
          feature);

      FeatureRepresentable data = FeatureUtil.readFeature(img, ft_desc);

      if (data instanceof LabeledRgnFtRepresentable) {
        LabeledRgnFtRepList labeld_rep = ( (LabeledRgnFtRepresentable) data).
            representLabeledRgnFts(
            feature, rp_desc.mode);
        String cdemo = FeatureDescriptor.getFeatureColorDemoName(ft_desc, img, true);
        String gdemo = FeatureDescriptor.getFeatureGraphicDemoName(ft_desc,
            img, true);
        System.out.println("<a href=\"" + image_path + img + "\">" +
                           " <img src=" + image_path + img + "></a>" +
                           "<img src=" + cdemo + " >" +
                           "<img src=" + gdemo + " >" +
                           "<br>");

        double[][] scores = new double[obj_list.size()][features.size()];

        int f_index = 0;
        for (Iterator f = features.iterator(); f.hasNext(); f_index++) {
          FeatureRepresentation fr = (FeatureRepresentation) f.next();
          double[] d = fr.data;
          HashMap comp_probs = m_model.getDensitiesUnderComponents(d, true, false);
          int j_index = 0;
          for (Iterator j = obj_list.iterator(); j.hasNext(); j_index++) {
            String obj = (String) j.next();
            double prob = ((Double)comp_probs.get(obj)).doubleValue();
            prob = Math.log(prob);
            scores[j_index][f_index] = prob;
          }
        }

        // normalize the scores
        double max = StatUtil.maximum(scores);
        double min = log_uniform_dist;
        scores = StatUtil.normalize(scores, min, max, 1);

        LinkedList descriptions = m_imgDataCenter.getImgDescriptions(img);

        int j_index = 0;
        for (Iterator j = obj_list.iterator(); j.hasNext(); j_index++) {
          String obj = (String) j.next();
          double[] ft_score = scores[j_index];

          System.err.println("scores on regions: ");
          OutputResult.print(System.err, ft_score);

          int[] prob_demo = labeld_rep.drawProbabilityDemo(null, ft_score, null);
          String prob_demo_name = learn_path + img +
              "." + exp_name +
              "." + obj + ".loc" +
              ".png";
          yi.util.io.File.makeDirectory(prob_demo_name, true);
          ImageIOUtil.write(prob_demo_name,
                            "png", prob_demo, labeld_rep.imgWidth,
                            labeld_rep.imgHeight);
          if (descriptions.contains(obj)) {
            System.out.print("<b>" + obj + "</b>");
          }
          else {
            System.out.print(obj);
          }
          System.out.println(" (" + nf.format(StatUtil.maximum(ft_score) * 100) +
                             ")" + "<br>");
          System.out.println(
              "<a href=\"" + prob_demo_name + "\">" +
              "<img src=\"" + prob_demo_name + "\" border=1 width=256>" +
              "</a><br>");

        }
      }

    }

    return false;
  }

  public static class ScorelizeRegion {

    public final static String USAGE = "Usage: [-d img_data_center_file] [-m model_file] [-i img_list_file]";

    public static void main(String[] args) {

      // init configuration
      Configuration.init(args);

      try {

        // read in an MixtureModelAdapter object
        String model_file = ReadArgu.getOption(
            'm', args,
            "model0.ser"
            );

        MixtureModelAdapter mma = (MixtureModelAdapter)MixtureModelAdapter.createFromFile(model_file);

        // init the datacenter
        String data_center_name = ReadArgu.getOption(
            'd', args,
            "groundtruth.rgn.ser"
            );

        ImgDataCenter data_center = ImgDataCenter.createFromFile(
            data_center_name);

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

        // if image list file is defined, read image list from that file
        LinkedList img_list = null;
        if (img_list_file != null) {
          String[] images = yi.util.io.ReadArgu.readStrings(img_list_file);
          img_list = yi.util.data.Conversion.asLinkedList(images);
        }

        /** @todo custom the feature name */
        String feature = mma.m_feature;
        System.out.println("Feature: " + feature);

        HashMap rst_file_suffix_map = new HashMap();
        rst_file_suffix_map.put("yi.iu.processor.texture.reg.DS_PolygonRegionTextureStat", ".s256.text.reg.gif");
        rst_file_suffix_map.put("yi.iu.processor.color.reg.DS_PolygonRegionColorStat", ".s256.color.reg.gif");
        rst_file_suffix_map.put("yi.iu.region.LabeledRgnFtsWithPxlValue", ".ct.rgn.gif");

        // the score will be based on which object
        String obj = ReadArgu.getOption(
            'd', args,
            "tree"
            );

        // loop through the image and their features
        for (Iterator i=img_list.iterator(); i.hasNext();) {
          String img = (String)i.next();
          PolygonFeatureRepresentationList rfrl =
              (PolygonFeatureRepresentationList)data_center.getImgFeatureList(img, feature);
          int[] score_img = rfrl.drawScoreDemo(obj, mma, 128, 10);
          for (int j=0; j<score_img.length; j++) {
            if (score_img[j] < 0) score_img[j] = 0;
            if (score_img[j] > 255) score_img[j] = 255;
          }
          int[] pixels_img = yi.util.ImageUtil.makeNewImageFromGray(score_img);
          yi.util.io.OutputResult.outputGIFImage(img + ".score.gif", pixels_img,
                                                 rfrl.imgWidth, rfrl.imgHeight);
          System.out.println("<P>" +
                             "<IMG SRC=\"" + img + "\" width=256>" +
                             "<IMG SRC=\"" + img + (String)rst_file_suffix_map.get(feature) + "\" width=256>" +
                             "<IMG SRC=\"" + img + ".score.gif\" width=256>" +
                             "</P>");
        }

      } catch (Exception e) {
        e.printStackTrace();
      }
    }
  }

  public static class Test {

    public final static String USAGE = "Usage: [-d img_data_center_file] [-m model_file] [-i img_list_file] [-f feature] [-r rst_file_name]";

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

      try {
        // read in an ObjGMMAdapter object
        String model_file = ReadArgu.getOption(
            'm', args,
            "model0.ser"
            );

        MixtureModelAdapter mma = (MixtureModelAdapter)MixtureModelAdapter.createFromFile(model_file);

        // init the datacenter
        String data_center_name = ReadArgu.getOption(
            'd', args,
            "groundtruth.ser"
            );

        ImgDataCenter data_center = ImgDataCenter.createFromFile(
            data_center_name);

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

        // image list
        LinkedList img_list = null;
        if (img_list_file != null) {
          String[] images = yi.util.io.ReadArgu.readStrings(img_list_file);
          img_list = yi.util.data.Conversion.asLinkedList(images);
        }

        System.out.println(mma.m_model);

        StatTestRst rst = mma.test(img_list);

        System.out.println(rst);

        HashMap rpcs = rst.rpcAnalysis(data_center); // right positive curves
        DoubleScoreHashMap roc_scores = rst.getROCScores(rpcs);
        System.out.println("roc scores:");
        System.out.println(roc_scores.toStringBykeyOrder());

        Plot2DPanel pp = rst.drawROCs(rpcs);

        String rst_output_file = ReadArgu.getOption('r', args);
        if (rst_output_file != null) {
          pp.setFixedBounds(0,0,1);
          pp.setFixedBounds(1,0,1);
          pp.invalidate();
          pp.toGraphicFile(new java.io.File(rst_output_file + ".png"));
        }

      } catch (Exception e) {
        e.printStackTrace();
      }
    }
  }

  public int[] getComponentMeanInColor(String generator) {
    // finds out how many Gaussian components
    MixtureModel gmm = (MixtureModel)m_model;
    int n_components = gmm.getRstNumComponents();
    System.out.println("component# =" + n_components);
    System.out.println();

    // each component corresponding to one color
    int[] color_maps = yi.util.ImageUtil.labels2Colors(n_components - 1, false);
    // if the feature is color feature, then use the color to represent
    // the clusters

    String feature = FeatureDescriptor.getDefaultFeatureDescriptor(generator).
        feature;
    if (feature.indexOf("CIELabLabeledRgnFts") >= 0) {
      return gmm.getRstMeansInColor("lab");
    }
    return color_maps;

  }

  /**
   * Use mean color to demonstrate the color clusters
   */
  public static class DemoClusterMeans {

    public final static String USAGE = "Usage: [-c use_cross_valid_fold] -e experiment_file [-f feature] [-o object]";

    public static void main(String[] args) {

      // init configuration
      Configuration.init(args);

      String represent_path = Configuration.getParameter("REPRESENTATION_PATH", "");
      String learn_path = Configuration.getParameter("LEARNING_PATH", "");

      try {

        // read in an ObjGMMAdapter object
        String exp_file = ReadArgu.getOption('e', args, null);
        if (exp_file == null) {
          System.err.println(USAGE);
          System.exit(1);
        }

        String cross_valid_fold_str = ReadArgu.getOption('c', args, "0");
        int cross_valid_fold = Integer.parseInt(cross_valid_fold_str);

        StatModelFoldExperiment exp = StatModelFoldExperiment.createFromFile(
            learn_path + exp_file);
        MixtureModelAdapter gmm = (MixtureModelAdapter)exp.getModels()[cross_valid_fold];

        // init the datacenter
        String data_center_name = ReadArgu.getOption(
            'd', args);

        ImgDataCenter data_center = (data_center_name == null) ?
            gmm.m_imgDataCenter :
            ImgDataCenter.createFromFile(represent_path + data_center_name);

        // feature
        String feature = ReadArgu.getOption('f', args);
        if (feature == null) {
          feature = (String) gmm.m_featureList.getFirst();
        }
        System.out.println("feature : " + feature);


        // each component corresponding to one color
        int[] color_maps = gmm.getComponentMeanInColor(feature);
        int width = 64, height = 64;
        int[] demo = yi.iu.processor.color.ColorUtil.createSpectrum(color_maps, width, height);
        String out_name = yi.util.data.StringUtil.getFileSuffixNameRemoved(exp_file) + "." +
                          yi.util.data.StringUtil.getClassShortName(feature) +
                          ".mc.png";

        ImageIOUtil.write(learn_path + out_name,
                          "png", demo, width * color_maps.length, height);
        System.out.println("mean color spectrum output to " + learn_path + out_name);

        color_maps = yi.util.ImageUtil.labels2Colors(color_maps.length - 1, false);
        demo = yi.iu.processor.color.ColorUtil.createSpectrum(color_maps, width, height);
        out_name = yi.util.data.StringUtil.getFileSuffixNameRemoved(exp_file) + "." +
                          yi.util.data.StringUtil.getClassShortName(feature) +
                          ".mc.gdemo.png";

        ImageIOUtil.write(learn_path + out_name,
                          "png", demo, width * color_maps.length, height);
        System.out.println("psedo-color spectrum output to " + learn_path + out_name);
      } catch (Exception e) {
        e.printStackTrace();
      }
    }
  }

  /**
   * For each image region, classify it according to mixture component, and output
   * the resultant clustering image
   */
  public static class DemoClassification {

    public final static String USAGE = "Usage: -e experiment_file [-c use_cross_valid_fold] [-f feature] [-o object] [-y(only use positive images)] [-l(use learing images)|-t(use testing image)|-i img_list_file]";

    public static void main(String[] args) {

      // init configuration
      Configuration.init(args);

      String represent_path = Configuration.getParameter("REPRESENTATION_PATH", "");
      String learn_path = Configuration.getParameter("LEARNING_PATH", "");
      String image_path = Configuration.getParameter("IMAGE_PATH", "");

      try {

        // read in an ObjGMMAdapter object
        String exp_file = ReadArgu.getOption('e', args, null);
        if (exp_file == null) {
          System.err.println(USAGE);
          System.exit(1);
        }

        String cross_valid_fold_str = ReadArgu.getOption('c', args, "0");
        int cross_valid_fold = Integer.parseInt(cross_valid_fold_str);

        StatModelFoldExperiment exp = StatModelFoldExperiment.createFromFile(
            learn_path + exp_file);
        MixtureModelAdapter gmmnn = (MixtureModelAdapter)exp.getModels()[cross_valid_fold];

        // init the datacenter
        String data_center_name = ReadArgu.getOption(
            'd', args);

        ImgDataCenter data_center = (data_center_name == null) ?
            gmmnn.m_imgDataCenter :
            ImgDataCenter.createFromFile(represent_path + data_center_name);

        // image list
        LinkedList img_list = null;

        boolean use_learning_images = Boolean.valueOf(ReadArgu.getOption('l', args)).booleanValue();
        if (use_learning_images) {
          img_list = ((TwoLinkedListData)exp.getFolds().get(cross_valid_fold)).first;
        }
        else {
          boolean use_testing_images = Boolean.valueOf(ReadArgu.getOption('t', args)).booleanValue();
          if (use_testing_images) {
            img_list = ((TwoLinkedListData)exp.getFolds().get(cross_valid_fold)).second;
          } else {
            // get the image list file name
            String img_list_file = ReadArgu.getOption('i', args);

            if (img_list_file != null) {
              String[] images = yi.util.io.ReadArgu.readStrings(img_list_file);
              img_list = yi.util.data.Conversion.asLinkedList(images);
            }
            else {
              img_list = gmmnn.m_imageList;
            }
          }
        }

        // feature
        FeatureDescriptor[] ft_descs = FeatureDescriptor.parse(
            ReadArgu.getOption('f', args), data_center.getFeatureList());
        String feature = yi.util.data.StringUtil.getClassShortName(ft_descs[0].generator);

        // represent
        RepresentationDescriptor[] rep_descs = RepresentationDescriptor.parse(
            ReadArgu.getOption('r', args), data_center.getFeatureList());

        // finds out how many components

        MixtureModel gmm = (MixtureModel) gmmnn.getMixtureModel();
        int n_components = gmm.getRstNumComponents();
        System.out.println("component# " + n_components);

        // each component corresponding to one color
        int[] color_maps = gmmnn.getComponentMeanInColor(feature);
        // make label 0 for un-classified regions
        int[] color_maps_bg = new int[color_maps.length + 1];
        for (int i=0; i<color_maps.length; i++) color_maps_bg[i+1] = color_maps[i];
        color_maps_bg[0] = 0xffff0000;

        // minimum allowed score on each component
        double[][] all_data = data_center.groupFeatureVectors(data_center.getImageList(), feature);
        double minimum = yi.stat.StatUtil.getUniformDistributionDensity(all_data);
        double log_min = Math.log(minimum);
        System.out.println("use minimums: " + minimum);

        for (Iterator i = img_list.iterator(); i.hasNext(); ) {
          String img = (String) i.next();

          // get the feature vectors
          FeatureRepresentationList features = data_center.
              getImgFeatureList(
              img, // image name
              feature);

          // classify feature to one component
          int[] feature_component_map = new int[features.size()];
          // the classification of feature to component has a prob.
          // is the normalized prob.  prob/max_prob, so [0,1]
          double[] ft_comp_map_score = new double[features.size()];
          int f_index = 0;
          for (Iterator f = features.iterator(); f.hasNext(); f_index++) {
            FeatureRepresentation fr = (FeatureRepresentation) f.next();
            double[] d = fr.data;

            Object classify_to = (Object)gmm.classify(d);
            int index = gmm.objectToRstComponentIndex(classify_to);
            MixtureComponential gc = gmm.getComponent(classify_to);
            double p = gc.getDensity(d);
            double score =  p * gmm.getWeight(classify_to);
            if (p < minimum) {
              index = -1;
              score = minimum;
            }

            feature_component_map[f_index] = index + 1;
            ft_comp_map_score[f_index] = Math.log(score) - log_min;
          }
          // normalize the scores
          double highest_score = StatUtil.maximum(ft_comp_map_score);
          ft_comp_map_score = StatUtil.normalize(ft_comp_map_score, 0, highest_score, 1);

          FeatureRepresentable data = FeatureUtil.readFeature(
                  img, ft_descs[0]);

          if (data instanceof LabeledRgnFtRepresentable) {
            LabeledRgnFtRepList labeld_rep = ((LabeledRgnFtRepresentable)data).representLabeledRgnFts(
                feature, rep_descs[0].mode);
            System.out.println("labels = " + StatUtil.maximum(labeld_rep.getLabels()));
            int[] demo = labeld_rep.drawClassificationDemo(feature_component_map, ft_comp_map_score, color_maps_bg);
            String demo_name = learn_path + img +
                yi.util.data.StringUtil.getFileSuffixNameRemoved(exp_file) +
                "." + feature + ".cls" + ".png";
            int[] prob_demo = labeld_rep.drawProbabilityDemo(feature_component_map, ft_comp_map_score, color_maps_bg);
            String prob_demo_name = learn_path + img +
                yi.util.data.StringUtil.getFileSuffixNameRemoved(exp_file) +
                "." + feature + ".prb" + ".png";
            yi.util.io.File.makeDirectory(demo_name, true);
            ImageIOUtil.write(demo_name,
                              "png", demo, labeld_rep.imgWidth, labeld_rep.imgHeight);
            ImageIOUtil.write(prob_demo_name,
                              "png", prob_demo, labeld_rep.imgWidth, labeld_rep.imgHeight);
            String cdemo = FeatureDescriptor.getFeatureColorDemoName(ft_descs[0], img, true);
            String gdemo = FeatureDescriptor.getFeatureGraphicDemoName(ft_descs[0], img, true);
            System.out.println("<a href=\"" + image_path + img + "\">" +
                             " <img src=" + image_path + img + "></a>" +
                             "<a href=\"" + cdemo + "\">" +
                             "<img src=" + cdemo + " border=1>" + "</a>" +
                             "<a href=\"" + gdemo + "\">" +
                             "<img src=" + gdemo + " border=1>" + "</a>" +
                             "<a href=\"" + prob_demo_name + "\">" +
                             "<img src=" + prob_demo_name + " border=1>" + "</a>" +
                             "<a href=\"" + demo_name + "\">" +
                             "<img src=" + demo_name + " border=1>" + "</a><br>");

          }
        }
      }
      catch (Exception e) {
        e.printStackTrace();

      }
    }
  }

}
