//#include "version.h"

#include "wl_def.h"
#include "wl_main.h"
#include "wl_shade.h"
#include "wl_play.h"
#include "id_vl.h"

#define SHADE_COUNT 32

#define LSHADE_NOSHADING 0xff
#define LSHADE_NORMAL 0
#define LSHADE_FOG 5

typedef struct {
	uint8_t destRed, destGreen, destBlue;   // values between 0 and 255
	uint8_t fogStrength;
} shadedef_t;

shadedef_t shadeDefs[] = {
	{   0,   0,   0, LSHADE_NOSHADING },
	{   0,   0,   0, LSHADE_NORMAL },
	{   0,   0,   0, LSHADE_FOG },
	{  40,  40,  40, LSHADE_NORMAL },
	{  60,  60,  60, LSHADE_FOG }
};

uint8_t shadetable[SHADE_COUNT][256];
int LSHADE_flag;

#ifdef USE_FEATUREFLAGS

// The lower 8-bit of the upper left tile of every map determine
// the used shading definition of shadeDefs.
static inline int GetShadeDefID()
{
	int shadeID = ffDataTopLeft & 0x00ff;
	assert(shadeID >= 0 && shadeID < lengthof(shadeDefs));
	return shadeID;
}

#else

static int GetShadeDefID()
{
	int shadeID = 3;
	/*switch(gamestate.episode * 10 + mapon)
	{
		case  0: shadeID = 4; break;
		case  1:
		case  2:
		case  6: shadeID = 1; break;
		case  3: shadeID = 0; break;
		case  5: shadeID = 2; break;
		default: shadeID = 3; break;
	}*/
	//assert(shadeID >= 0 && shadeID < lengthof(shadeDefs));
	return shadeID;
}

#endif


// Returns the palette index of the nearest matching color of the
// given RGB color in given palette
byte GetColor(byte red, byte green, byte blue, SDL_Color *palette)
{
	byte mincol = 0;
	double mindist = 200000.F, curdist, DRed, DGreen, DBlue;

	SDL_Color *palPtr = palette;

	for(int col = 0; col < 256; col++, palPtr++)
	{
		DRed   = (double) (red   - palPtr->r);
		DGreen = (double) (green - palPtr->g);
		DBlue  = (double) (blue  - palPtr->b);
		curdist = DRed * DRed + DGreen * DGreen + DBlue * DBlue;
		if(curdist < mindist)
		{
			mindist = curdist;
			mincol = (byte) col;
		}
	}
	return mincol;
}

// Fade all colors in 32 steps down to the destination-RGB
// (use gray for fogging, black for standard shading)
void GenerateShadeTable(byte destRed, byte destGreen, byte destBlue,
						SDL_Color *palette, int fog)
{
	double curRed, curGreen, curBlue, redStep, greenStep, blueStep;
	SDL_Color *palPtr = palette;

	// Set the fog-flag
	LSHADE_flag=fog;

	// Color loop
	for(int i = 0; i < 256; i++, palPtr++)
	{
		// Get original palette color
		curRed   = palPtr->r;
		curGreen = palPtr->g;
		curBlue  = palPtr->b;

		// Calculate increment per step
		redStep   = ((double) destRed   - curRed)   / (SHADE_COUNT + 8);
		greenStep = ((double) destGreen - curGreen) / (SHADE_COUNT + 8);
		blueStep  = ((double) destBlue  - curBlue)  / (SHADE_COUNT + 8);

		// Calc color for each shade of the current color
		for (int shade = 0; shade < SHADE_COUNT; shade++)
		{
			shadetable[shade][i] = GetColor((byte) curRed, (byte) curGreen, (byte) curBlue, palette);

			// Inc to next shade
			curRed   += redStep;
			curGreen += greenStep;
			curBlue  += blueStep;
		}
	}
}

void NoShading()
{
	for(int shade = 0; shade < SHADE_COUNT; shade++)
		for(int i = 0; i < 256; i++)
			shadetable[shade][i] = i;
}

void InitLevelShadeTable()
{
	shadedef_t *shadeDef = &shadeDefs[GetShadeDefID()];
	if(shadeDef->fogStrength == LSHADE_NOSHADING)
		NoShading();
	else
		GenerateShadeTable(shadeDef->destRed, shadeDef->destGreen, shadeDef->destBlue, gamepal, shadeDef->fogStrength);
}

int GetShade(int scale)
{
	int shade = (scale >> 1) / (((viewwidth * 4) >> 8) + 1 + LSHADE_flag);  // TODO: reconsider this...
	if(shade > 32) shade = 32;
	else if(shade < 1) shade = 1;
	shade = 32 - shade;

	return shade;
}
