/***************************** LICENSE START ***********************************

 Copyright 2012 ECMWF and INPE. This software is distributed under the terms
 of the Apache License version 2.0. In applying this license, ECMWF does not
 waive the privileges and immunities granted to it by virtue of its status as
 an Intergovernmental Organization or submit itself to any jurisdiction.

 ***************************** LICENSE END *************************************/

#ifndef XPalette_H
#include "XPalette.h"
#endif

#ifndef MetviewUI_H
#include "MetviewUI.h"
#endif

#ifndef ConfigLoader_H
#include "ConfigLoader.h"
#endif

#include <Palette.h>
#include <ctype.h>
#include <math.h>

#ifndef Tokenizer_H
#include "Tokenizer.h"
#endif


static Palette palette = 0;
static map<string,RGBColor> colors;
static vector<string>  names;

void XPalette::load(request* r)
{
	const char* fname = get_value(r,"colour_file",0);
	if(!fname) return;

	FILE *f = fopen(fname, "r");

	if (!f) return;

	char		   line[500];
	char           color[80];
	char           name[80];

	palette = NewPalette(MetviewUI::root());

	while(fgets(line,sizeof(line),f))
	{
		char *p = line;
		int  i = 0;

		sscanf(p,"%s ; %s",color,name);
		while(*p && !i)
		{
			
			if(*p == '#')
			{
				color[i++] = *p++;
				while(*p && isxdigit(*p))
					color[i++] = *p++;
				color[i] = 0;
				if(i != 4 && i != 7 && i != 13)
					i = 0;
			}
			p++;
		}
		if(i) {
			names.push_back(name);
			PaletteNameToRGB(palette,color,&colors[name]);
		}
	}

	fclose(f);
}


Pixel XPalette::pixel(const string& name)
{
	static map<string,Pixel> cache;
	map<string,Pixel>::iterator j = cache.find(name);

	if(j != cache.end())
		return (*j).second;

	Pixel p = PaletteNamedColor(palette,name.c_str());
	cache[name] = p;
	return p;
}

void XPalette::scan(PaletteScanner& p)
{
	for(vector<string>::iterator j = names.begin(); j != names.end(); ++j)
		p.next(*j);
}

void XPalette::convert(const string& name,RGBColor& c)
{
	map<string,RGBColor>::iterator j = colors.find(name);
	if(j == colors.end())
		magics(name);

	c = colors[name];
}

bool XPalette::exists(const string& name)
{
	return colors.find(name) != colors.end();
}

inline bool same(double a,double b)
{
	return abs(a-b) < 0.001;
}

bool XPalette::convert(const RGBColor& c,string& name)
{
	RGBColor r;
	for(map<string,RGBColor>::iterator j = colors.begin(); j != colors.end(); ++j)
	{
		const RGBColor& r = (*j).second;
		if(same(c.red,r.red) && same(c.green,r.green) && same(c.blue,r.blue))
		{
			name = (*j).first;
			return true;
		}
	}
	return false;
}

Pixel XPalette::magics(const string& name)
{
	map<string,RGBColor>::iterator j = colors.find(name);
	if(j != colors.end())
		return PaletteRGBColor(palette,&(*j).second);

	Tokenizer parse("(, )");
	vector<string> v;

	parse(name,v);

	RGBColor c;
	HSLColor h;

	// Try rgb, hsl

	if(v.size() == 4)
	{
		double x1 = atof(v[1].c_str());
		double x2 = atof(v[2].c_str());
		double x3 = atof(v[3].c_str());

		switch(v[0][0])
		{
			case 'r':
			case 'R':
				c = RGBColor(x1,x2,x3);
				break;

			case 'h':
			case 'H':
				h = HSLColor(x1,x2,x3);
				PaletteHSLToRGB(palette,&h,&c);
				break;
		}

	}

	colors[name] = c;
	return PaletteRGBColor(palette,&c);
}

Pixel XPalette::pixel(const RGBColor& c)
{
	return PaletteRGBColor(palette,&c);
}

Pixel XPalette::pixel(const HSLColor& c)
{
	return PaletteHSLColor(palette,&c);
}

void XPalette::convert(const RGBColor& a,HSLColor& b)
{
	PaletteRGBToHSL(palette,&a,&b);
}

void XPalette::convert(const HSLColor& a,RGBColor& b)
{
	PaletteHSLToRGB(palette,&a,&b);
}


static SimpleLoader<XPalette> load("resources",0);
