#pragma once

#include <vector>
#include <tchar.h>

#include "tstring.h"
#include "scci.h"
#include "SCCIDefines.h"
#include "udpl_dll.h"
#include <Windows.h>
#include <fstream>

#ifdef _DEBUG
	#define _CRTDBG_MAP_ALLOC
	#include <crtdbg.h>
	#define new ::new(_NORMAL_BLOCK, __FILE__, __LINE__)
#endif

#define ADPCM_SIZE	16777216	// YM2610 の PCMバッファ 16MB

const TCHAR dllName[] = _T("udpl.dll");			// udpl の dll
const TCHAR iniName[] = _T("scci2udpl.ini");	// 設定ファイル


// クラスプロトタイプ
class SoundInterfaceManager_udpl;
class SoundInterface_udpl;
class SoundChip_udpl;


class SoundInterfaceManager_udpl : public SoundInterfaceManager
{
private:
	
	typedef struct {
		std::tstring appname;
		std::tstring param;
	} PARAM_ELEM;

	typedef struct {
		std::tstring section;
		std::vector<PARAM_ELEM> paramlist;
	} INI_ELEM;

public:
	SoundInterfaceManager_udpl(HMODULE hdl, UdplManager *pUm, HMODULE sccihdl, SoundInterfaceManager *psm)
	{
		hDll = hdl;
		pudplManager = pUm;
		chip_num = 0;
		pchipInfo = nullptr;
		pscciIf = nullptr;
		memset(&ifInfo, 0, sizeof(ifInfo));

		interfaceNum = 1;
	};

	virtual ~SoundInterfaceManager_udpl() {};

	// override
	int __stdcall getInterfaceCount();
	SCCI_INTERFACE_INFO* __stdcall getInterfaceInfo(int iInterfaceNo);
	SoundInterface* __stdcall getInterface(int iInterfaceNo);
	BOOL __stdcall releaseInterface(SoundInterface* pSoundInterface);
	BOOL __stdcall releaseAllInterface();
	SoundChip* __stdcall getSoundChip(int iSoundChipType, DWORD dClock);
	BOOL __stdcall releaseSoundChip(SoundChip* pSoundChip);
	BOOL __stdcall releaseAllSoundChip();
	BOOL __stdcall setDelay(DWORD dMSec);
	DWORD __stdcall getDelay();
	BOOL __stdcall reset();
	BOOL __stdcall init();
	BOOL __stdcall initializeInstance();
	BOOL __stdcall releaseInstance();
	BOOL __stdcall config();
	DWORD __stdcall getVersion(DWORD *pMVersion = NULL);
	BOOL __stdcall isValidLevelDisp();
	BOOL __stdcall isLevelDisp();
	void __stdcall setLevelDisp(BOOL bDisp);
	void __stdcall setMode(int iMode);
	void __stdcall sendData();
	void __stdcall clearBuff();
	void __stdcall setAcquisitionMode(int iMode);
	void __stdcall setAcquisitionModeClockRenge(DWORD dClock);
	BOOL __stdcall setCommandBuffetSize(DWORD dBuffSize);
	BOOL __stdcall isBufferEmpty();

private:
	void makeAllList(const std::vector<INI_ELEM> &list);
	void delAllList(void);
	void readSetting(std::vector<INI_ELEM> &list);
	void split_null(const TCHAR *c, uint32_t size, std::vector<std::tstring> &str);
	void get_appparam(const std::vector<std::tstring> &in, std::vector<PARAM_ELEM> &out);
	void make_clocklist(const std::vector<PARAM_ELEM> &in, std::vector<uint32_t> &out);
	void get_clocks(const char *chipname, const std::vector<INI_ELEM> &list, std::vector<uint32_t> &out);

	HMODULE	hDll;					// udpl DLL ハンドル
	UdplManager *pudplManager;		// udpl のマネージャー

	uint32_t chip_num;			// チップ数
	UDPL_CHIP_INFO *pchipInfo;

	SCCI_INTERFACE_INFO ifInfo;

	std::vector<SoundChip_udpl *> scciChipList;

	SoundInterface_udpl *pscciIf;

	int interfaceNum;
};

class SoundInterface_udpl : public SoundInterface {
public:
	SoundInterface_udpl(std::vector<SoundChip_udpl *> &list)
	{
		chipList = list;
	};

	virtual ~SoundInterface_udpl() {};

	//override
	BOOL __stdcall isSupportLowLevelApi();
	BOOL __stdcall setData(BYTE *pData, DWORD dSendDataLen);
	DWORD __stdcall getData(BYTE *pData, DWORD dGetDataLen);
	BOOL __stdcall setDelay(DWORD dDelay);
	DWORD __stdcall getDelay();
	BOOL __stdcall reset();
	BOOL __stdcall init();
	DWORD	__stdcall getSoundChipCount();
	SoundChip* __stdcall getSoundChip(DWORD dNum);

private:
	std::vector<SoundChip_udpl *> chipList;

};

class SoundChip_udpl : public SoundChip {
public:
	SoundChip_udpl(UdplChip *pc, UDPL_CHIP_INFO *pi, uint32_t no);
	SoundChip_udpl(SoundChip_udpl *pc, uint32_t clock, uint32_t no);
	virtual ~SoundChip_udpl() {
	//	of.close();
	}
	// override
	SCCI_SOUND_CHIP_INFO* __stdcall getSoundChipInfo();
	int __stdcall getSoundChipType();
	virtual BOOL __stdcall setRegister(DWORD dAddr, DWORD dData);
	DWORD __stdcall getRegister(DWORD dAddr);
	BOOL __stdcall init();
	DWORD __stdcall getSoundChipClock();
	DWORD __stdcall getWrittenRegisterData(DWORD addr);
	BOOL __stdcall isBufferEmpty();

	void setSameList(const std::vector<SoundChip_udpl*> &in);
	void setUsed(bool val, bool recursive = false);
	bool getUsed(void);
	bool getVariableClock(void);

protected:
	UdplChip *pchip;
	SCCI_SOUND_CHIP_INFO info;
	std::vector<SoundChip_udpl*> samelist;
	bool isUsed;
	UDPL_CHIP_INFO *udplinfo;	// 一応持っておく
};

class SoundChip_udpl_sn76489 : public SoundChip_udpl {
public:
	SoundChip_udpl_sn76489(UdplChip *pc, UDPL_CHIP_INFO *pi, uint32_t no) : SoundChip_udpl(pc, pi, no) {};
	SoundChip_udpl_sn76489(SoundChip_udpl *pc, uint32_t clock, uint32_t no) : SoundChip_udpl(pc, clock, no) {};
	virtual ~SoundChip_udpl_sn76489() {};

	// override
	virtual BOOL __stdcall setRegister(DWORD dAddr, DWORD dData);
};

class SoundChip_udpl_ym2610_h : public SoundChip_udpl {
public:
	SoundChip_udpl_ym2610_h(UdplChip *pc, UDPL_CHIP_INFO *pi, uint32_t no) : SoundChip_udpl(pc, pi, no)
	{
		allocPcmBuf();
	};
	SoundChip_udpl_ym2610_h(SoundChip_udpl *pc, uint32_t clock, uint32_t no) : SoundChip_udpl(pc, clock, no)
	{
		allocPcmBuf();
	};
	virtual ~SoundChip_udpl_ym2610_h()
	{
		freePcmBuf();
	};

	// override
	virtual BOOL __stdcall setRegister(DWORD dAddr, DWORD dData);

private:
	void allocPcmBuf(void);
	void freePcmBuf(void);

	uint8_t *pcmbuf[2];
	uint32_t pcmbuf_len[2];
	unsigned int cur_ch;
	bool filling;
	YM2610_PCMDATA pcminfo;
	uint32_t offset;
};