/* ----------------------------------------
 * Origin  : GFI INFORMATIQUE 
 * Project : CDPP Propagation Tool 
 * ----------------------------------------
 * History 
 * Version : 01/05/2015 : SCA : V2.1
 * Version : 06/11/2017 : SCA : V2.2.1 
 *  Redmine #5403 - DMPT3 
 * ----------------------------------------
 */
package fr.tlse.irap.pt.client.controller.tools.common;

import java.awt.Color;
import java.awt.image.BufferedImage;
import java.awt.image.DataBuffer;
import java.awt.image.DataBufferByte;
import java.awt.image.IndexColorModel;
import java.awt.image.Raster;
import java.awt.image.SampleModel;
import java.awt.image.WritableRaster;

public class ImageHelper {

	public static final Color[] raimbowColorMap = {
		new Color(84,0,159),new Color(84,0,159),new Color(84,0,159),new Color(84,0,159),new Color(84,0,159),new Color(84,0,159),new Color(84,0,159),new Color(84,0,159),
		new Color(84,0,159),new Color(84,0,159),new Color(84,0,159),new Color(84,0,159),new Color(84,0,159),new Color(84,0,159),new Color(84,0,159),new Color(84,0,159),
		new Color(84,0,159),new Color(84,0,159),new Color(84,0,159),new Color(84,0,159),new Color(84,0,159),new Color(84,0,159),new Color(84,0,159),new Color(84,0,159),
		new Color(84,0,159),new Color(84,0,159),new Color(84,0,159),new Color(84,0,159),new Color(84,0,159),new Color(84,0,159),new Color(84,0,159),new Color(84,0,159),
		new Color(84,0,159),new Color(84,0,163),new Color(84,0,168),new Color(79,0,177),new Color(78,0,182),new Color(77,0,186),new Color(76,0,191),new Color(70,0,200),
		new Color(68,0,204),new Color(66,0,209),new Color(60,0,214),new Color(58,0,218),new Color(55,0,223),new Color(46,0,232),new Color(43,0,236),new Color(40,0,241),
		new Color(36,0,245),new Color(33,0,250),new Color(25,0,255),new Color(16,0,255),new Color(12,0,255),new Color(4,0,255),new Color(0,0,255),new Color(0,4,255),
		new Color(0,16,255),new Color(0,21,255),new Color(0,25,255),new Color(0,29,255),new Color(0,38,255),new Color(0,42,255),new Color(0,46,255),new Color(0,51,255),
		new Color(0,63,255),new Color(0,67,255),new Color(0,72,255),new Color(0,84,255),new Color(0,89,255),new Color(0,93,255),new Color(0,97,255),new Color(0,106,255),
		new Color(0,110,255),new Color(0,114,255),new Color(0,119,255),new Color(0,127,255),new Color(0,135,255),new Color(0,140,255),new Color(0,152,255),new Color(0,157,255),
		new Color(0,161,255),new Color(0,165,255),new Color(0,174,255),new Color(0,178,255),new Color(0,182,255),new Color(0,187,255),new Color(0,195,255),new Color(0,199,255),
		new Color(0,216,255),new Color(0,220,255),new Color(0,225,255),new Color(0,229,255),new Color(0,233,255),new Color(0,242,255),new Color(0,246,255),new Color(0,250,255),
		new Color(0,255,255),new Color(0,255,246),new Color(0,255,242),new Color(0,255,238),new Color(0,255,225),new Color(0,255,216),new Color(0,255,212),new Color(0,255,203),
		new Color(0,255,199),new Color(0,255,195),new Color(0,255,191),new Color(0,255,187),new Color(0,255,178),new Color(0,255,174),new Color(0,255,170),new Color(0,255,157),
		new Color(0,255,152),new Color(0,255,144),new Color(0,255,135),new Color(0,255,131),new Color(0,255,127),new Color(0,255,123),new Color(0,255,114),new Color(0,255,110),
		new Color(0,255,106),new Color(0,255,102),new Color(0,255,89),new Color(0,255,84),new Color(0,255,80),new Color(0,255,76),new Color(0,255,63),new Color(0,255,59),
		new Color(0,255,55),new Color(0,255,46),new Color(0,255,42),new Color(0,255,38),new Color(0,255,25),new Color(0,255,21),new Color(0,255,16),new Color(0,255,12),
		new Color(0,255,8),new Color(0,255,0),new Color(8,255,0),new Color(12,255,0),new Color(21,255,0),new Color(25,255,0),new Color(29,255,0),new Color(42,255,0),
		new Color(46,255,0),new Color(51,255,0),new Color(55,255,0),new Color(63,255,0),new Color(67,255,0),new Color(72,255,0),new Color(76,255,0),new Color(89,255,0),
		new Color(93,255,0),new Color(97,255,0),new Color(110,255,0),new Color(114,255,0),new Color(119,255,0),new Color(123,255,0),new Color(131,255,0),new Color(135,255,0),
		new Color(140,255,0),new Color(144,255,0),new Color(153,255,0),new Color(161,255,0),new Color(165,255,0),new Color(178,255,0),new Color(182,255,0),new Color(187,255,0),
		new Color(191,255,0),new Color(199,255,0),new Color(203,255,0),new Color(208,255,0),new Color(212,255,0),new Color(221,255,0),new Color(225,255,0),new Color(242,255,0),
		new Color(246,255,0),new Color(250,255,0),new Color(255,255,0),new Color(255,250,0),new Color(255,242,0),new Color(255,238,0),new Color(255,233,0),new Color(255,229,0),
		new Color(255,221,0),new Color(255,216,0),new Color(255,212,0),new Color(255,199,0),new Color(255,191,0),new Color(255,187,0),new Color(255,178,0),new Color(255,174,0),
		new Color(255,170,0),new Color(255,165,0),new Color(255,161,0),new Color(255,153,0),new Color(255,148,0),new Color(255,144,0),new Color(255,131,0),new Color(255,127,0),
		new Color(255,119,0),new Color(255,110,0),new Color(255,106,0),new Color(255,102,0),new Color(255,97,0),new Color(255,89,0),new Color(255,85,0),new Color(255,80,0),
		new Color(255,76,0),new Color(255,63,0),new Color(255,59,0),new Color(255,55,0),new Color(255,51,0),new Color(255,38,0),new Color(255,34,0),new Color(255,29,0),
		new Color(255,21,0),new Color(255,17,0),new Color(255,12,0),new Color(255,0,0),new Color(255,0,0),new Color(255,0,0),new Color(255,0,0),new Color(255,0,0),
		new Color(255,0,0),new Color(255,0,0),new Color(255,0,0),new Color(255,0,0),new Color(255,0,0),new Color(255,0,0),new Color(255,0,0),new Color(255,0,0),
		new Color(255,0,0),new Color(255,0,0),new Color(255,0,0),new Color(255,0,0),new Color(255,0,0),new Color(255,0,0),new Color(255,0,0),new Color(255,0,0),
		new Color(255,0,0),new Color(255,0,0),new Color(255,0,0),new Color(255,0,0),new Color(255,0,0),new Color(255,0,0),new Color(255,0,0),new Color(255,0,0),
		new Color(255,0,0),new Color(255,0,0),new Color(255,0,0),new Color(255,0,0),new Color(255,0,0),new Color(255,0,0),new Color(255,0,0),new Color(255,0,0)
	};
		
	/**
	 * Create an image from an array of bytes 
	 */
	public static BufferedImage createBufferedImage(byte[] pixels, int width, int height, Color[] colorMap) {
		SampleModel sm = getIndexSampleModel(width, height);
		DataBuffer db = new DataBufferByte(pixels, width*height, 0);
		WritableRaster raster = Raster.createWritableRaster(sm, db, null);
		
		IndexColorModel cm = null;
		if (colorMap == null) {
			cm = getDefaultColorModel();
		}
		else {
			cm = getRaimbowColorModel();	
		}
		BufferedImage image = new BufferedImage(cm, raster, false, null);
		return image;
	}

	/**
	 * Create an image from an array of floats
	 * @param contrast of image created between ]0, 10]
	 */
	public static BufferedImage createBufferedImage(float[] pixels, int width, int height, int contrast, Color[] colorMap) {
		return createBufferedImage(convert(pixels, contrast), width, height, colorMap);
	}

	/**
	 * Convert a float[] in byte[]. 
	 * @param contrast between [0, 10]
	 * @return Array of bytes complement of 2 : [0, 127]=>[0, 127].   [128, 254]=>[-127, -1]
	 */
	private static byte[] convert(float[] data, int contrast) {
		byte[] bytes = new byte[data.length];
		float max = 0;
		float min = 100;
		float maxLimit = 100000;
		
		// filter data out of limits
		float average = getAverage(data, maxLimit);
		float sd = getSD(data, maxLimit);
		maxLimit = average + contrast * sd;
		// compute min/max
		for (int i=0; i<data.length; i++) {
			if (Math.abs(data[i]) < maxLimit) {
				if (data[i] < min) {
					min = data[i];
				} 
				else if (data[i] > max) {
					max = data[i];
				}
			}
		}
		for (int i=0; i<data.length; i++) {
			bytes[i] = convertToByte(data[i], min, max);
		}
		return bytes;
	}

	/**
	 * Compute average of float array
	 */
	public static float getAverage(float[] data, float max) {
		float avg = 0;
		for (int i=0; i<data.length; i++) {
			if (Math.abs(data[i]) < max) {
				avg += data[i];
			}
		}
		return avg / data.length;
	}

	/**
	 * Compute standard deviation of float array
	 * @param data
	 * @return
	 */
	public static float getSD(float[] data, float max) {
		float avg = getAverage(data, max);
		double var = 0;
		for (int i=0; i<data.length; i++) {
			if (Math.abs(data[i]) < max) {
				var += Math.pow(data[i] - avg, 2);
			}
		}
		var = var / data.length;
		return (float) Math.sqrt(var);
	}

	/**
	 * Convert float data between min and max values to a byte [0, 255[
	 */
	private static byte convertToByte(float value, float min, float max) {
		Float f = Math.max(Math.min(value,  max), min);
		f = ((f - min) / (max - min)) * 254;
		return f.byteValue();
	}

	private static SampleModel getIndexSampleModel(int width, int height) {
		IndexColorModel icm = getDefaultColorModel();
		WritableRaster wr = icm.createCompatibleWritableRaster(1, 1);
		SampleModel sampleModel = wr.getSampleModel();
		sampleModel = sampleModel.createCompatibleSampleModel(width, height);
		return sampleModel;
	}

	/**
	 * get default color model (black and white)  
	 */
	private static IndexColorModel getDefaultColorModel() {
		byte[] r = new byte[256];
		byte[] g = new byte[256];
		byte[] b = new byte[256];
		for(int i=0; i<256; i++) {
			r[i]=(byte)i;
			g[i]=(byte)i;
			b[i]=(byte)i;
		}
		IndexColorModel defaultColorModel = new IndexColorModel(8, 256, r, g, b);
		return defaultColorModel;
	}

	/**
	 * get raimbow color model from static array  
	 */
	private static IndexColorModel getRaimbowColorModel() {
		byte[] r = new byte[256];
		byte[] g = new byte[256];
		byte[] b = new byte[256];
		for(int i=0; i<256; i++) {
			r[i]=(byte)raimbowColorMap[i].getRed();
			g[i]=(byte)raimbowColorMap[i].getGreen();
			b[i]=(byte)raimbowColorMap[i].getBlue();
		}
		IndexColorModel defaultColorModel = new IndexColorModel(8, 256, r, g, b);
		return defaultColorModel;
	}

//	private static IndexColorModel getRaimbowColorModel2() {
//		int step = 42;
//		List<Color> colors = new ArrayList<Color>();
//		for (int r=0; r<step; r++) colors.add(new Color(r*255/step,       255,         0));
//		for (int g=step; g>0; g--) colors.add(new Color(      255, g*255/step,         0));
//		for (int b=0; b<step; b++) colors.add(new Color(      255,         0, b*255/step));
//		for (int r=step; r>0; r--) colors.add(new Color(r*255/step,         0,       255));
//		for (int g=0; g<step; g++) colors.add(new Color(        0, g*255/100,       255));
//		for (int b=step; b>0; b--) colors.add(new Color(        0,       255, b*255/step));
//		for (int i=step*6; i<256; i++) {
//								   colors.add(new Color(        0,       255,         0));
//		}
//
//		byte[] r = new byte[256];
//		byte[] g = new byte[256];
//		byte[] b = new byte[256];
//		for(int i=0; i<256; i++) {
//			r[i]=(byte)colors.get(i).getRed();
//			g[i]=(byte)colors.get(i).getGreen();
//			b[i]=(byte)colors.get(i).getBlue();
//		}
//		IndexColorModel defaultColorModel = new IndexColorModel(8, 256, r, g, b);
//		return defaultColorModel;
//	}


}
