// DM2DescriptCtx.cpp: CDM2DescriptCtx クラスのインプリメンテーション
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "dm2gded.h"
#include "DM2DescriptCtx.h"
#include "CSVrw.h"
#include "GDEdCtx.h"
#include "WVCT.h"
#include "SplitStr.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

namespace
{

static BYTE g_bL2RTbl[8] = {1, 2, 4, 8, 16, 32, 64, 128};

};

//////////////////////////////////////////////////////////////////////
// CDM2DescItem

CDM2DescItem::CDM2DescItem()
{
	ZeroMemory(c1m, sizeof(c1m));
	ZeroMemory(c2m, sizeof(c2m));
	ZeroMemory(c3, sizeof(c3));
	ZeroMemory(f3, sizeof(f3));
}

bool CDM2DescItem::Parse(LPCSTR psz1, LPCSTR psz2, LPCSTR psz3, LPCSTR psz4, LPCSTR psz5, LPCSTR psz6, LPCSTR psz7)
{
	LPCSTR pszPos, pszEnd;

	// 1
	pszEnd = strchr(pszPos = psz1, 0);
	while (pszPos[0] == '$' && pszPos + 3 <= pszEnd) {
		if (!isxdigit(pszPos[1]) || !isxdigit(pszPos[2]))
			break;
		int x = Hex2Val(pszPos[1]) * 16 + Hex2Val(pszPos[2]);
		c1m[x / 8] |= g_bL2RTbl[x % 8];
		if (pszPos[3] == ';') {
			pszPos += 4;
		} else {
			pszPos += 3;
			break;
		}
	}

	// 2
	pszEnd = strchr(pszPos = psz2, 0);
	if (pszPos == pszEnd) {
		memset(c2m, -1, sizeof(c2m));
	} else {
		while (pszPos[0] == '$' && pszPos + 3 <= pszEnd) {
			if (!isxdigit(pszPos[1]) || !isxdigit(pszPos[2]))
				break;
			int x = Hex2Val(pszPos[1]) * 16 + Hex2Val(pszPos[2]);
			c2m[x / 8] |= g_bL2RTbl[x % 8];
			if (pszPos[3] == ';') {
				pszPos += 4;
			} else {
				pszPos += 3;
				break;
			}
		}
	}

	// 3
	pszPos = psz3;
	if (pszPos[0] != '$' || !isxdigit(pszPos[1]) || !isxdigit(pszPos[2]))
		return false;
	c3[0] = Hex2Val(pszPos[1]) * 16 + Hex2Val(pszPos[2]);
	f3[0] = true;

	// 4
	pszPos = psz4;
	if (pszPos[0] != '$')
		return false;
	pszPos++;
	if (false
		|| !ParseHex2OrXX(pszPos, c3[1], f3[1])
		|| !ParseHex2OrXX(pszPos, c3[2], f3[2])
		|| !ParseHex2OrXX(pszPos, c3[3], f3[3])
	) {
		return false;
	}

	// 5
	strText = psz5;

	// 6
	CString strType = psz6;
	if (strType.CompareNoCase("signed") == 0) wvct = wvctSigned;
	else if (strType.CompareNoCase("unsigned") == 0 || strType.IsEmpty()) wvct = wvctUnsigned;
	else if (strType.CompareNoCase("hex") == 0) wvct = wvctHex;
	else if (strType.CompareNoCase("flags") == 0) wvct = wvctFlags;
	else if (strType.CompareNoCase("keyitem") == 0) wvct = wvctKeyItem;
	else if (strType.CompareNoCase("prizeitem") == 0) wvct = wvctPrizeItem;
	else if (strType.CompareNoCase("items") == 0) wvct = wvctMSItemsA;
	else if (strType.CompareNoCase("creatures") == 0) wvct = wvctMSItemsC;
	else if (strType.CompareNoCase("b5353") == 0) wvct = wvctB5353;
	else if (strType.CompareNoCase("command") == 0) wvct = wvctSKText;
	else return false;

	// 7
	strFlags = psz7;

	if (wvct == wvctFlags && !strFlags.IsEmpty()) {
		wvct = wvctHintFlags;
		wvcf.SetHintText(strFlags);
	}
	if (wvct == wvctB5353) {
		if (strFlags.IsEmpty())
				wvct = wvctUnsigned;
		else	wvcfB5353.SetHintText(strFlags);
	}

	return true;
}

bool CDM2DescItem::Match(CGDEntry pos) const
{
	BYTE c1 = pos.c1();
	if (!(c1m[c1 / 8] & g_bL2RTbl[c1 % 8]))
		return false;

	BYTE c2 = pos.c2();
	if (!(c2m[c2 / 8] & g_bL2RTbl[c2 % 8]))
		return false;

	for (int i = 0; i < 4; i++) {
		if (f3[i] && pos.c[2 + i] != c3[i])
			return false;
	}

	return true;
}

//////////////////////////////////////////////////////////////////////
// CDM2DescriptCtx

void CDM2DescriptCtx::RemoveAll()
{
	listRule.clear();
}

bool CDM2DescriptCtx::LoadFrom(LPCTSTR pszFileIn)
{
	while (true) {
		CSVR_t csvr;
		if (!csvr.Open(pszFileIn))
			break;
		while (csvr.ReadNextLine()) {
			CString str[7];
			int iColumn = 0;
			for (; iColumn < 7 && csvr.ReadNextToken(str[iColumn]); iColumn++);
			if (iColumn >= 5) {
				listRule.push_back(CDM2DescItem());
				if (listRule.back().Parse(str[0], str[1], str[2], str[3], str[4], str[5], str[6])) {

				} else {
					listRule.pop_back();
				}
			}
		}
		csvr.Close();
		return true;
	};
	return false;
}

const CDM2DescItem *CDM2DescriptCtx::FindItem(const CGDEntry &pos)
{
	RuleList::iterator
		iterPos = listRule.begin(),
		iterEnd = listRule.end();
	for (; iterPos != iterEnd; iterPos++) {
		if (iterPos->Match(pos))
			return &*iterPos;
	}
	return NULL;
}
