// ControllerRom.cpp : Implementation of CRom
#include "stdafx.h"
#include "VPinMAME.h"
#include "ControllerRom.h"
#include "ControllerOptions.h"

extern "C" {
#include "driver.h"
}

#define AUD_ROM_UNKNOWN		0x0000
#define AUD_ROM_GOOD		0x0001
#define AUD_ROM_NEED_REDUMP	0x0002
#define AUD_ROM_NOT_FOUND	0x0004
#define AUD_NOT_AVAILABLE	0x0008
#define AUD_BAD_CHECKSUM	0x0010
#define AUD_MEM_ERROR		0x0020
#define AUD_LENGTH_MISMATCH	0x0040
#define AUD_ROM_NEED_DUMP	0x0080


STDMETHODIMP CRom::InterfaceSupportsErrorInfo(REFIID riid)
{
	static const IID* arr[] = 
	{
		&IID_IRom
	};
	for (int i=0; i < sizeof(arr) / sizeof(arr[0]); i++)
	{
		if (InlineIsEqualGUID(*arr[i],riid))
			return S_OK;
	}
	return S_FALSE;
}

CRom::CRom()
{
	m_gamedrv = NULL;
	m_rom = NULL;

	m_pszName = NULL;
	m_dwState = 0;
	m_dwLength = 0;
	m_dwExpLength = 0;
	m_dwChecksum = 0;
	m_dwExpChecksum = 0;
	m_dwRegionFlags = 0;
}

CRom::~CRom()
{
}


HRESULT CRom::Init(const struct GameDriver *gamedrv, const struct RomModule *region, const struct RomModule *rom)
{
	if ( !gamedrv || !region ||!rom )
		return S_FALSE;

	m_gamedrv = gamedrv;
	m_region = region;
	m_rom = rom;

	m_pszName = ROM_GETNAME(m_rom);

	m_dwState = 0;
	m_dwLength = 0;
	m_dwExpLength = 0;

	const struct RomModule *chunk;
	for (chunk = rom_first_chunk(m_rom); chunk; chunk = rom_next_chunk(chunk))
		m_dwExpLength += ROM_GETLENGTH(chunk);

	m_dwChecksum = 0;
	m_dwExpChecksum = ROM_GETCRC(m_rom);
	m_dwRegionFlags = ROMREGION_GETFLAGS(m_region);

	return S_OK;
}

STDMETHODIMP CRom::get_Name(BSTR *pVal)
{
	if ( !m_pszName )
		return S_FALSE;

	CComBSTR Name(m_pszName);

	*pVal = Name.Detach();
	return S_OK;
}


STDMETHODIMP CRom::get_State(long *pVal)
{
	*pVal = m_dwState;

	return S_OK;
}

STDMETHODIMP CRom::get_StateDescription(BSTR *pVal)
{
	CComBSTR sStateDescription;

	switch ( m_dwState ) {
	case AUD_ROM_GOOD:
		sStateDescription = "OK";
		break;

	case AUD_ROM_NEED_REDUMP:
		sStateDescription = "Need redump";
		break;

	case AUD_ROM_NOT_FOUND:
		sStateDescription = "Not found";
		break;

	case AUD_NOT_AVAILABLE:
		sStateDescription = "Not available";
		break;

	case AUD_BAD_CHECKSUM:
		sStateDescription = "Bad checksum";
		break;

	case AUD_MEM_ERROR:
		sStateDescription = "Memory error";
		break;
	
	case AUD_LENGTH_MISMATCH:
		sStateDescription = "Length mismatch";
		break;

	case AUD_ROM_NEED_DUMP:
		sStateDescription = "Need dump";
		break;

	default:
		sStateDescription = "Unknown";
		break;
	}

	*pVal = sStateDescription.Detach();

	return S_OK;
}

STDMETHODIMP CRom::Audit(BOOL fStrict)
{
	int err;

	m_dwChecksum = fStrict?0xffffffff:ROM_GETCRC(m_rom);

	/* obtain CRC-32 and length of ROM file */
	const struct GameDriver *drv = m_gamedrv;
	do
	{
		err = osd_fchecksum (drv->name, m_pszName, (unsigned int*) &m_dwLength, (unsigned int*) &m_dwChecksum);
		drv = drv->clone_of;
	} while (err && drv);

	if (err)
	{
		if (!m_dwChecksum)
			/* not found but it's not good anyway */
			m_dwState = AUD_NOT_AVAILABLE;
		else
			/* not found */
			m_dwState = AUD_ROM_NOT_FOUND;
	}

	/* all cases below assume the ROM was at least found */
	else if (m_dwExpLength != m_dwLength)
		m_dwState = AUD_LENGTH_MISMATCH;
	else if (m_dwExpChecksum != m_dwChecksum)
	{
		if (!m_dwExpChecksum)
			m_dwState = AUD_ROM_NEED_DUMP; /* new case - found but not known to be dumped */
		else if (m_dwChecksum == BADCRC(m_dwExpChecksum))
			m_dwState = AUD_ROM_NEED_REDUMP;
		else
			m_dwState = AUD_BAD_CHECKSUM;
	}
	else
		m_dwState = AUD_ROM_GOOD;

	return S_OK;
}

STDMETHODIMP CRom::get_Length(long *pVal)
{
	*pVal = m_dwLength;

	return S_OK;
}

STDMETHODIMP CRom::get_ExpLength(long *pVal)
{
	*pVal = m_dwExpLength;

	return S_OK;
}

STDMETHODIMP CRom::get_Checksum(long *pVal)
{
	*pVal = m_dwChecksum;

	return S_OK;
}


STDMETHODIMP CRom::get_ExpChecksum(long *pVal)
{
	*pVal = m_dwExpChecksum;

	return S_OK;
}

STDMETHODIMP CRom::get_Flags(long *pVal)
{
	*pVal = m_dwRegionFlags;

	return S_OK;
}
