/**
 **
 ** ThermalColor.java - Color mapping utilities for LWIR thermal imagery
 **
 ** Copyright (C) 2019-2023 Elphel, Inc.
 **
 ** -----------------------------------------------------------------------------**
 **
 **  ThermalColor.java is free software: you can redistribute it and/or modify
 **  it under the terms of the GNU General Public License as published by
 **  the Free Software Foundation, either version 3 of the License, or
 **  (at your option) any later version.
 **
 **  This program is distributed in the hope that it will be useful,
 **  but WITHOUT ANY WARRANTY; without even the implied warranty of
 **  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 **  GNU General Public License for more details.
 **
 **  You should have received a copy of the GNU General Public License
 **  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 ** -----------------------------------------------------------------------------**
 **
 */
package com.elphel.imagej.cameras;

public class ThermalColor {
	private static double PALETTE_RANGE = 255.0;
	double [][] palette = null;
	double      min = 0.0;
	double      max = 1.0;
	double      out_range = 255.0;

	public ThermalColor(
			int    palette_indx,
			double min,
			double max,
			double out_range) {
		this.min = min;
		this.max = max;
		this.out_range = out_range;
		int [] ipalette = setupPalette(palette_indx);
		this.palette = new double [ipalette.length][3];
		for (int i = 0; i < ipalette.length; i++) {
			this.palette[i][0] =   (ipalette[i] >> 16) & 0xff; // Red
			this.palette[i][1] =   (ipalette[i] >>  8) & 0xff; // Green
			this.palette[i][2] =   (ipalette[i] >>  0) & 0xff; // Blue
		}
	}

	public double [] getRGB(double v) { // Get R,G,B (0..255) triplet for input value in the range 0..1
		double k = out_range/PALETTE_RANGE;
		double value = (v-min)/(max-min) * (this.palette.length - 1);
		int ivalue = (int) (value);
		if (value < 0) return this.palette[0];
		if (value >= (this.palette.length -1)) return this.palette[this.palette.length -1];
		double a = (value-ivalue); // 0..1
		double [] rslt = {
				k*((1 - a) * this.palette[ivalue][0] + a * this.palette[ivalue+1][0]),
				k*((1 - a) * this.palette[ivalue][1] + a * this.palette[ivalue+1][1]),
				k*((1 - a) * this.palette[ivalue][2] + a * this.palette[ivalue+1][2])};
		return rslt;
	}

	public float [] getRGB(float v) { // Get R,G,B (0..255) triplet for input value in the range 0..1
		double k = out_range/PALETTE_RANGE;
		double value = (v-min)/(max-min) * (this.palette.length - 1);
		int ivalue = (int) (value);
		if (ivalue < 0) {
//			return getRGB((float) min); // this.palette[0];
			return new float[] {
					(float) this.palette[0][0],
					(float) this.palette[0][1],
					(float) this.palette[0][2]};
		}
		if (ivalue >= (this.palette.length -1)) {
//			return getRGB((float) max); // this.palette[this.palette.length -1];
			return new float[] {
				(float) this.palette[this.palette.length -1][0],
				(float) this.palette[this.palette.length -1][1],
				(float) this.palette[this.palette.length -1][2]};
		}
		double a = (value-ivalue); // 0..1
		float [] rslt = {
				(float) (k*((1 - a) * this.palette[ivalue][0] + a * this.palette[ivalue+1][0])),
				(float) (k*((1 - a) * this.palette[ivalue][1] + a * this.palette[ivalue+1][1])),
				(float) (k*((1 - a) * this.palette[ivalue][2] + a * this.palette[ivalue+1][2]))};
		return rslt;
	}

	private int []  setupPalette(int indx) {
		//https://stackoverflow.com/questions/28495390/thermal-imaging-palette
		int [] white_hot_palette = {0x000000, 0xffffff};
		int [] black_hot_palette = {0xffffff, 0x000000};
		int [] iron_palette = {
				0x00000a, 0x000014, 0x00001e, 0x000025, 0x00002a, 0x00002e, 0x000032, 0x000036,
				0x00003a, 0x00003e, 0x000042, 0x000046, 0x00004a, 0x00004f, 0x000052, 0x010055,
				0x010057, 0x020059, 0x02005c, 0x03005e, 0x040061, 0x040063, 0x050065, 0x060067,
				0x070069, 0x08006b, 0x09006e, 0x0a0070, 0x0b0073, 0x0c0074, 0x0d0075, 0x0d0076,
				0x0e0077, 0x100078, 0x120079, 0x13007b, 0x15007c, 0x17007d, 0x19007e, 0x1b0080,
				0x1c0081, 0x1e0083, 0x200084, 0x220085, 0x240086, 0x260087, 0x280089, 0x2a0089,
				0x2c008a, 0x2e008b, 0x30008c, 0x32008d, 0x34008e, 0x36008e, 0x38008f, 0x390090,
				0x3b0091, 0x3c0092, 0x3e0093, 0x3f0093, 0x410094, 0x420095, 0x440095, 0x450096,
				0x470096, 0x490096, 0x4a0096, 0x4c0097, 0x4e0097, 0x4f0097, 0x510097, 0x520098,
				0x540098, 0x560098, 0x580099, 0x5a0099, 0x5c0099, 0x5d009a, 0x5f009a, 0x61009b,
				0x63009b, 0x64009b, 0x66009b, 0x68009b, 0x6a009b, 0x6c009c, 0x6d009c, 0x6f009c,
				0x70009c, 0x71009d, 0x73009d, 0x75009d, 0x77009d, 0x78009d, 0x7a009d, 0x7c009d,
				0x7e009d, 0x7f009d, 0x81009d, 0x83009d, 0x84009d, 0x86009d, 0x87009d, 0x89009d,
				0x8a009d, 0x8b009d, 0x8d009d, 0x8f009c, 0x91009c, 0x93009c, 0x95009c, 0x96009b,
				0x98009b, 0x99009b, 0x9b009b, 0x9c009b, 0x9d009b, 0x9f009b, 0xa0009b, 0xa2009b,
				0xa3009b, 0xa4009b, 0xa6009a, 0xa7009a, 0xa8009a, 0xa90099, 0xaa0099, 0xab0099,
				0xad0099, 0xae0198, 0xaf0198, 0xb00198, 0xb00198, 0xb10197, 0xb20197, 0xb30196,
				0xb40296, 0xb50295, 0xb60295, 0xb70395, 0xb80395, 0xb90495, 0xba0495, 0xba0494,
				0xbb0593, 0xbc0593, 0xbd0593, 0xbe0692, 0xbf0692, 0xbf0692, 0xc00791, 0xc00791,
				0xc10890, 0xc10990, 0xc20a8f, 0xc30a8e, 0xc30b8e, 0xc40c8d, 0xc50c8c, 0xc60d8b,
				0xc60e8a, 0xc70f89, 0xc81088, 0xc91187, 0xca1286, 0xca1385, 0xcb1385, 0xcb1484,
				0xcc1582, 0xcd1681, 0xce1780, 0xce187e, 0xcf187c, 0xcf197b, 0xd01a79, 0xd11b78,
				0xd11c76, 0xd21c75, 0xd21d74, 0xd31e72, 0xd32071, 0xd4216f, 0xd4226e, 0xd5236b,
				0xd52469, 0xd62567, 0xd72665, 0xd82764, 0xd82862, 0xd92a60, 0xda2b5e, 0xda2c5c,
				0xdb2e5a, 0xdb2f57, 0xdc2f54, 0xdd3051, 0xdd314e, 0xde324a, 0xde3347, 0xdf3444,
				0xdf3541, 0xdf363d, 0xe0373a, 0xe03837, 0xe03933, 0xe13a30, 0xe23b2d, 0xe23c2a,
				0xe33d26, 0xe33e23, 0xe43f20, 0xe4411d, 0xe4421c, 0xe5431b, 0xe54419, 0xe54518,
				0xe64616, 0xe74715, 0xe74814, 0xe74913, 0xe84a12, 0xe84c10, 0xe84c0f, 0xe94d0e,
				0xe94d0d, 0xea4e0c, 0xea4f0c, 0xeb500b, 0xeb510a, 0xeb520a, 0xeb5309, 0xec5409,
				0xec5608, 0xec5708, 0xec5808, 0xed5907, 0xed5a07, 0xed5b06, 0xee5c06, 0xee5c05,
				0xee5d05, 0xee5e05, 0xef5f04, 0xef6004, 0xef6104, 0xef6204, 0xf06303, 0xf06403,
				0xf06503, 0xf16603, 0xf16603, 0xf16703, 0xf16803, 0xf16902, 0xf16a02, 0xf16b02,
				0xf16b02, 0xf26c01, 0xf26d01, 0xf26e01, 0xf36f01, 0xf37001, 0xf37101, 0xf37201,
				0xf47300, 0xf47400, 0xf47500, 0xf47600, 0xf47700, 0xf47800, 0xf47a00, 0xf57b00,
				0xf57c00, 0xf57e00, 0xf57f00, 0xf68000, 0xf68100, 0xf68200, 0xf78300, 0xf78400,
				0xf78500, 0xf78600, 0xf88700, 0xf88800, 0xf88800, 0xf88900, 0xf88a00, 0xf88b00,
				0xf88c00, 0xf98d00, 0xf98d00, 0xf98e00, 0xf98f00, 0xf99000, 0xf99100, 0xf99200,
				0xf99300, 0xfa9400, 0xfa9500, 0xfa9600, 0xfb9800, 0xfb9900, 0xfb9a00, 0xfb9c00,
				0xfc9d00, 0xfc9f00, 0xfca000, 0xfca100, 0xfda200, 0xfda300, 0xfda400, 0xfda600,
				0xfda700, 0xfda800, 0xfdaa00, 0xfdab00, 0xfdac00, 0xfdad00, 0xfdae00, 0xfeaf00,
				0xfeb000, 0xfeb100, 0xfeb200, 0xfeb300, 0xfeb400, 0xfeb500, 0xfeb600, 0xfeb800,
				0xfeb900, 0xfeb900, 0xfeba00, 0xfebb00, 0xfebc00, 0xfebd00, 0xfebe00, 0xfec000,
				0xfec100, 0xfec200, 0xfec300, 0xfec400, 0xfec500, 0xfec600, 0xfec700, 0xfec800,
				0xfec901, 0xfeca01, 0xfeca01, 0xfecb01, 0xfecc02, 0xfecd02, 0xfece03, 0xfecf04,
				0xfecf04, 0xfed005, 0xfed106, 0xfed308, 0xfed409, 0xfed50a, 0xfed60a, 0xfed70b,
				0xfed80c, 0xfed90d, 0xffda0e, 0xffda0e, 0xffdb10, 0xffdc12, 0xffdc14, 0xffdd16,
				0xffde19, 0xffde1b, 0xffdf1e, 0xffe020, 0xffe122, 0xffe224, 0xffe226, 0xffe328,
				0xffe42b, 0xffe42e, 0xffe531, 0xffe635, 0xffe638, 0xffe73c, 0xffe83f, 0xffe943,
				0xffea46, 0xffeb49, 0xffeb4d, 0xffec50, 0xffed54, 0xffee57, 0xffee5b, 0xffee5f,
				0xffef63, 0xffef67, 0xfff06a, 0xfff06e, 0xfff172, 0xfff177, 0xfff17b, 0xfff280,
				0xfff285, 0xfff28a, 0xfff38e, 0xfff492, 0xfff496, 0xfff49a, 0xfff59e, 0xfff5a2,
				0xfff5a6, 0xfff6aa, 0xfff6af, 0xfff7b3, 0xfff7b6, 0xfff8ba, 0xfff8bd, 0xfff8c1,
				0xfff8c4, 0xfff9c7, 0xfff9ca, 0xfff9cd, 0xfffad1, 0xfffad4, 0xfffbd8, 0xfffcdb,
				0xfffcdf, 0xfffde2, 0xfffde5, 0xfffde8, 0xfffeeb, 0xfffeee, 0xfffef1, 0xfffef4,
				0xffffff};
		int [] pal01_palette = {0x1f77b4,0xff7f0e,
				0x2ca02c,
				0xd62728,
				0x9467bd,
				0x8c564b,
				0xe377c2,
				0x7f7f7f,
				0xbcbd22,
				0x17becf};
		int [] viridis_palette = {
				0x46317e,
				0x365b8c,
				0x277e8e,
				0x1fa187,
				0x49c16d,
				0x9fd938};
		
		int [] viridis_mod_palette = {
				0x401080,
				0x46317e,
				0x365b8c,
				0x277e8e,
				0x1fa187,
				0x49c16d,
				0x9fd938,
				0xcc9000,
				0xff6000
				};
		
		int [] coolwarm_palette = {
				0x6788ed ,
				0x99bafe ,
				0xc8d7ef ,
				0xedd0c1 ,
				0xf6a789 ,
				0xe16852};
		int [] cubehelix_palette = {
				0x1a2341 ,
				0x1b6144 ,
				0x687a30 ,
				0xc77a7c ,
				0xcda2e0 ,
				0xc6e1f1};
		int [] hsv_palette = {		
				0xffd400 ,
				0x4eff00 ,
				0xff85 ,
				0x9dff ,
				0x3600ff ,
				0xff00ec};
		int [] hsv2_palette = {		
				0xffd400 ,
				0x4eff00 ,
				0xff85 ,
				0x9dff ,
				0x3600ff ,
				0xff00ec,
				0xffd400 ,
				0x4eff00 ,
				0xff85 ,
				0x9dff ,
				0x3600ff ,
				0xff00ec};
		int [] hsv3_palette = {		
				0xffd400 ,
				0x4eff00 ,
				0xff85 ,
				0x9dff ,
				0x3600ff ,
				0xff00ec,
				0xffd400 ,
				0x4eff00 ,
				0xff85 ,
				0x9dff ,
				0x3600ff ,
				0xff00ec ,
				0xffd400 ,
				0x4eff00 ,
				0xff85 ,
				0x9dff ,
				0x3600ff ,
				0xff00ec};
		
		int [] spectral_palette = {		
				0xe1514a ,
				0xfba55c ,
				0xfee899 ,
				0xecf7a2 ,
				0xa1d9a4 ,
				0x479fb3};

		int [] spectral_r_palette = {		
				0x479fb3 ,
				0xa1d9a4 ,
				0xecf7a2 ,
				0xfee899 ,
				0xfba55c ,
				0xe1514a};


		int [][] palettes = {
				white_hot_palette,
				black_hot_palette,
				iron_palette,
				pal01_palette,
				viridis_palette,
				coolwarm_palette,
				cubehelix_palette,
				hsv_palette,
				hsv2_palette,
				hsv3_palette,
				viridis_mod_palette,
				spectral_palette,
				spectral_r_palette
		};
		if (indx <0) indx = 0;
		else if (indx >= palettes.length) indx = palettes.length - 1;
		return palettes[indx];
	}




}
