package yi.iu.processor.ort;

import java.awt.*;
import java.util.*;

import yi.util.config.*;
import yi.util.io.*;
import yi.util.io.input.*;
import yi.util.io.output.*;
import yi.util.log.*;

/**
 * Wrapper for Fex, line and arc detection algorithm
 */
public class DPU_Fex extends Fex implements Configurable, RstReusable{
  /**
   * Used by in StringToSegments.  The difference in the number of pixels leads
   * to a-symetry
   */
  public int    MAX_JUMP_PIXELS = 2;

  /**
   * Minimum line length.  Those detected lines with length less than this value
   * will be discarded.
   */
  public double MIN_LINE_LEN    = 5;

  /**
   * Canny edge detector argument.  Standard deviation of the gaussian kernel.
   */
  public double CANNY_SIGMA     = 1;

  /**
   * Canny edge detector argument.  Fraction of the high threshold in hysteresis.
   */
  public double CANNY_T_LOW     = 0.5;

  /**
   * Canny edge detector argument.  High hysteresis threshold control. The actual
   */
  public double CANNY_T_HIGH    = 50;

  public int    REUSE  = DIU.INPUT_NONE;
  public int    OUTPUT = DOU.OUTPUT_NONE;
  public boolean SKIP_EXISTING = false;

  public boolean DEMO_LINES = true;

  public String[] getParameterNames() {
    return new String[] {
      "MAX_JUMP_PIXELS",
      "MIN_LINE_LEN",
      "CANNY_SIGMA",
      "CANNY_T_LOW",
      "CANNY_T_HIGH",
      "REUSE",
      "OUTPUT",
      "SKIP_EXISTING",
      "DEMO_LINES"
    };
  }

  public DPU_Fex() {
    Configuration.configParameters(this);
  }

  /**
   * Get lines and arcs in an image.
   * @param pixels image pixels
   * @param width image width
   * @param height image height
   * @return a 2-length array with its first element is a vector containing
   *         ORTLine(s) and its second element is another vector containing
   *         ORTCircularArc(s)
   */
  public Vector[] getLinesAndArcs(int[] pixels, int width, int height) {
    DS_ORTLines lines = (DS_ORTLines)reuse(REUSE);
    if (lines != null) {
      outputLines(OUTPUT, lines);
      return new Vector[] {
        lines.getLines(),
        new Vector()
      };
    }

    Vector[] segs=
      (new Fex(CANNY_SIGMA,CANNY_T_LOW,CANNY_T_HIGH,MIN_LINE_LEN,MAX_JUMP_PIXELS)).fex
        (pixels, new Dimension(width, height));
    Vector v_lines= segs[0];
    Vector v_arcs = segs[1];

    lines = new DS_ORTLines(width, height, v_lines);

    outputLines(OUTPUT, lines);

    return segs;
  }

  public int[] getDemo(int[] pixels, int width, int height, Vector[] segs) {
    Vector ID_ListORTLine= segs[0];
    Vector ID_ListORTCircularArc= segs[1];

    char[][] label= DrawUtil.ort2image(new Dimension(width, height), ID_ListORTLine,  ID_ListORTCircularArc);
//    int[] img= yi.util.ImageUtil.makeNewImageFromLabel(label_1);

    //This is to display the linked-line after canny and the line detected
    //int[] rst= (new CannyGray(sigma,tlow,thigh)).getProcessed(source,d);
    //yi.util.ImageUtil.makeImageFromGray(rst);
    //for (int i=0;i<img.length;i++)
    //    if (img[i]!=0xff000000) rst[i]=img[i];
    //(new DisplayFrame("rst", rst, d.width, d.height)).show();

//    (new DisplayFrame("rst", img, d.width, d.height)).show();

    int[] img = yi.util.ImageUtil.makeBackground(pixels);
    int count = 0;
    for (int h = 0; h < height; h ++) {
      for (int w = 0; w < width; w ++ , count ++) {
        if (label[h][w] != 0) img[count] = 0xffffffff;
      }
    }
//    (new DisplayFrame("rst", img, d.width, d.height)).show();
    return img;
  }

  /**
   * Return an image with lines and arcs drawn in it.
   * @param pixels
   * @param width
   * @param height
   * @return
   */
  public int[] getDemo(int[] pixels, int width, int height)
  {
    Vector[] segs= getLinesAndArcs(pixels, width, height);
    return getDemo(pixels, width, height, segs);
  }

  public void outputLines(int output_level, DS_ORTLines ds) {
    if (output_level != DOU.OUTPUT_NONE) {
      try {
        DOU.out(
            output_level,
            DOU.shortName(this.getClass().getName()),
            "DS_ORTLines",
            ds);
      } catch (DataOutputException e) {
          System.err.println("Can't Output DS_ORTLines");
          e.printStackTrace();
      }
    }
  }

  public Object reuse(int reuse_level) {
    if (reuse_level != DIU.INPUT_NONE) {
      try {
        DS_ORTLines rst = (DS_ORTLines)DIU.in(
            reuse_level,
            DOU.shortName(this.getClass().getName()),
            "DS_ORTLines",
            Class.forName("yi.iu.processor.ort.DS_ORTLines"));
        return rst;
      }
      catch (Exception e) {
        System.err.println("Can't Reuse DS_ORTLines");
        e.printStackTrace();
      }
    }
    return null;
  }

  /**
   * Generate the Global Representation for the feature
   */
  public static class FeatureGenerate {

    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);
      }

      // read in image
      Image image = null;
      Dimension d = new Dimension();
      int[] pixels = null;
      try {
        image = yi.util.io.ImageReader.readImageFile(img_name);
        pixels = yi.util.io.ImageReader.getPixels(image, d);
      }
      catch (java.io.IOException e) {
        System.err.println("Can't read image " + img_name);
        e.printStackTrace();
        System.exit(2);
      }


      // process
      Configuration.setParameter("SOURCE_NAME", img_name);
      DPU_Fex dp = new DPU_Fex();
    //    dp.getLinesAndArcs(pixels, d.width, d.height);
      int[] rst_img = dp.getDemo(pixels, d.width, d.height);

      // output result
      OutputResult.outputColorImage(img_name + "." + DOU.shortName(dp.getClass().getName()) + ".ppm", rst_img, d.width, d.height);

      System.exit(0);

    }
  }

  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);
    }

    // skip if SKIP_EXISTING
    DPU_Fex dummy = new DPU_Fex();
    if (dummy.SKIP_EXISTING) {
      String out_name = DOU.getOutputFileName(
            dummy.OUTPUT,
            img_name,
            DOU.shortName(dummy.getClass().getName()),
            "DS_ORTLines");
      java.io.File out = new java.io.File(out_name);
      if (out.exists()) {
        System.out.println(out + " exists.  Skip");
        System.exit(0);
      }

    }

    // read in image
    Image image = null;
    Dimension d = new Dimension();
    int[] pixels = null;
    try {
      image = yi.util.io.ImageReader.readImageFile(img_name);
      pixels = yi.util.io.ImageReader.getPixels(image, d);
    }
    catch (java.io.IOException e) {
      System.err.println("Can't read image " + img_name);
      e.printStackTrace();
      System.exit(2);
    }


    // process
    try {
      Configuration.setParameter("SOURCE_NAME", img_name);
      DPU_Fex dp = new DPU_Fex();
      long startTime = System.currentTimeMillis();
      Vector[] segs = dp.getLinesAndArcs(pixels, d.width, d.height);
      long endTime = System.currentTimeMillis();
      System.out.println("running time: " + (endTime-startTime));

      // demo the resultant lines;
      if (dp.DEMO_LINES) {
        int[] rst_img = dp.getDemo(pixels, d.width, d.height, segs);
        OutputResult.outputColorImage(img_name + "." + DOU.shortName(dp.getClass().getName()) + ".ppm", rst_img, d.width, d.height);
      }
    } catch (Exception e) {
      System.err.println("DPU_Fex Terminated.");
      e.printStackTrace();
    }

    System.exit(0);
  }

  public static class DemoLineAndArc {
    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);
      }

      // read in image
      Image image = null;
      Dimension d = new Dimension();
      int[] pixels = null;
      try {
        image = yi.util.io.ImageReader.readImageFile(img_name);
        pixels = yi.util.io.ImageReader.getPixels(image, d);
      }
      catch (java.io.IOException e) {
        System.err.println("Can't read image " + img_name);
        e.printStackTrace();
        System.exit(2);
      }


      // process
      try {
        DPU_Fex dp = new DPU_Fex();
        long startTime = System.currentTimeMillis();
        int[] demo = dp.getProcessedPseudoColor(pixels, d);
        long endTime = System.currentTimeMillis();
        System.out.println("running time: " + (endTime-startTime));

        OutputResult.outputColorImage(img_name + ".la.ppm", demo, d.width, d.height);
      } catch (Exception e) {
        e.printStackTrace();
      }
    }
  }
}