#include <image.h>
#include <fourcc.h>

#include <cstdio>
#include <iostream>

using namespace std;

BitmapInfo::BitmapInfo(int width, int height, int bpp)
{
    memset(this, 0, sizeof(BitmapInfo));
    biWidth = width;
    biHeight = height;
    biPlanes = 1;
    switch (bpp)
    {
    case 8:
    case 15:
    case 16:
    case 24:
    case 32:
	biSizeImage = labs(width * height) * ((bpp + 7) / 8);
	SetBits(bpp);
	break;
    default:
	SetSpace(bpp);
	break;
    }
}

BitmapInfo::BitmapInfo(const BITMAPINFOHEADER& hdr)
{
    if (hdr.biSize > int(sizeof(BITMAPINFOHEADER)))
	cout << "BitmapInfo::Unknown format (BIH) - size: " << hdr.biSize << endl;

    memcpy(this, &hdr, sizeof(BITMAPINFOHEADER));
}

BitmapInfo::BitmapInfo(const BitmapInfo& bi)
{
    if (bi.biSize > int(sizeof(BitmapInfo)))
	cout << "BitmapInfo::Unknown format (BI) - size: " << bi.biSize << endl;

    memcpy(this, &bi, sizeof(BitmapInfo));
}

BitmapInfo::BitmapInfo(const BitmapInfo* bi)
{
    if (!bi)
	cout << "BitmapInfo::Invalid argument" << endl;
    else
    {
	if (bi->biSize > int(sizeof(BitmapInfo)))
	    cout << "BitmapInfo::Unknown format (BI*) - size: " << bi->biSize << endl;
	    //          throw FATAL("Unknown format");
	memcpy(this, bi, sizeof(BitmapInfo));
    }
}

int BitmapInfo::BitCount(int csp)
{
    switch(csp)
    {
	case fccYUV:
	    return 24;
	case fccYUY2:
	case fccUYVY:
	case fccYVYU:
	    return 16;
	case fccYV12:
	case fccIYUV:
	case fccI420:
	    return 12;
    }
    return 0;
}

int BitmapInfo::Bpp() const
{
    //      if(biCompression==0)return biBitCount;
    if (biCompression != 3)
	return biBitCount;
    if (m_iColors[0] == 0x7c00)
	return 15;
    return 16;
}


void BitmapInfo::SetBitFields16()
{
    biSize = sizeof(BitmapInfo);
    biCompression = 3;	//BI_BITFIELDS
    biBitCount = 16;
    //biHeight = labs(biHeight);
    biSizeImage = labs(2 * biWidth * biHeight);
    m_iColors[0] = 0xF800;
    m_iColors[1] = 0x07E0;
    m_iColors[2] = 0x001F;
}

void BitmapInfo::SetBitFields15()
{
    biSize = sizeof(BitmapInfo);
    biCompression = 3;	//BI_BITFIELDS
    biBitCount = 16;
    //biHeight = labs(biHeight);
    biSizeImage = labs(2 * biWidth * biHeight);
    m_iColors[0] = 0x7C00;
    m_iColors[1] = 0x03E0;
    m_iColors[2] = 0x001F;
}

void BitmapInfo::SetRGB()
{
    biSize = sizeof(BITMAPINFOHEADER);
    biCompression = 0;	//BI_RGB
    //biHeight = labs(biHeight);
    biSizeImage = labs(biWidth * biHeight) * ((biBitCount + 7) / 8);
}

void BitmapInfo::SetBits(int bits)
{
    bool ok = false;
    switch (bits)
    {
    case 15:
	SetBitFields15();
	break;
    case 16:
	SetBitFields16();
	break;
    default:
	biBitCount = bits;
	SetRGB();
	break;
    }
}

void BitmapInfo::SetSpace(int csp)
{
    biSize = sizeof(BITMAPINFOHEADER);
    biCompression = csp;
    biBitCount = BitCount(csp);
    if (csp != 0 && csp != 3 && biHeight > 0)
        biHeight *= -1; // YUV formats uses should have height < 0
    biSizeImage = labs(biBitCount * biWidth * biHeight / 8);
}

void BitmapInfo::Print() const
{
    printf("BitmapInfo, format: \n");
    printf("  biSize %d\n", biSize);
    printf("  biWidth %d\n", biWidth);
    printf("  biHeight %d\n", biHeight);
    printf("  biPlanes %d\n", biPlanes);
    printf("  biBitCount %d\n", biBitCount);
    printf("  biCompression %d='%.4s'\n", biCompression, (const char *)&biCompression);
    printf("  biSizeImage %d\n", biSizeImage);
}
