#include <stdlib.h>
#include <stdio.h>
#include <inttypes.h>
#include <algorithm>
#include "clut.h"
#include "configuration.h"
#include <string.h>
#include <vdr/osdbase.h>
#include <vdr/tools.h>

/*
static uint32_t default_2bit[4] = {
0x00000000,
0xFFFFFFFF,
0xFF000000,
0xFF808080
};
static uint32_t default_4bit[16] = {
0xFF000000,
0xFF000080,
0xFF008000,
0xFF008080,
0xFF800000,
0xFF800080,
0xFF808000,
0xFF808080,
0xFF000000,
0xFF0000FF,
0xFF00FF00,
0xFF00FFFF,
0xFFFF0000,
0xFFFF00FF,
0xFFFFFF00,
0xFFFFFFFF,
};
static uint32_t default_8bit[256] = {
0x00000000,0xBF0000FF,0xBF00FF00,0xBF00FFFF,
0xBFFF0000,0xBFFF00FF,0xBFFFFF00,0xBFFFFFFF,
0x80000000,0x80000055,0x80005500,0x80005555,
0x80550000,0x80550055,0x80555500,0x80555555,
0xBF000000,0xBF0000FF,0xBF00FF00,0xBF00FFFF,
0xBFFF0000,0xBFFF00FF,0xBFFFFF00,0xBFFFFFFF,
0x800000AA,0x800000FF,0x800055AA,0x800055FF,
0x805500AA,0x805500FF,0x805555AA,0x805555FF,
0xBF000000,0xBF0000FF,0xBF00FF00,0xBF00FFFF,
0xBFFF0000,0xBFFF00FF,0xBFFFFF00,0xBFFFFFFF,
0x8000AA00,0x8000AA55,0x8000FF00,0x8000FF55,
0x8055AA00,0x8055AA55,0x8055FF00,0x8055FF55,
0xBF000000,0xBF0000FF,0xBF00FF00,0xBF00FFFF,
0xBFFF0000,0xBFFF00FF,0xBFFFFF00,0xBFFFFFFF,
0x8000AAAA,0x8000AAFF,0x8000FFAA,0x8000FFFF,
0x8055AAAA,0x8055AAFF,0x8055FFAA,0x8055FFFF,
0xBF000000,0xBF0000FF,0xBF00FF00,0xBF00FFFF,
0xBFFF0000,0xBFFF00FF,0xBFFFFF00,0xBFFFFFFF,
0x80AA0000,0x80AA0055,0x80AA5500,0x80AA5555,
0x80FF0000,0x80FF0055,0x80FF5500,0x80FF5555,
0xBF000000,0xBF0000FF,0xBF00FF00,0xBF00FFFF,
0xBFFF0000,0xBFFF00FF,0xBFFFFF00,0xBFFFFFFF,
0x80AA00AA,0x80AA00FF,0x80AA55AA,0x80AA55FF,
0x80FF00AA,0x80FF00FF,0x80FF55AA,0x80FF55FF,
0xBF000000,0xBF0000FF,0xBF00FF00,0xBF00FFFF,
0xBFFF0000,0xBFFF00FF,0xBFFFFF00,0xBFFFFFFF,
0x80AAAA00,0x80AAAA55,0x80AAFF00,0x80AAFF55,
0x80FFAA00,0x80FFAA55,0x80FFFF00,0x80FFFF55,
0xBF000000,0xBF0000FF,0xBF00FF00,0xBF00FFFF,
0xBFFF0000,0xBFFF00FF,0xBFFFFF00,0xBFFFFFFF,
0x80AAAAAA,0x80AAAAFF,0x80AAFFAA,0x80AAFFFF,
0x80FFAAAA,0x80FFAAFF,0x80FFFFAA,0x80FFFFFF,
0xFF7F7F7F,0xFF7F7FAA,0xFF7FAA7F,0xFF7FAAAA,
0xFFAA7F7F,0xFFAA7FAA,0xFFAAAA7F,0xFFAAAAAA,
0xFF000000,0xFF00002B,0xFF002B00,0xFF002B2B,
0xFF2B0000,0xFF2B002B,0xFF2B2B00,0xFF2B2B2B,
0xFF7F7FD4,0xFF7F7FFF,0xFF7FAAD4,0xFF7FAAFF,
0xFFAA7FD4,0xFFAA7FFF,0xFFAAAAD4,0xFFAAAAFF,
0xFF000055,0xFF000080,0xFF002B55,0xFF002B80,
0xFF2B0055,0xFF2B0080,0xFF2B2B55,0xFF2B2B80,
0xFF7FD47F,0xFF7FD4AA,0xFF7FFF7F,0xFF7FFFAA,
0xFFAAD47F,0xFFAAD4AA,0xFFAAFF7F,0xFFAAFFAA,
0xFF005500,0xFF00552B,0xFF008000,0xFF00802B,
0xFF2B5500,0xFF2B552B,0xFF2B8000,0xFF2B802B,
0xFF7FD4D4,0xFF7FD4FF,0xFF7FFFD4,0xFF7FFFFF,
0xFFAAD4D4,0xFFAAD4FF,0xFFAAFFD4,0xFFAAFFFF,
0xFF005555,0xFF005580,0xFF008055,0xFF008080,
0xFF2B5555,0xFF2B5580,0xFF2B8055,0xFF2B8080,
0xFFD47F7F,0xFFD47FAA,0xFFD4AA7F,0xFFD4AAAA,
0xFFFF7F7F,0xFFFF7FAA,0xFFFFAA7F,0xFFFFAAAA,
0xFF550000,0xFF55002B,0xFF552B00,0xFF552B2B,
0xFF800000,0xFF80002B,0xFF802B00,0xFF802B2B,
0xFFD47FD4,0xFFD47FFF,0xFFD4AAD4,0xFFD4AAFF,
0xFFFF7FD4,0xFFFF7FFF,0xFFFFAAD4,0xFFFFAAFF,
0xFF550055,0xFF550080,0xFF552B55,0xFF552B80,
0xFF800055,0xFF800080,0xFF802B55,0xFF802B80,
0xFFD4D47F,0xFFD4D4AA,0xFFD4FF7F,0xFFD4FFAA,
0xFFFFD47F,0xFFFFD4AA,0xFFFFFF7F,0xFFFFFFAA,
0xFF555500,0xFF55552B,0xFF558000,0xFF55802B,
0xFF805500,0xFF80552B,0xFF808000,0xFF80802B,
0xFFD4D4D4,0xFFD4D4FF,0xFFD4FFD4,0xFFD4FFFF,
0xFFFFD4D4,0xFFFFD4FF,0xFFFFFFD4,0xFFFFFFFF,
0xFF555555,0xFF555580,0xFF558055,0xFF558080,
0xFF805555,0xFF805580,0xFF808055,0xFF808080
};
*/

cSubtitlesPalette::cSubtitlesPalette(int bpp)
{
  if (bpp != 2 && bpp != 4 && bpp != 8)
    bpp = 8;

  maxColors = 1<<bpp;

  for (int i = 0; i < MAX_COLORS; i++)
  {
      colors[i] = clrWhite;
  }

}
cSubtitlesPalette::~cSubtitlesPalette()
{
}

void cSubtitlesPalette::SetColor(int index, uint32_t value)
{
  if (index >=0 && index < maxColors)
    colors[index] = value;
}

uint32_t cSubtitlesPalette::GetColor(int index) const
{
  if (index >0 && index < maxColors)
    return colors[index];
  return 0;

}
const cSubtitlesPalette *Clut::GetPalette(int bpp) const
{
  switch (bpp)
  {
  case 2:
    return &palette2;
  case 4:
    return &palette4;
  case 8:
    return &palette8;
  default:
    dsyslog("Clut::GetPalette with invalid bpp = %d",bpp);
    return NULL;
  }
  return NULL;
}

Clut::Clut( int aId )
:palette2(2),palette4(4),palette8(8){
  iId = aId;


}

Clut::~Clut()
{

}

int Clut::Id()
{

  return iId;

}

static uint32_t yuv2rgb(int Y,int Cb, int Cr)
{
    int Ey, Epb, Epr;
    int Eg, Eb, Er;

    Ey = (Y - 16);
    Epb = (Cb - 128);
    Epr = (Cr - 128);
    /* ITU-R 709 */
    Er = std::max(std::min(((298 * Ey             + 460 * Epr) / 256), 255), 0);
    Eg = std::max(std::min(((298 * Ey -  55 * Epb - 137 * Epr) / 256), 255), 0);
    Eb = std::max(std::min(((298 * Ey + 543 * Epb            ) / 256), 255), 0);

    return (Er << 16) | (Eg << 8) | Eb;
}


void Clut::Decode(unsigned char* Data, int Size)
{
    
    int pl = 0;

    while (pl < Size)
    {
	unsigned char entry_id = Data[pl++];

	bool full_range = (Data[pl]&0x01)!=0;
	unsigned char entry_flags = Data[pl++]&0xE0;
	
	unsigned char y;
	unsigned char cr;
	unsigned char cb;
	unsigned char t;
	if (full_range)
	{
	    y  = Data[pl++];
	    cr = Data[pl++];
	    cb = Data[pl++];
	    t  = Data[pl++];

	}
	else
	{
	    y   =  Data[pl] & 0xFC;
	    cr  =  (Data[pl++] & 0x03) << 6;
	    cr |=  (Data[pl]   & 0xC0) >> 2;
	    cb  =  (Data[pl]   & 0x3C) << 2;
	    t   =  (Data[pl++] & 0x03) << 6;
	}
	
	uint32_t value;
	if ( y == 0 )
	{
	  value = 0;
	}
	else
	{
	  value = yuv2rgb(y,cb,cr);
	  if (value)
	    value |= (((10-gSubtitlesConfiguration.fgTransparency) * (255 - t)) / 10) << 24;
	  else
	    value |= (((10-gSubtitlesConfiguration.bgTransparency) * (255 - t)) / 10) << 24;
	}

	
	if ((entry_flags & 0x80) && (entry_id<4))
	{
	  palette2.SetColor(entry_id,value);
	}

	if ((entry_flags & 0x40) && (entry_id < 16))
	{
	    palette4.SetColor(entry_id,value);
	}

	if ((entry_flags & 0x20))
	{
	  palette8.SetColor(entry_id,value);
	}
    }

}
