package yi.iu.processor.color;

import java.awt.*;

import org.jmat.data.*;
import org.jmat.gui.*;
import yi.util.io.*;

/**
 * Color Utilities
 * @author Yi Li
 * @version 1.0
 */
public class ColorUtil {
  /**
   * Make a spectrum to represent all the colors int the c array
   * @param colors RGB colors stored in an array
   * @param width width of each color block in the spectrum
   * @param heigth height of each color block in the spectrum
   * @return a RGB array containing the spectrum
   */
  public static int[] createSpectrum(int[] colors, int width, int height) {
    return createSpectrum(new int[][] {colors}
                          , width, height);
  }

  /**
   * Make a spectrum to represent all the colors int the c array
   * @param colors RGB colors stored in an array
   * @param width width of each color block in the spectrum
   * @param heigth height of each color block in the spectrum
   * @return a RGB array containing the spectrum
   */
  public static int[] createSpectrum(int[][] colors, int width, int height) {
    return createSpectrum(colors, colors[0].length, width, height, 0xffffffff);
  }

  /**
   * Make a spectrum to represent all the colors int the c array.  The array
   * length on the second dimension can be different
   * @param colors RGB colors stored in an array
   * @param max_dim2 max dimension lenght of the 2nd dimension of colors
   * @param width width of each color block in the spectrum
   * @param heigth height of each color block in the spectrum
   * @param bg_color when the colors are short, what color to fill in
   * @return a RGB array containing the spectrum
   */
  public static int[] createSpectrum(int[][] colors, int max_dim2, int width,
                                     int height, int bg_color) {
    int h = colors.length;
    int[] img = new int[h * height * max_dim2 * width];

    for (int i = 0; i < h; i++) {
      int w = colors[i].length;

      for (int j = 0; j < max_dim2; j++) {
        for (int y = 0; y < height; y++) {
          for (int x = 0; x < width; x++) {
            img[ (i * height + y) * width * max_dim2 + j * width + x] =
                (j < w) ? colors[i][j] : bg_color;
          }
        }
      }
    }
    return img;
  }

  /**
   * Draw the color points in 3D color space (use jmat package)
   * @param colors each one is a rgb packed integer
   * @return
   */
  public static Plot3DPanel drawPointsInRGBSpace(int[] colors) {
    Plot3DPanel pp = new Plot3DPanel();
    for (int i = 0; i < colors.length; i++) {
      int[] rgb = yi.iu.processor.color.ColorUtil.RGB2IntArray(colors[i]);
      AbstractMatrix A = new Matrix(1, 3);
      A.set(0, 0, rgb[0]);
      A.set(0, 1, rgb[1]);
      A.set(0, 2, rgb[2]);
      pp.addPlot(A, Integer.toString(i), "SCATTER", new Color(rgb[0], rgb[1], rgb[2]));
    }
    pp.setAxesLabels("R", "G", "B");
    pp.setPreferredSize(new java.awt.Dimension(600, 600));
    FrameView viewer = new FrameView("RGB Color Space", pp);

    pp.setFixedBounds(0, 0, 255);
    pp.setFixedBounds(1, 0, 255);
    pp.setFixedBounds(2, 0, 255);

    pp.invalidate();

    return pp;

  }

  /**
   * Draw the color points in 3D color space (use jmat package)
   * @param colors each one is a rgb packed integer
   * @return
   */
  public static Plot3DPanel drawPointsInLabSpace(double[][] labs) {
    Plot3DPanel pp = new Plot3DPanel();
    for (int i = 0; i < labs.length; i++) {
      int color = yi.iu.processor.color.CIELab.lab2rgb(labs[i]);
      int[] rgb = yi.iu.processor.color.ColorUtil.RGB2IntArray(color);
      AbstractMatrix A = new Matrix(1, 3);
      A.set(0, 0, labs[i][0]);
      A.set(0, 1, labs[i][1]);
      A.set(0, 2, labs[i][2]);
      pp.addPlot(A, Integer.toString(i), "SCATTER", new Color(rgb[0], rgb[1], rgb[2]));
    }
    pp.setAxesLabels("L", "a", "b");
    pp.setPreferredSize(new java.awt.Dimension(600, 600));
    FrameView viewer = new FrameView("RGB Color Space", pp);

    pp.setFixedBounds(0, 0, 100);
    pp.setFixedBounds(1, -50, 50);
    pp.setFixedBounds(2, -50, 50);

    pp.invalidate();

    return pp;

  }

  /**
   * Pack r,g,b color components to an integer
   * @param r r component
   * @param g g component
   * @param b b component
   * @return the rgb integer
   */
  public static int packRGB(int r, int g, int b) {
    return 0xff000000 | (r << 16) | (g << 8) | b;
  }

  /**
   * Pack a gray color components to an integer
   * @param g gray level
   * @return the rgb integer
   */
  public static int packGray(int g) {
    return 0xff000000 | (g << 16) | (g << 8) | g;
  }

  /**
   * Convert a rgb color to a 3-length int array
   * @param rgb
   * @return
   */
  public static int[] RGB2IntArray(int rgb) {
    return new int[] {
        (rgb >> 16) & 0xff,
        (rgb >> 8) & 0xff,
        (rgb) & 0xff,
    };
  }

  public static void RGB2IntArray(int rgb, int[] rgb_array) {
    rgb_array[0] = (rgb >> 16) & 0xff;
    rgb_array[1] = (rgb >> 8) & 0xff;
    rgb_array[2] = (rgb) & 0xff;
  }

  /**
   * Create a rgb integer from a r,g,b component integer array
   * @param rgb the integer array
   * @return rgb integer
   */
  public static int intArray2RGB(int[] rgb) {
    return packRGB(rgb[0], rgb[1], rgb[2]);
  }

  /**
   * Return the inverse color of the given one.  For example,
   * 0xffffffff -> 0xff000000
   * @param rgb
   * @return
   */
  public static int inverseColor(int rgb) {
    return (~rgb) | 0xff000000;
  }

  /**
   * Convert the pixels from rgb to hsb.
   * @param pixels
   * @return
   */
  public static double[][] RGB2HSB(int[] pixels) {
    double[][] hsb = new double[pixels.length][3];
    float[] hsbvals = new float[3];
    int[] rgb = new int[3];
    for (int i = 0; i < pixels.length; i++) {
      // convert from pixel to rgb
      RGB2IntArray(pixels[i], rgb);
      // from rgb to hsb
      java.awt.Color.RGBtoHSB(rgb[0], rgb[1], rgb[2], hsbvals);
      hsb[i][0] = hsbvals[0];
      hsb[i][1] = hsbvals[1];
      hsb[i][2] = hsbvals[2];
    }
    return hsb;
  }

  /**
   * Print out the HSI statistics information of the given image
   */
  public static class HSIStatistics {

    public final static String USAGE = "Usage: -i img_file_name -f img_path";

    public static void main(String[] 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);
      }

      String from_path = ReadArgu.getOption('f', args, "");
      if (from_path != null) img_name = from_path + img_name;
      try {
        // read in image
        Dimension d = new Dimension();
        int[] pixels = yi.util.io.ImageIOUtil.read(img_name, d);

        double[][] hsb = RGB2HSB(pixels);

        double[] max = yi.stat.StatUtil.maximumOnCol(hsb);
        double[] min = yi.stat.StatUtil.minimumOnCol(hsb);
        System.out.println("<img src=" + img_name + ">" + "\t" +
                           min[0] + "\t" + max[0] + "\t" +
                           min[1] + "\t" + max[1] + "\t" +
                           min[2] + "\t" + max[2] + "\t");
      }
      catch (Exception e) {
        System.err.println("<img src=" + img_name + ">" + "\t" + "unreadable");
        e.printStackTrace();
      }

      System.exit(0);
    }
  }

  public static void main(String[] args) {

//    // building
//    int[] rgbs = {
//        ColorUtil.packRGB(97,141,172),
//        ColorUtil.packRGB(120,166,200),
//        ColorUtil.packRGB(102,141,175),
//        ColorUtil.packRGB(123,167,199),
//        ColorUtil.packRGB(112,159,195)
//    };

//    // overcast sky
//    int[] rgbs = {
//        ColorUtil.packRGB(240,245,248),
//        ColorUtil.packRGB(240,244,248),
//        ColorUtil.packRGB(241,245,249),
//        ColorUtil.packRGB(242,245,248),
//        ColorUtil.packRGB(240,243,248)
//    };

//    // grass
//    int[] rgbs = {
//        ColorUtil.packRGB(27,42,44),
//        ColorUtil.packRGB(54,78,63),
//        ColorUtil.packRGB(61,86,71),
//        ColorUtil.packRGB(50,74,60),
//        ColorUtil.packRGB(61,85,66)
//    };

//    // cloudy sky
//    int[] rgbs = {
//        ColorUtil.packRGB(126,95,87),
//        ColorUtil.packRGB(136,111,107),
//        ColorUtil.packRGB(135,105,96),
//        ColorUtil.packRGB(120,96,92),
//        ColorUtil.packRGB(126,101,97)
//    };

//    // bushes
//    int[] rgbs = {
//        ColorUtil.packRGB(14,21,11),
//        ColorUtil.packRGB(13,24,20),
//        ColorUtil.packRGB(11,22,12),
//        ColorUtil.packRGB(11,21,15),
//        ColorUtil.packRGB(52,66,76)
//    };

    int[][] rgbs = {
        {
        0xffff0000, 0xff00ff00, 0xff0000ff}
        , {
        0xff000000, 0xff7f7f7f, 0xffffffff}
    };
    int[] rgbs_img = ColorUtil.createSpectrum(rgbs, 30, 30);
    yi.util.io.OutputResult.outputGIFImage("mean_colors.gif", rgbs_img,
                                           30 * 3,
                                           30 * 2);

  }
}