#include "ctype.h"
#include "assert.h"
#include "CImg.h"
#if ( defined(_MSC_VER) && _MSC_VER<=1200 ) || defined(__DMC__)
#define std
#endif

using namespace cimg_library;
#include <math.h>

#define CUT(x) (int)((((x)>1.0)?1.0:(((x)<0)?0:(x)))*255.0)
#define MAP(x, C, N) ((double)(2.0-fabs((x)*6.0/N-C)))

#define HSVR(x, N) CUT(1-MAP(x, 3, N))
#define HSVG(x, N) CUT(MAP(x, 2, N))
#define HSVB(x, N) CUT(MAP(x, 4, N))

#define JETR(x, N) CUT(MAP(x, 5, N))
#define JETG(x, N) CUT(MAP(x, 3, N))
#define JETB(x, N) CUT(MAP(x, 1, N))

#define COOLR(x, N) ((int)(x*255.0/N))
#define COOLG(x, N) ((int)(255-x*255.0/N))
#define COOLB(x, N) (255)

#define SPRINGR(x, N) (255)
#define SPRINGG(x, N) ((int)(x*255.0/N))
#define SPRINGB(x, N) ((int)(255-x*255.0/N))

#define HSV(x, N) RGB(HSVR(x,N), HSVG(x,N), HSVB(x,N))
#define JET(x, N) RGB(JETR(x,N), JETG(x,N), JETB(x,N))
#define COOL(x, N) RGB(COOLR(x,N), COOLG(x,N), COOLB(x,N))
#define SPRING(x, N) RGB(SPRINGR(x,N), SPRINGG(x,N), SPRINGB(x,N))

#define MAP_BMP(TYPE, name)	\
	for (i=0; i<width; i++) {	\
		for (j=0; j<width; j++) {	\
			c(i, j, 0) = (unsigned char)(TYPE##R(src(i,j), stmax));	\
			c(i, j, 1) = (unsigned char)(TYPE##G(src(i,j), stmax));	\
			c(i, j, 2) = (unsigned char)(TYPE##B(src(i,j), stmax));	\
		}	\
	}	sprintf(buf, "%s.%s.bmp", filename, name); if (bDisplay) imgl.insert(c); if (bSave) c.save(buf); 

char buf[1024];
int  bBlackWhite, bHSV, bJET, bCOOL, bSPRING, bDisplay, bSave, bMean;

void usage(char* filename) {
	std::fprintf(stdout, "Usage: %s [options] target\n", filename);
	std::fprintf(stdout, "\t-s save to bmp file\n");
	std::fprintf(stdout, "\t-d show bmp file in windows\n");
	std::fprintf(stdout, "\t-m using mean method instead of log method\n");
	std::fprintf(stdout, "\t-B Black/White output\n");
	std::fprintf(stdout, "\t-H HSV output\n");
	std::fprintf(stdout, "\t-J JET output\n");
	std::fprintf(stdout, "\t-C COOL output\n");
	std::fprintf(stdout, "\t-S SPRING output\n\n");
	exit(1);
}

void gen2img(char* filename) {
	unsigned int width, i, j;
	CImg<float> src; src = src.load(filename); 
	width = src.width;

	if (bMean) {
		float minvalue = src.min();
		src = src.cut(minvalue, (src.mean()*2));
	} else {
		src = ((src+1)*2.718/src.mean()).log();
	}

	double stmax = src.max();
	CImgList<> imgl;
	CImg<unsigned char> c = CImg<unsigned char>(width,width,1,3,0).fill(0);
	
	if (bHSV) {	MAP_BMP(HSV, "HSV"); }
	if (bJET) {	MAP_BMP(JET, "JET"); }
	if (bCOOL) { 	MAP_BMP(COOL, "COOL"); }
	if (bSPRING) {	MAP_BMP(SPRING, "SPRING"); }
	if (bBlackWhite) { 
		sprintf(buf, "%s.bmp", filename);
		src = src.normalize(0,255);
		if (bHSV || bJET || bCOOL || bSPRING) {
 		        for (i=0; i<width; i++) {
		                for (j=0; j<width; j++) {
		                        c(i, j, 0) = (unsigned char)(255-src(i,j));
		                        c(i, j, 1) = (unsigned char)(255-src(i,j));        
		                        c(i, j, 2) = (unsigned char)(255-src(i,j));        
		                }       
		        }
		} else {
			c = CImg<>(width,width).fill(255)-src.normalize(0, 255);
		}

		if (bDisplay) imgl.insert(c);
		if (bSave) {
			c = CImg<>(width,width).fill(255)-src.normalize(0, 255);
			c.save(buf);
		}
	}

	if (bDisplay) 
		imgl.display(filename);
	std::printf("=> %s\n", filename);
}

int getopt(char* option) {
	int j;
	for (j=0; j<(int)strlen(option); j++) {
        	memset(buf, 0, 256); buf[0] = option[j];

		if (strcmp(buf, "-") == 0) continue;
		else if (strcmp(buf, "m") == 0) { bMean = 1; }
		else if (strcmp(buf, "s") == 0) { bSave = 1; }
		else if (strcmp(buf, "d") == 0) { bDisplay = 1; }
		else if (strcmp(buf, "B") == 0) { bBlackWhite = 1; }
		else if (strcmp(buf, "H") == 0) { bHSV = 1; }
		else if (strcmp(buf, "J") == 0) { bJET = 1; }
		else if (strcmp(buf, "C") == 0) { bCOOL = 1; }
		else if (strcmp(buf, "S") == 0) { bSPRING = 1; }
		else return 0;
	}
	return 1;
}

int main(int argc,char **argv) {
	int i; char buffer[1024]; int bArgs = 0; 
	bMean = 0; bSave = 0; bDisplay =0; 
	bBlackWhite = bHSV = bJET = bCOOL = bSPRING = 0;
	
	if (argc < 2) usage(argv[0]); 
	
	for (i=1; i<argc; i++) {
		if (*argv[i] != '-')
			continue;

		bArgs = 1;

		if (!getopt(argv[i]))
			usage(argv[0]);
	}

	if (!bArgs) {
        	sprintf(buf, "%s.cfg", argv[0]);
	       	FILE* fp = fopen(buf, "r");
	        if (fp) {
	                fscanf(fp, "%s\n", buffer);
	                if (buffer[0] != '#')
	                        getopt(buffer);
	                fclose(fp);
	        }  
	}

	if (!bBlackWhite && !bHSV && !bJET && !bCOOL && !bSPRING)
		usage(argv[0]);
	
	for (i=1; i<argc; i++) {
		if (*argv[i] == '-')
			continue;

		gen2img(argv[i]);
	}

	return 0;
}

