#include <string.h>

#include <vdr/tools.h>

#include "osd.h"
#include "common.h"

#include <unistd.h>




class cDummyOsd: public cOsd
{
public:
#if APIVERSNUM < 10509
	cDummyOsd(int Left, int Top) : cOsd(Left,Top) { };
#else
	cDummyOsd(int Left, int Top, uint Level) : cOsd(Left,Top,Level) { };
#endif	
	virtual ~cDummyOsd() {};
};



class cOsdEm84xx2mb: public cOsdEm84xx
{
private:
	static unsigned char mCompressedOsdBuffer[_EM84OSD_2MB_SIZE];
	static int mLastOsdSize;

protected:
	virtual void displayOSD(int x, int y);

	static int Compress2(int iBitmapWidth, unsigned char* iBuffer, int iBufferSize, unsigned char* oBuffer, int oBufferSize, int* oCompressedLines);
	static int Compress4(int iBitmapWidth, unsigned char* iBuffer, int iBufferSize, unsigned char* oBuffer, int oBufferSize, int* oCompressedLines);	
	static int Compress7(int iBitmapWidth, unsigned char* iBuffer, int iBufferSize, unsigned char* oBuffer, int oBufferSize, int* oCompressedLines);

public:
#if APIVERSNUM < 10509
	cOsdEm84xx2mb(int Left, int Top);
#else
	cOsdEm84xx2mb(int Left, int Top, uint Level);
#endif	
	virtual ~cOsdEm84xx2mb();

	virtual eOsdError CanHandleAreas(const tArea *Areas, int NumAreas);
};

class cOsdEm84xx4mb: public cOsdEm84xx
{	
protected:
	virtual void displayOSD(int x, int y);

public:
#if APIVERSNUM < 10509
	cOsdEm84xx4mb(int Left, int Top);
#else
	cOsdEm84xx4mb(int Left, int Top, uint Level);
#endif	
	virtual ~cOsdEm84xx4mb();
};








cOsdProviderEm84xx::cOsdProviderEm84xx(bool iOsdHas4mb) :
	mOsd4mb(iOsdHas4mb),
	mOsdEnabled(true)
{
}

#if APIVERSNUM < 10509
cOsd* cOsdProviderEm84xx::CreateOsd(int Left, int Top)
#else
cOsd* cOsdProviderEm84xx::CreateOsd(int Left, int Top, uint Level)
#endif
{
	if (!mOsdEnabled)
#if APIVERSNUM < 10509
		return new cDummyOsd(Left, Top); // create a dummy cOsd, so that access won't result in a segfault
#else
		return new cDummyOsd(Left, Top, Level); // create a dummy cOsd, so that access won't result in a segfault
#endif		

	if (mOsd4mb)
#if APIVERSNUM < 10509
		return new cOsdEm84xx4mb(Left, Top);
#else
		return new cOsdEm84xx4mb(Left, Top, Level);
#endif		
	else
#if APIVERSNUM < 10509
		return new cOsdEm84xx2mb(Left, Top);
#else
		return new cOsdEm84xx2mb(Left, Top, Level);
#endif		
}

void cOsdProviderEm84xx::Enable(bool Enable)
{
	mOsdEnabled = Enable;
}

bool cOsdProviderEm84xx::IsEnabled()
{
	return mOsdEnabled;
}


IOsd* cOsdEm84xx::mOsd = NULL;
unsigned char cOsdEm84xx::mOsdBuffer[_EM84OSD_OSDBUFFERSIZE];
EM84PALENTRY cOsdEm84xx::mPaletteEM84[_EM84OSD_PALETTESIZE];
int cOsdEm84xx::mUsedColors = 0;
int cOsdEm84xx::mMaxColors = _EM84OSD_PALETTESIZE;
int cOsdEm84xx::mCurrentWidth = _EM84OSD_MAXWIDTH;
int cOsdEm84xx::mCurrentHeight = _EM84OSD_MAXHEIGHT;
int cOsdEm84xx::mOffsetX = 0;
int cOsdEm84xx::mOffsetY = 0;

#if APIVERSNUM < 10509
cOsdEm84xx::cOsdEm84xx(int Left, int Top):
		cOsd(Left, Top)
#else
cOsdEm84xx::cOsdEm84xx(int Left, int Top, uint Level):
		cOsd(Left, Top, Level)
#endif		
{
	mCurrentWidth = _EM84OSD_MAXWIDTH;
	mCurrentHeight = _EM84OSD_MAXHEIGHT;
	mOffsetX = 0;
	mOffsetY = 0;

	if ((mOsd == NULL) && (FMPQueryInterface(IID_IOSD, (void**)&mOsd)))
	{
		Dprintf("could not open OSD\n");
		mOsd = NULL;
  	}	
}

cOsdEm84xx::~cOsdEm84xx()
{
	if (mOsd)
	{
		mOsd->lpVtbl->Off(mOsd);
		mOsd->lpVtbl->Flush(mOsd);

		mOsd = NULL;
	}
}

bool cOsdEm84xx::GetOsdBufferRGB(unsigned char *oImageBuffer)
{
	if (!cOsd::IsOpen())
		return false;

	/*int wStartX = mOffsetX;
	int wStartY = mOffsetY;
	int wStopX = mOffsetX + mCurrentWidth;
	int wStopY = mOffsetY + mCurrentHeight;
	if (wStartX < 0)
		wStartX = 0;
	if (wStartY < 0)
		wStartY = 0;
	if (wStartX >= _EM84OSD_MAXWIDTH)
		wStartX = (_EM84OSD_MAXWIDTH-1);
	if (wStartY >= _EM84OSD_MAXHEIGHT)
		wStartY = (_EM84OSD_MAXHEIGHT-1);
	if (wStopX < 0)
		wStopX = 0;
	if (wStopY < 0)
		wStopY = 0;
	if (wStopX > _EM84OSD_MAXWIDTH)
		wStopX = (_EM84OSD_MAXWIDTH);
	if (wStopY > _EM84OSD_MAXHEIGHT)
		wStopY = (_EM84OSD_MAXHEIGHT);*/
	
	/*if ((wStopX < wStartX) || (wStopY < wStartY))
	{
		esyslog("em84xx: grabbing image coords are incorrect (%d-%d to %d-%d)",wStartX,wStartY,wStopX,wStopY);
		return false;
	}*/

	for (int row=0; row < mCurrentHeight /*_EM84OSD_MAXHEIGHT*/; row++)
	{
		for (int  col=0; col < mCurrentWidth; col++)
		{
			oImageBuffer[(((row+mOffsetY)*_EM84OSD_MAXWIDTH)+(col+mOffsetX))*3] = cOsdEm84xx::mPaletteEM84[mOsdBuffer[_EM84OSD_HEADERSIZE+(row*mCurrentWidth+col)]].r;
			oImageBuffer[((((row+mOffsetY)*_EM84OSD_MAXWIDTH)+(col+mOffsetX))*3)+1] = cOsdEm84xx::mPaletteEM84[mOsdBuffer[_EM84OSD_HEADERSIZE+(row*mCurrentWidth+col)]].g;
			oImageBuffer[((((row+mOffsetY)*_EM84OSD_MAXWIDTH)+(col+mOffsetX))*3)+2] = cOsdEm84xx::mPaletteEM84[mOsdBuffer[_EM84OSD_HEADERSIZE+(row*mCurrentWidth+col)]].b;
		}
	}

	return true;
}

void cOsdEm84xx::rgbtoyuv(double R,double G,double B,double *y,double *u,double *v)
{
	*y=(0.257*R + 0.504*G + 0.098*B) + 16.0;
	*u=(-0.148*R - 0.291*G + 0.439*B) + 128.0;
	*v=(0.439*R - 0.368*G - 0.071*B) + 128.0;
}

void cOsdEm84xx::fillOsdHeader(unsigned char* iOsdBuffer, unsigned short iOsdWidth, unsigned short iOsdHeight, unsigned char iBpp, bool iRle, bool iHilite, unsigned int iBufSize)
{
	unsigned char wClut = 7;
	unsigned char wBpp  = 3;
	unsigned short wClutSize = 1024;
	unsigned int wTotalSize;

	if (iBpp == 2)
	{
		wClut = 1;
		wBpp  = 0;
		wClutSize = 16;
	}
	else if (iBpp == 4)
	{
		wClut = 3;
		wBpp  = 1;
		wClutSize = 64;
	}
	else if (iBpp == 7)
	{
		wClut = 6;
		wBpp  = 2;
		wClutSize = 512;
	}

	if ((wBpp != 3) && (iHilite))
	{
		wClut++;
		wClutSize *= 2;
	}

	wTotalSize = ((8 + wClutSize + iBufSize) & 0x00FFFFFF);

	iOsdBuffer[0] = (wBpp << 1) | (wClut << 3);
	if ((iRle) && (wBpp != 3))
		iOsdBuffer[0] |= 0x01;
	iOsdBuffer[1] = wTotalSize >> 16;
	iOsdBuffer[2] = (wTotalSize >> 8) & 0xFF;
	iOsdBuffer[3] = wTotalSize & 0xFF;
	iOsdBuffer[4] = iOsdWidth >> 8;
	iOsdBuffer[5] = iOsdWidth & 0xFF;
	iOsdBuffer[6] = iOsdHeight >> 8;
	iOsdBuffer[7] = iOsdHeight & 0xFF;
}

void cOsdEm84xx::setOSDPaletteEntry(int iPaletteIndex, unsigned char* iOsdBuffer, unsigned char iRed, unsigned char iGreen, unsigned char iBlue, unsigned char iAlpha)
{
	unsigned char* ptr = &iOsdBuffer[8+(iPaletteIndex*4)];
	unsigned char temp[3];
	double R,G,B,y,u,v;
		
	R = iRed;
	G = iGreen;
	B = iBlue;
	rgbtoyuv(R,G,B,&y,&u,&v);
	temp[0] = (unsigned char) y;
	temp[1] = (unsigned char) u;
	temp[2] = (unsigned char) v;

	*ptr++ = iAlpha;
	*ptr++ = temp[0];
	*ptr++ = temp[1];
	*ptr++ = temp[2];
}

int cOsdEm84xx::suiteColorToPalette(unsigned int vdrcolor)
{
	int difr, difg, difb;
	int alldif;
	int i;
	int found = -1;

	for (i=0 ; i < mUsedColors; i++)
	{
		if 	(
			(mPaletteEM84[i].a == ((vdrcolor & 0xFF000000) >> 24))
			&&
			(mPaletteEM84[i].b == (vdrcolor & 0x000000FF))
			&&
			(mPaletteEM84[i].g == ((vdrcolor & 0x00FF00) >> 8))
			&&
			(mPaletteEM84[i].r == ((vdrcolor & 0x00FF0000) >> 16))
			)
		{
			return i;
		}
	}

	if (mUsedColors < mMaxColors)
	{
		mPaletteEM84[mUsedColors].a = ((vdrcolor & 0xFF000000) >> 24);
		mPaletteEM84[mUsedColors].r = ((vdrcolor & 0x00FF0000) >> 16);
		mPaletteEM84[mUsedColors].g = ((vdrcolor & 0x00FF00) >> 8);
		mPaletteEM84[mUsedColors].b = (vdrcolor & 0x000000FF);
		mUsedColors++;

		return (mUsedColors-1);
	}

	// choose best one! ;)
	found = -1;
	alldif = 3*256;

	for (i=0; i < 256; i++)
	{
		difr = mPaletteEM84[i].r - ((vdrcolor & 0x00FF0000) >> 16);
		difg = mPaletteEM84[i].g - ((vdrcolor & 0x00FF00) >> 8);
		difb = mPaletteEM84[i].b - (vdrcolor & 0x000000FF);
		if (difr < 0)
			difr = -1*difr;
		if (difg < 0)
			difg = -1*difg;
		if (difb < 0)
			difb = -1*difb;		

		if ((difr + difg + difb) < alldif)
		{
			alldif = (difr + difg + difb);
			found = i;
		}
	}

	return found;
}

void cOsdEm84xx::commitPaletteToOsd()
{
	int i;
	for (i=0; i < _EM84OSD_PALETTESIZE; i++)
	{
		setOSDPaletteEntry(i, mOsdBuffer, mPaletteEM84[i].r,mPaletteEM84[i].g,mPaletteEM84[i].b,mPaletteEM84[i].a);
	}
}

void cOsdEm84xx::resetPalette()
{
	for (int i=0; i < _EM84OSD_PALETTESIZE; i++)
	{
		mPaletteEM84[i].a = 0x00;
		mPaletteEM84[i].r = 0x00;
		mPaletteEM84[i].g = 0x00;
		mPaletteEM84[i].b = 0x00;
	}

	mUsedColors = 0;
}

void cOsdEm84xx::resetOSD()
{
	memset(mOsdBuffer,0x00,_EM84OSD_OSDBUFFERSIZE);
}

void cOsdEm84xx::setOSDPixel(int x, int y, unsigned char color)
{
	if (x >= mCurrentWidth)
		return;
	if (y >= mCurrentHeight)
		return;

	mOsdBuffer[_EM84OSD_HEADERSIZE+(y*mCurrentWidth+x)] = color;
}

eOsdError cOsdEm84xx::CanHandleAreas(const tArea *Areas, int NumAreas)
{
   int maxBpp = 0;
   int totSize = 0;
   int maxX = 0, maxY = 0;

   eOsdError Result = cOsd::CanHandleAreas(Areas, NumAreas);

   if(Result == oeOk)
   {
      for(int i = 0; i < NumAreas; i++)
      {
         if( Areas[i].bpp > maxBpp)
            maxBpp = Areas[i].bpp;

         if(Areas[i].bpp > 8)
            return oeBppNotSupported;
         if(Areas[i].Width() < 1 || Areas[i].Height() < 1 || Areas[i].x2 > _EM84OSD_MAXWIDTH || Areas[i].y2 > _EM84OSD_MAXHEIGHT)
            return oeOutOfMemory;

         totSize += Areas[i].Width() * Areas[i].Height();

         if((Areas[i].x1 + Areas[i].Width()) > maxX)
            maxX = Areas[i].x1+Areas[i].Width();
         if((Areas[i].y1 + Areas[i].Height()) > maxY)
            maxY = Areas[i].y1 + Areas[i].Height();
      }

      mCurrentWidth  = maxX;
      mCurrentHeight = maxY;

      resetOSD();
      resetPalette();
      fillOsdHeader(mOsdBuffer, mCurrentWidth, mCurrentHeight, 8, false, false, (mCurrentWidth*mCurrentHeight));

      // Check for reserving blank color
      if( totSize < (maxX * maxY) )
	   suiteColorToPalette(0x00000000);
   }

   return Result;
}

void cOsdEm84xx::Flush(void)
{	
	bool needsOsdUpdate = false;
	cBitmap *Bitmap;

	if (!mOsd)
		return;

	// first build a common palette (don't know if this will work !?!?
	for (int i = 0; (Bitmap = GetBitmap(i)) != NULL; i++)
	{
		int x1 = 0, y1 = 0, x2 = 0, y2 = 0;
		if (Bitmap->Dirty(x1, y1, x2, y2))
		{
			needsOsdUpdate = true;

			// commit colors:
	       	int NumColors;
		       const tColor *Colors = Bitmap->Colors(NumColors);
       		if (Colors)
			{
				int* newcolors = (int*)malloc(NumColors*sizeof(int));
				for (int j = 0; j < NumColors; j++)
				{
					newcolors[j] = suiteColorToPalette(Colors[j]);
				}
			
				// draw window to osd!
				int x,y;
				for (y = y1; y <= y2; y++)
				{
					for (x = x1; x <= x2; x++)
					{
						setOSDPixel(Bitmap->X0()+x, Bitmap->Y0()+y, newcolors[*((unsigned char*)(Bitmap->Data(x,y)))]);
					}
				}
			}

			Bitmap->Clean();
		}
	}
	
	if (needsOsdUpdate)
	{
		// display osd
		commitPaletteToOsd();
		displayOSD(Left(), Top());
		usleep(50000);
	}
}








int cOsdEm84xx2mb::mLastOsdSize = 0;
unsigned char cOsdEm84xx2mb::mCompressedOsdBuffer[_EM84OSD_2MB_SIZE];

#if APIVERSNUM < 10509
cOsdEm84xx2mb::cOsdEm84xx2mb(int Left, int Top):
		cOsdEm84xx(Left, Top)
#else
cOsdEm84xx2mb::cOsdEm84xx2mb(int Left, int Top, uint Level):
		cOsdEm84xx(Left, Top, Level)
#endif		
{
	mLastOsdSize = 0;
}

cOsdEm84xx2mb::~cOsdEm84xx2mb()
{
}

eOsdError cOsdEm84xx2mb::CanHandleAreas(const tArea *Areas, int NumAreas)
{
   eOsdError Result = cOsdEm84xx::CanHandleAreas(Areas, NumAreas);

   if(Result == oeOk)
   {
      // Check if we have to compress and reduce maxColors if necessary
      if((mCurrentWidth * mCurrentHeight + _EM84OSD_HEADERSIZE) > _EM84OSD_2MB_SIZE)
         mMaxColors = 128;
      else
         mMaxColors = 256;

   }

   return Result;
}

void cOsdEm84xx2mb::displayOSD(int x, int y)
{
	bool wCompressOsd = false;
	int wAlignedSize = mCurrentWidth;
	int wClutSize     = 512;
	unsigned char wBpp = 7;

	if (!mOsd)
		return;

	if (mUsedColors <= 4)
	{
		wAlignedSize= mCurrentWidth / 4;
		if ((mCurrentWidth % 4) > 0)
			wAlignedSize++;
		wClutSize = 16;
		wBpp = 2;
	}
	else if (mUsedColors <= 16)
	{
		wAlignedSize= mCurrentWidth / 2;
		if ((mCurrentWidth % 2) > 0)
			wAlignedSize++;
		wClutSize = 64;
		wBpp = 4;
	}
	wAlignedSize *= mCurrentHeight;

	// right now we always compress until someone complaints about to much cpu-usage :)
	//if (wAlignedSize + 8 + wClutSize > _EM84OSD_2MB_SIZE)
		wCompressOsd = true;

	if (!wCompressOsd)
	{
		// not implemented yet - need to restructure code
	}
	else
	{
		unsigned short wResultHeight = 0;
		int wCompressedLines = 0;
		int wCompressedBufferSize = 0;
		
		if (mUsedColors <= 4)
		{

			wCompressedBufferSize = Compress2(
						mCurrentWidth,
						&mOsdBuffer[_EM84OSD_HEADERSIZE],
						(mCurrentWidth*mCurrentHeight),
						&mCompressedOsdBuffer[8+wClutSize],
						(_EM84OSD_2MB_SIZE-8-wClutSize),
						&wCompressedLines);
		}
		else if (mUsedColors <= 16)
		{
			wCompressedBufferSize = Compress4(
						mCurrentWidth,
						&mOsdBuffer[_EM84OSD_HEADERSIZE],
						(mCurrentWidth*mCurrentHeight),
						&mCompressedOsdBuffer[8+wClutSize],
						(_EM84OSD_2MB_SIZE-8-wClutSize),
						&wCompressedLines);

		}
		else
		{
			wCompressedBufferSize = Compress7(
						mCurrentWidth,
						&mOsdBuffer[_EM84OSD_HEADERSIZE],
						(mCurrentWidth*mCurrentHeight),
						&mCompressedOsdBuffer[8+wClutSize],
						(_EM84OSD_2MB_SIZE-8-wClutSize),
						&wCompressedLines);
		}

		wResultHeight = mCurrentHeight;
		if( wCompressedLines > 0 && wCompressedLines < mCurrentHeight)
			wResultHeight = wCompressedLines-1;

		// fill osd header
		fillOsdHeader(mCompressedOsdBuffer, mCurrentWidth, wResultHeight, wBpp, true, false, wCompressedBufferSize);

		// copy clut
		memcpy(&mCompressedOsdBuffer[8],&mOsdBuffer[8],wClutSize);

		// display
		int size = 8+wClutSize+wCompressedBufferSize;

		if ((mLastOsdSize + size) > _EM84OSD_2MB_SIZE)
			mOsd->lpVtbl->Flush(mOsd);

       	OSD_WND Wnd;
		Wnd.x = x;
		Wnd.y = y;
		Wnd.w = mCurrentWidth;
		Wnd.h = wResultHeight;

		mOsd->lpVtbl->Write(mOsd , mCompressedOsdBuffer, size);
		mOsd->lpVtbl->SetDest(mOsd , &Wnd);

		mOsd->lpVtbl->On(mOsd );

		mLastOsdSize = size;
		mOffsetX = x;
		mOffsetY = y;
	}
}


/*----- NEW -----------------------*/
int cOsdEm84xx2mb::Compress2(int iBitmapWidth, unsigned char* iBuffer, int iBufferSize, unsigned char* oBuffer, int oBufferSize, int* oCompressedLines)
{
   unsigned char b,b1,b2, oldb, newb, incomplete, temp;
   int iIdx, oIdx, count, newline, size;

   oIdx = 0;
   *oCompressedLines = 0;
   iIdx = 0;
   size = 0;
   newline = 0;
   incomplete = 0;
   b = iBuffer[0] & 0x03;

   while(iIdx < iBufferSize && oIdx < oBufferSize) {
      oldb = b;
      count = 0;
      while((iIdx < iBufferSize) && (count < 60) && (b == oldb) && (size < iBitmapWidth)) {
         count++;
         oldb = b;
         b = iBuffer[iIdx] & 0x03;

         iIdx++;

         if(newline) {
            oldb = b;
            newline = 0;
         }

         size++;
      }

      if(size == iBitmapWidth) {
         b1 = oldb & 0x03;
         newb = 0;
         newb = newb | b1;
         size = 0;
         if(incomplete == 1) {
            temp = (newb >> 4) & 0x0F;
            oBuffer[oIdx] = oBuffer[oIdx] | temp;
            oIdx++;
            temp = newb & 0x0F;
            oBuffer[oIdx] = 0xF0 & (temp << 4);
            oIdx++;
            incomplete = 0;
         }
         else {
            oBuffer[oIdx] = newb;
            oIdx++;
         }

         newline = 1;
         (*oCompressedLines)++;
      }
      else if(count < 4) {
         b1 = (oldb & 0x03);
         b2 = (count & 0x03);
         newb = (b2 << 2) | (b1);
         newb = (newb << 4) & 0xF0;
         if(incomplete == 1) {
            temp = (newb >> 4) & 0x0F;
            oBuffer[oIdx] = oBuffer[oIdx] | temp;
            oIdx++;
            incomplete = 0;
         }
         else {
            oBuffer[oIdx] = newb;
            incomplete = 1;
         }
      }
      else if(count >= 4) {
         if(count % 4 != 0) {
            b1 = (oldb & 0x03);
            newb = 0;
            newb = ((count / 4) << 2) | b1;
            if(incomplete == 1) {
               temp = (newb >> 4) & 0x0F;
               oBuffer[oIdx] = oBuffer[oIdx] | temp;
               oIdx++;
               temp = newb & 0x0F;
               oBuffer[oIdx] = temp << 4;
               incomplete = 1;
            }
            else {
               oBuffer[oIdx] = newb;
               oIdx++;
            }

            newb = 0;
            b2 = count % 4;
            newb = (b2 << 2) | b1;
            if(incomplete == 1) {
               temp = (newb) & 0x0F;
               oBuffer[oIdx] = oBuffer[oIdx] | temp;
               oIdx++;
               incomplete = 0;
            }
            else {
               oBuffer[oIdx] = (newb << 4) & 0xF0;
               incomplete = 1;
            }
         }
         else {
            b1 = (oldb & 0x03);
            newb = 0;
            newb = ((count / 4) << 2) | b1;
            if(incomplete == 1) {
               temp = (newb >> 4) & 0x0F;
               oBuffer[oIdx] = oBuffer[oIdx] | temp;
               oIdx++;
               temp = newb & 0x0F;
               oBuffer[oIdx] = temp << 4;
               incomplete = 1;
            }
            else {
               oBuffer[oIdx] = newb;
               oIdx++;
            }
         }
      }
      else {
         Dprintf("Error count");
      }
   }

   return oIdx;
}


int cOsdEm84xx2mb::Compress4(int iBitmapWidth, unsigned char* iBuffer, int iBufferSize, unsigned char* oBuffer, int oBufferSize, int* oCompressedLines)
{
   unsigned char b = 0, oldb;
   int iIdx, oIdx, oldoidx, count, newcount, size;

   oIdx = 0;
   oldoidx = 0;
   iIdx = 0;
   size = iBitmapWidth; // Little trick to initiate newline variables

   // RR, neu
   *oCompressedLines = 0;

   while(iIdx < iBufferSize && oIdx < oBufferSize) {
      if(size >= iBitmapWidth) {
         (*oCompressedLines)++;
         size = 1;
         b = iBuffer[iIdx] & 0x0F;
         iIdx++;
//          Dprintf("\nCompressed:\n");
//          while( oldoidx < oIdx ) {
//             Dprintf("%02x ", oBuffer[oldoidx]);
//             oldoidx++;
//          }
//          Dprintf("\n");
      }
      count = 0;
      oldb = b;
      while((iIdx < iBufferSize) && (b == oldb) && (size < (int) iBitmapWidth)) {
         b = iBuffer[iIdx] & 0x0f;
         iIdx++;
//          if(size < 40) {
//             Dprintf("%02x ", b);
//          }
         count++;
         size++;
      }
      if(size == (int) iBitmapWidth && oldb == b) {
         oBuffer[oIdx] = oldb & 0x0F;
         oIdx++;
         count = 0;
      }

      while( count >= 8) {
         if(count > 64)
            newcount = 64/8;
         else
            newcount = count/8;

         oBuffer[oIdx] = (((newcount-1) << 4)|0x80) | oldb;
         oIdx++;
         count -= newcount * 8;
      }
      if(count > 0) {
         oBuffer[oIdx] = (count << 4) | oldb;
         oIdx++;
      }
      if(size == iBitmapWidth && oldb != b) {
         oBuffer[oIdx] = (0x01 << 4) | oldb;
         oIdx++;
      }
   }

   return oIdx;
}

int cOsdEm84xx2mb::Compress7(int iBitmapWidth, unsigned char* iBuffer, int iBufferSize, unsigned char* oBuffer, int oBufferSize, int* oCompressedLines)
{
   unsigned char b,b1, oldb, temp, incomplete = 0;
   int iIdx, oIdx, count, size, half, newcount, oldoidx;

   oIdx = 0;
   oldoidx = 0;
   *oCompressedLines = 0;
   iIdx = 0;
   half = 0;
   b = iBuffer[0] & 0x7f;
   size = iBitmapWidth; // Little trick to initiate newline variables

   while(iIdx < iBufferSize && oIdx < oBufferSize) {
      if(size >= iBitmapWidth) {
         (*oCompressedLines)++;
         incomplete = 0;
         size = 1;
         b = iBuffer[iIdx] & 0x0F;
         iIdx++;
//          Dprintf("\nCompressed:\n");
//          while( oldoidx < oIdx ) {
//             Dprintf("%02x ", oBuffer[oldoidx]);
//             oldoidx++;
//          }
//          Dprintf("\n");
      }
      count = 0;
      oldb = b;

      while((iIdx < iBufferSize) && (b == oldb) && (size < (int) iBitmapWidth)) {
         oldb = b;
         b = iBuffer[iIdx] & 0x7f;
         iIdx++;
//          if(size < 40) {
//             Dprintf("%02x ", b);
//          }
         count++;
         size++;
      }

      if(size == iBitmapWidth && oldb == b) {
         // Do not matter about last pixel if line has changed !!!
         if(incomplete == 1) {
            oBuffer[oIdx] |= 0x08;
            oIdx++;
            oBuffer[oIdx] = b;
            oIdx++;
         }
         else {
            temp = (b >> 4) & 0x0F;
            oBuffer[oIdx] = 0x80 | temp;
            oIdx++;
            oBuffer[oIdx] = (b & 0x0F) << 4;
            oIdx++;
         }
         count = 0;
      }
      while( count >= 16 ) {
         if(count > 72)
            newcount = 72/8;
         else
            newcount = count/8;

         b1 = ((newcount-2) << 3) | 0xC0;
         if(incomplete) {
            oBuffer[oIdx] |= ((b1 & 0xF0) >> 4);
            oIdx++;
            oBuffer[oIdx] = ((b1<<4)& 0xF0) | oldb;
            oIdx++;
            incomplete = 0;
         }
         else {
            oBuffer[oIdx] = b1 | ((oldb & 0xF0) >> 4 );
            oIdx++;
            oBuffer[oIdx] = (oldb & 0x0F) << 4;
            incomplete = 1;
         }
         count -= newcount * 8;
      }
      while( count >= 2 ) {
         if(count > 7)
            newcount = 7;
         else
            newcount = count;

         b1 = ((newcount-1) << 3) | 0x80;
         if(incomplete) {
            oBuffer[oIdx] |= (b1 & 0xF0) >> 4;
            oIdx++;
            oBuffer[oIdx] = ((b1<<4)& 0xF0) | oldb;
            oIdx++;
            incomplete = 0;
         }
         else {
            oBuffer[oIdx] = b1 | ((oldb & 0xF0) >> 4 );
            oIdx++;
            oBuffer[oIdx] = (oldb & 0x0F) << 4;
            incomplete = 1;
         }
         count -= newcount;
      }
      if( count == 1 ) {
         if(incomplete) {
            oBuffer[oIdx] |= (oldb & 0xF0) >> 4;
            oIdx++;
            oBuffer[oIdx] = (oldb << 4) & 0xF0;
         }
         else {
            oBuffer[oIdx] = oldb & 0x7F;
            oIdx++;
         }
         count = 0;
      }
      if(size == iBitmapWidth && oldb != b) {
         if(incomplete) {
            oBuffer[oIdx] |= (b & 0xF0) >> 4;
            oIdx++;
            oBuffer[oIdx] = (b << 4) & 0xF0;
            oIdx++;
         }
         else {
            oBuffer[oIdx] = b & 0x7F;
            oIdx++;
         }
      }
   }

   return oIdx;
}


#if APIVERSNUM < 10509
cOsdEm84xx4mb::cOsdEm84xx4mb(int Left, int Top):
		cOsdEm84xx(Left, Top)
#else
cOsdEm84xx4mb::cOsdEm84xx4mb(int Left, int Top, uint Level):
		cOsdEm84xx(Left, Top, Level)
#endif		
{
}

cOsdEm84xx4mb::~cOsdEm84xx4mb()
{
}

void cOsdEm84xx4mb::displayOSD(int x, int y)
{
	if (mOsd )
	{
		int size = mCurrentWidth*mCurrentHeight+_EM84OSD_HEADERSIZE;
       
       	OSD_WND Wnd;
		Wnd.x = x;
		Wnd.y = y;
		Wnd.w = mCurrentWidth;
		Wnd.h = mCurrentHeight;

		mOsd->lpVtbl->Write(mOsd , mOsdBuffer, size);
		mOsd->lpVtbl->SetDest(mOsd , &Wnd);

		mOsd->lpVtbl->On(mOsd );
	}  
}
