// mbc.h: interface for the CMBC class.
//
//////////////////////////////////////////////////////////////////////

#if !defined(AFX_MBC_H__570CE811_7B15_4311_B40F_571EBACBC500__INCLUDED_)
#define AFX_MBC_H__570CE811_7B15_4311_B40F_571EBACBC500__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#include "platform.h"
#include "Memory.h"

typedef enum _tagEMBCType
{
	MBC_NONE,
	MBC1,
	MBC2,
	MBC3,
	MBC4,
	MBC5,
	MBC6,
	MBC7,
	MMM01,
	MBC_RUMBLE,
	HuC1,
	HuC3,
	CAMERA,
	TAMA5
} EMBCType;

typedef enum _tagEROMMode
{
	MBC_ROM_MODE,
	MBC_RAM_MODE
} EROMMode;

class CMBC
{
public:
	CMBC(EMBCType eMBCType, CMemory* pMemory);
	virtual ~CMBC();
public:
	inline void SetMemory(CMemory* pMemory)
	{
		m_pMemory = pMemory;
	}

	inline EMBCType MBCType()
	{
		return m_enMBCType;
	}
	
	inline EROMMode MBCMode()
	{
		return m_enMBCMode;
	}

	virtual void Write(u32 addr, u32 value) = 0;
	virtual u32 Read(u32 addr) = 0;
protected:
// 	inline void MBCType(EMBCType mbc)
// 	{
// 		m_enMBCType = mbc;
// 	}
protected:
	EMBCType	m_enMBCType;
	EROMMode	m_enMBCMode;
	CMemory*	m_pMemory;
};

class CMBCNone : public CMBC
{
public:
	CMBCNone(CMemory* pMemory) : CMBC(MBC_NONE, pMemory)
	{
		m_enMBCType = MBC_NONE;
		m_pMemory = pMemory;
#if !NMGB_INTEGRATE_ROM
		FILE* fp = fopen(g_configinfo.m_sROMFile,"rb");
		if(fp)
		{
			fread(m_pMemory->m_ROM0, 16*1024/*16KB*/, 1, fp);
			NMGB_DEBUG_PRINT(NMGB_DEBUG_COLOR_GREEN,"Reading Bank 0 OK!");
			fclose(fp);
		}
		else
			;
		
		m_pMemory->m_ROM1.ReadBank(g_configinfo.m_sROMFile,1);
#else
		memcpy(m_pMemory->m_ROM0, g_configinfo.m_sROMFile,16*1024/*16KB*/);
		m_pMemory->m_ROM1.ReadBank(g_configinfo.m_sROMFile,1,32*1024/*file size*/);
#endif
	}
	
	void Write(u32 addr, u32 value)
	{
		//do nothing!
	}

	u32 Read(u32 addr)
	{

		return 0xff;
	};
};

class CMBC1 : public CMBC
{
public:
	CMBC1(CMemory* pMemory,bool bHasRAM=false,bool bHasBattery=false) : CMBC(MBC1, pMemory)
	{
		m_enMBCType = MBC1;
		m_pMemory= pMemory;

		FILE* fp = fopen(g_configinfo.m_sROMFile,"rb");
		if(fp)
		{
			fread(m_pMemory->m_ROM0, 16*1024/*16KB*/, 1, fp);
			NMGB_DEBUG_PRINT(NMGB_DEBUG_COLOR_GREEN,"Reading Bank 0 OK!");
			fclose(fp);
		}
		else
			;

		m_pMemory->m_ROM1.ReadBank(g_configinfo.m_sROMFile,1);
		m_pMemory->SelectedROMIndex(1);

// 		if(bHasRAM)
// 		{
// 			int nRAMBank = 0xA000/(8*1024);
// 			m_pMemory->m_EXRAM.ReadBank(g_configinfo.m_sROMFile,nRAMBank);
// 			m_pMemory->SelectedRAMIndex(0);
// 		}
	}

	void Write(u32 addr, u32 value);
	u32 Read(u32 addr);
};

class CMBC2 : public CMBC
{
public:
	CMBC2(CMemory* pMemory) : CMBC(MBC2, pMemory)
	{
		FILE* fp = fopen(g_configinfo.m_sROMFile,"rb");
		if(fp)
		{
			fread(m_pMemory->m_ROM0, 16*1024/*16KB*/, 1, fp);
			NMGB_DEBUG_PRINT(NMGB_DEBUG_COLOR_GREEN,"Reading Bank 0 OK!");
			fclose(fp);
		}
		else
			;

		m_pMemory->m_ROM1.ReadBank(g_configinfo.m_sROMFile,1);
		m_pMemory->SelectedROMIndex(1);
	}

	void Write(u32 addr, u32 value);
	u32 Read(u32 addr);
};

class CMBC5 : public CMBC
{
	bool m_bHasRumble;
public:
	CMBC5(CMemory* pMemory,bool bHasRumble=false, bool bHasRAM=false,bool bHasBattery=false) : CMBC(MBC1, pMemory)
	{
		m_enMBCType = MBC5;
		m_pMemory= pMemory;
		m_bHasRumble = bHasRumble;

		FILE* fp = fopen(g_configinfo.m_sROMFile,"rb");
		if(fp)
		{
			fread(m_pMemory->m_ROM0, 16*1024/*16KB*/, 1, fp);
			NMGB_DEBUG_PRINT(NMGB_DEBUG_COLOR_GREEN,"Reading Bank 0 OK!");
			fclose(fp);
		}
		else
			;

		m_pMemory->m_ROM1.ReadBank(g_configinfo.m_sROMFile,1);
		m_pMemory->SelectedROMIndex(1);

		// 		if(bHasRAM)
		// 		{
		// 			int nRAMBank = 0xA000/(8*1024);
		// 			m_pMemory->m_EXRAM.ReadBank(g_configinfo.m_sROMFile,nRAMBank);
		// 			m_pMemory->SelectedRAMIndex(0);
		// 		}
	}

	void Write(u32 addr, u32 value);
	u32 Read(u32 addr);
public:
	bool IsRumbleEnable()
	{
		return m_bHasRumble;
	}
};


#endif // !defined(AFX_MBC_H__570CE811_7B15_4311_B40F_571EBACBC500__INCLUDED_)
