#include "xentax.h"
#include "x_bmp.h"

BOOL CreateBMPHeaders(DWORD dx, DWORD dy, DWORD bpp, BITMAPFILEHEADER* fileHeader, BITMAPINFOHEADER* infoHeader)
{
 // validate
 if(!fileHeader) return FALSE;
 if(!infoHeader) return FALSE;
 if(dx == 0) return FALSE;
 if(dy == 0) return FALSE;
 if(!(bpp == 1 || bpp == 4 || bpp == 8 || bpp == 16 || bpp == 24 || bpp == 32)) return FALSE;

 // set file header
 fileHeader->bfType = 0x4D42; 
 fileHeader->bfSize = 0;
 fileHeader->bfReserved1 = 0;
 fileHeader->bfReserved2 = 0;
 fileHeader->bfOffBits = 0;

 // set info header
 infoHeader->biSize = sizeof(BITMAPINFOHEADER);
 infoHeader->biWidth = dx;
 infoHeader->biHeight = dy;
 infoHeader->biPlanes = 1;
 infoHeader->biBitCount = (WORD)bpp;
 infoHeader->biCompression = BI_RGB;
 infoHeader->biSizeImage = 0;
 infoHeader->biXPelsPerMeter = 0;
 infoHeader->biYPelsPerMeter = 0;
 infoHeader->biClrUsed = 0;
 infoHeader->biClrImportant = 0;

 return TRUE;
}

BOOL SaveYUV411ToBMP(const char* filename, DWORD dx, DWORD dy, const char* data, uint32 size)
{
 return TRUE;
}

BOOL SaveYUV420ToBMP(const char* filename, DWORD dx, DWORD dy, const char* data, uint32 size)
{
 return TRUE;
}

BOOL SaveYUV422ToBMP(const char* filename, DWORD dx, DWORD dy, const char* data, uint32 size)
{
 // validate
 if(!filename || !strlen(filename)) return FALSE;
 if(!dx) return FALSE;
 if(!dy) return FALSE;
 if(!data || !size) return FALSE;

 // TODO: validate size of data

 // create bitmap headers
 BITMAPFILEHEADER fileHeader;
 BITMAPINFOHEADER infoHeader;
 if(!CreateBMPHeaders(dx, dy, 32, &fileHeader, &infoHeader)) return FALSE;

 // create BGRA data
 uint32 n = dx*dy*4;
 boost::shared_array<uint08> ptr(new uint08[n]);

 // for every 4 bytes
 uint32 index1 = 0;
 uint32 index2 = 0;
 while(index1 < size)
      {
       // constants
       real32 y1 = (real32)data[index1++];
       real32  u = (real32)data[index1++];
       real32 y2 = (real32)data[index1++];
       real32  v = (real32)data[index1++];

       // convert pixel #1
       real32 r1 = y1 + 1.13983f*v;
       real32 g1 = y1 - 0.39465f*u - 0.58060f*v;
       real32 b1 = y1 + 2.03211f*u;
       ptr[index2++] = (uint08)clamp(b1, 0.0f, 255.0f);
       ptr[index2++] = (uint08)clamp(g1, 0.0f, 255.0f);
       ptr[index2++] = (uint08)clamp(r1, 0.0f, 255.0f);
       ptr[index2++] = (uint08)255;

       // convert pixel #2
       real32 r2 = y2 + 1.13983f*v;
       real32 g2 = y2 - 0.39465f*u - 0.58060f*v;
       real32 b2 = y2 + 2.03211f*u;
       ptr[index2++] = (uint08)clamp(b2, 0.0f, 255.0f);
       ptr[index2++] = (uint08)clamp(g2, 0.0f, 255.0f);
       ptr[index2++] = (uint08)clamp(r2, 0.0f, 255.0f);
       ptr[index2++] = (uint08)255;
      }

 // create file
 using namespace std;
 ofstream ofile(filename, ios::binary);
 if(!ofile) return FALSE;

 // save file header
 ofile.write((char*)&fileHeader, sizeof(fileHeader));
 if(ofile.fail()) return FALSE;

 // save info header
 ofile.write((char*)&infoHeader, sizeof(infoHeader));
 if(ofile.fail()) return FALSE;

 // save data
 ofile.write((char*)ptr.get(), n);
 if(ofile.fail()) return FALSE;

 // success
 return TRUE;
}

BOOL SaveYUV444ToBMP(const char* filename, DWORD dx, DWORD dy, const char* data, uint32 size)
{
 return TRUE;
}
