#include "libthecore/stdafx.h"
#include "attribute.h"

#define SET_BIT(var,bit)                ((var) |= (bit))
#define REMOVE_BIT(var,bit)             ((var) &= ~(bit))

void CAttribute::Initialize(DWORD width, DWORD height)
{
    dataType = D_DWORD;
    defaultAttr = 0;
    this->width = width;
    this->height = height;
    data = NULL;
    bytePtr = NULL;
    wordPtr = NULL;
    dwordPtr = NULL;
}

void CAttribute::Alloc()
{
    size_t memSize;

    switch (dataType)
    {
	case D_DWORD:
	    memSize = width * height * sizeof(DWORD);
	    break;

	case D_WORD:
	    memSize = width * height * sizeof(WORD);
	    break;

	case D_BYTE:
	    memSize = width * height;
	    break;

	default:
	    assert(!"dataType error!");
	    return;
    }

    //sys_log(0, "Alloc::dataType %u width %d height %d memSize %d", dataType, width, height, memSize);
    data = malloc(memSize);

    switch (dataType)
    {
	case D_DWORD:
	    dwordPtr = new DWORD * [height];
	    dwordPtr[0] = (DWORD *) data;

	    for (DWORD y = 1; y < height; ++y)
		dwordPtr[y] = dwordPtr[y - 1] + width;

	    for (DWORD y = 0; y < height; ++y)
		for (DWORD x = 0; x < width; ++x)
		    dwordPtr[y][x] = defaultAttr;

	    break;

	case D_WORD:
	    wordPtr = new WORD * [height];
	    wordPtr[0] = (WORD *) data;

	    for (DWORD y = 1; y < height; ++y)
		wordPtr[y] = wordPtr[y - 1] + width;

	    for (DWORD y = 0; y < height; ++y)
		for (DWORD x = 0; x < width; ++x)
		    wordPtr[y][x] = defaultAttr;

	    break;

	case D_BYTE:
	    bytePtr = new BYTE * [height];
	    bytePtr[0] = (BYTE *) data;

	    for (DWORD y = 1; y < height; ++y)
		bytePtr[y] = bytePtr[y - 1] + width;

	    for (DWORD y = 0; y < height; ++y)
		for (DWORD x = 0; x < width; ++x)
		    bytePtr[y][x] = defaultAttr;

	    break;
    }
}

CAttribute::CAttribute(DWORD width, DWORD height) // dword 타잎으로 모두 0을 채운다.
{
    Initialize(width, height);
    Alloc();
}

CAttribute::CAttribute(DWORD * attr, DWORD width, DWORD height) // attr을 읽어서 smart하게 속성을 읽어온다.
{
    Initialize(width, height);

    int i;
    int size = width * height;

    for (i = 0; i < size; ++i)
	if (attr[0] != attr[i])
	    break;

    // 속성이 전부 같으면 단지 defaultAttr만 설정한다.
    if (i == size)
	defaultAttr = attr[0];
    else
    {
	int allAttr = 0;

	for (i = 0; i < size; ++i)
	    allAttr |= attr[i];

	// 하위 8비트만 사용할 경우 D_BYTE
	if (!(allAttr & 0xffffff00))
	    dataType = D_BYTE;
	// 하위 16비트만 사용할 경우 D_WORD
	else if (!(allAttr & 0xffff0000))
	    dataType = D_WORD;
	else // 그 이외에는 D_DWORD
	    dataType = D_DWORD;

	Alloc();

	if (dataType == D_DWORD) // D_DWORD일 때는 원본 속성과 같으므로 단지 복사.
	    thecore_memcpy(data, attr, sizeof(DWORD) * width * height);
	else
	{
	    // 아니면 컨버트 해야 한다.
	    DWORD * pdw = (DWORD *) attr;

	    if (dataType == D_BYTE)
	    {
		for (DWORD y = 0; y < height; ++y)
		    for (DWORD x = 0; x < width; ++x)
			bytePtr[y][x] = *(pdw++);
	    }
	    else if (dataType == D_WORD)
	    {
		for (DWORD y = 0; y < height; ++y)
		    for (DWORD x = 0; x < width; ++x)
			wordPtr[y][x] = *(pdw++);
	    }
	}
    }
}

CAttribute::~CAttribute()
{
    if (data)
	free(data);

    if (bytePtr)
	delete [] bytePtr;

    if (wordPtr)
	delete [] wordPtr;

    if (dwordPtr)
	delete [] dwordPtr;
}

int CAttribute::GetDataType()
{
    return dataType;
}

void * CAttribute::GetDataPtr()
{
    return data;
}

void CAttribute::Set(DWORD x, DWORD y, DWORD attr)
{
    if (x > width || y > height)
	return;

    if (!data)
	Alloc();

    if (bytePtr)
    {
	SET_BIT(bytePtr[y][x], attr);
	return;
    }

    if (wordPtr)
    {
	SET_BIT(wordPtr[y][x], attr);
	return;
    }

    SET_BIT(dwordPtr[y][x], attr);
}

void CAttribute::Remove(DWORD x, DWORD y, DWORD attr)
{
    if (x > width || y > height)
	return;

    if (!data) // 속성을 삭제할 때 만약 데이터가 없으면 그냥 리턴한다.
	return;

    if (bytePtr)
    {
	REMOVE_BIT(bytePtr[y][x], attr);
	return;
    }

    if (wordPtr)
    {
	REMOVE_BIT(wordPtr[y][x], attr);
	return;
    }

    REMOVE_BIT(dwordPtr[y][x], attr);
}

DWORD CAttribute::Get(DWORD x, DWORD y)
{
    if (x > width || y > height)
	return 0;

    if (!data)
	return defaultAttr;

    if (bytePtr)
	return bytePtr[y][x];

    if (wordPtr)
	return wordPtr[y][x];

    return dwordPtr[y][x];
}

void CAttribute::CopyRow(DWORD y, DWORD * row)
{
    if (!data)
    {
	for (DWORD x = 0; x < width; ++x)
	    row[x] = defaultAttr;

	return;
    }

    if (dwordPtr)
	thecore_memcpy(row, dwordPtr[y], sizeof(DWORD) * width);
    else
    {
	if (bytePtr)
	{
	    for (DWORD x = 0; x < width; ++x)
		row[x] = bytePtr[y][x];
	}
	else if (wordPtr)
	{
	    for (DWORD x = 0; x < width; ++x)
		row[x] = wordPtr[y][x];
	}
    }
}

