#define cimg_debug 2

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

using namespace cimg_library;

char buf[1024];

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

#if cimg_OS!=2
#define CASE(cmd) if (strcasecmp(pcmd, cmd) == 0)
#else
#define CASE(cmd) if (strcmpi(pcmd, cmd) == 0)
#endif

void mapImg(CImg<>& src, char* pcmd) {
	unsigned int i, j, width=src.width;
	CImg<unsigned char> c = CImg<unsigned char>(width,width,1,3,0).fill(0);
	double stmax = src.max();

	CASE("HSV") {	MAP_BMP(HSV, "HSV"); }
	CASE("JET") {	MAP_BMP(JET, "JET"); }
	CASE("COOL") { 	MAP_BMP(COOL, "COOL"); }
	CASE("SPRING") {MAP_BMP(SPRING, "SPRING"); }

	src = c;
}

void halfIt(CImg<>& img) {
        CImg<> img0=img;
        img.resize(img.width/2, img.height/2);
        img.fill(0);
        cimg_forXY(img0,x,y) {
                img(x/2,y/2) += img0(x,y);
        };
}

void usage(char* filename) {
	std::fprintf(stdout, "Usage: %s [img file (asc or bmp format)] [command lists]\n", filename);
	std::fprintf(stdout, "commands:\n");
	std::fprintf(stdout, "\t.mean\n");
	std::fprintf(stdout, "\t.addimg [img file]\n");
	std::fprintf(stdout, "\t.subimg [img file]\n");
	std::fprintf(stdout, "\t.add value\n");
	std::fprintf(stdout, "\t.sub value\n");
	std::fprintf(stdout, "\t.mul value\n");
	std::fprintf(stdout, "\t.div value\n");
	std::fprintf(stdout, "\t.sqrt\n");
	std::fprintf(stdout, "\t.log\n");
	std::fprintf(stdout, "\t.pow\n");
	std::fprintf(stdout, "\t.abs\n");
	std::fprintf(stdout, "\t.cos\n");
	std::fprintf(stdout, "\t.sin\n");
	std::fprintf(stdout, "\t.tan\n");
	std::fprintf(stdout, "\t.inverse\n");
	std::fprintf(stdout, "\t.normalize lowvalue highvalue\n");
	std::fprintf(stdout, "\t.cut lowvalue highvalue\n");
	std::fprintf(stdout, "\t.map COOL, SPRING, HSV, or JET\n");
	std::fprintf(stdout, "\t.save img file name(.asc or .bmp format)\n");
	std::fprintf(stdout, "\t.display\n");
	std::fprintf(stdout, "\t.half\n");
	std::fprintf(stdout, "\t.print\n\n");
	exit(-1);
}

int main(int argc,char **argv) {
	int i; char* pcmd;
	for (i=0; i<argc; i++) printf("%s ", argv[i]);
	if (argc < 3)
		usage(argv[0]);

	CImg<> src, src2;
	src = src.load(argv[1]);
	if (src.size() == 0) {
		printf("can't load file - %s\n", argv[1]);
		exit(-1);
	}
	
	for (i=2; i<argc; i++) {
		pcmd = argv[i];

		CASE(".mean") { printf("%f", src.mean()); continue; } 
		CASE(".addimg") { src2=src2.load(argv[++i]); src+=src2; continue; } 
		CASE(".subimg") { src2=src2.load(argv[++i]); src-=src2; continue; } 
		CASE(".add") { src+=atof(argv[++i]); continue; } 
		CASE(".sub") { src-=atof(argv[++i]); continue; } 
		CASE(".mul") { src*=atof(argv[++i]); continue; } 
		CASE(".div") { src/=atof(argv[++i]); continue; } 
		CASE(".sqrt") { src = src.sqrt(); continue; } 
		CASE(".log") { src = src.log(); continue; } 
		CASE(".pow") { src = src.pow(atof(argv[++i])); }
		CASE(".abs") { src = src.abs(); continue; } 
		CASE(".cos") { src = src.cos(); continue; } 
		CASE(".sin") { src = src.sin(); continue; } 
		CASE(".tan") { src = src.tan(); continue; } 
		CASE(".inverse") { src = src.inverse(); continue; }
		CASE(".normalize") { src = src.normalize(atof(argv[++i]), atof(argv[++i])); continue; }
		CASE(".cut") { src = src.cut(atof(argv[++i]), atof(argv[++i])); continue; }
		CASE(".save") { src.save(argv[++i]); continue; }  //ascii dlm  pnm     analyze raw     convert inr     pandore bmp
		CASE(".display") { src.display(); continue; }
		CASE(".map") { mapImg(src, argv[++i]); continue; } // map to gray, hsv, jet, cool, or spring...
		CASE(".print") { src.print(2); continue; }
		CASE(".half") { halfIt(src); continue; }
		fprintf(stdout, "Unknown command -'%s'\n", argv[i]);
	}
	
	return 0;
}

