
//#include "stdafx.h"
#include <wchar.h>
#include "GuruGuruSMF4_Cpp.h"


namespace GuruGuruSmf {
	
	// 関数ポインタの型定義
	typedef GGSERROR (WINAPI *FunctionOpenDevice)(int deviceId, HWND handle);
	typedef void (WINAPI *FunctionCloseDevice)();
	typedef GGSERROR (WINAPI *FunctionAddDlsW)(LPCWSTR fileName);
	typedef GGSERROR (WINAPI *FunctionAddDlsA)(LPCSTR fileName);
	typedef GGSERROR (WINAPI *FunctionPlay)(int option, int musicId, int seek, int fadeInTime, int keyShift);
	typedef void (WINAPI *FunctionStop)(int fadeOutTime);
	typedef void (WINAPI *FunctionPause)();
	typedef void (WINAPI *FunctionRestart)();
	typedef void (WINAPI *FunctionSetMasterTempo)(float tempo);
	typedef void (WINAPI *FunctionSetMasterVolume)(int volume);
	typedef void (WINAPI *FunctionSetMasterPitch)(int pitch);
	typedef void (WINAPI *FunctionGetPlayerStatus)(PlayerStatus* status, int size);
	typedef GGSERROR (WINAPI *FunctionAddListFromFileW)(LPCWSTR fileName, int option, int musicId);
	typedef GGSERROR (WINAPI *FunctionAddListFromFileA)(LPCSTR fileName, int option, int musicId);
	typedef GGSERROR (WINAPI *FunctionAddListFromMemory)(LPCBYTE smfBinary, int length, int option, int musicId);
	typedef void (WINAPI *FunctionDeleteListItem)(int musicId);
	typedef void (WINAPI *FunctionClearList)();
	typedef const SmfListKeys* (WINAPI *FunctionEnumList)();
	typedef GGSERROR (WINAPI *FunctionGetSmfInformation)(SmfInformation* info, int size, int musicId);
	typedef void (WINAPI* FunctionUninitialize)();//by Kobarin

	// 関数ポインタ置き場
	static FunctionOpenDevice DllOpenDevice = 0;
	static FunctionCloseDevice DllCloseDevice = 0;
	static FunctionAddDlsW DllAddDlsW = 0;
	static FunctionAddDlsA DllAddDlsA = 0;
	static FunctionPlay DllPlay = 0;
	static FunctionStop DllStop = 0;
	static FunctionPause DllPause = 0;
	static FunctionRestart DllRestart = 0;
	static FunctionSetMasterTempo DllSetMasterTempo = 0;
	static FunctionSetMasterVolume DllSetMasterVolume = 0;
	static FunctionSetMasterPitch DllSetMasterPitch = 0;
	static FunctionGetPlayerStatus DllGetPlayerStatus = 0;
	static FunctionAddListFromFileW DllAddListFromFileW = 0;
	static FunctionAddListFromFileA DllAddListFromFileA = 0;
	static FunctionAddListFromMemory DllAddListFromMemory = 0;
	static FunctionDeleteListItem DllDeleteListItem = 0;
	static FunctionClearList DllClearList = 0;
	static FunctionEnumList DllEnumList = 0;
	static FunctionGetSmfInformation DllGetSmfInformation = 0;
	static FunctionUninitialize DllUninitialize = 0;//by Kobarin

	// マルチプルインスタンス用
	// 関数ポインタの型定義
	typedef void* (WINAPI* FunctionCreateInstance_k)();//by Kobarin
	typedef void (WINAPI* FunctionFreeInstance_k)(void* p);//by Kobarin
	typedef GGSERROR(WINAPI* FunctionOpenDevice_k)(void* p, int deviceId, HWND handle);
	typedef void (WINAPI* FunctionCloseDevice_k)(void* p);
	typedef GGSERROR(WINAPI* FunctionAddDlsW_k)(void* p, LPCWSTR fileName);
	typedef GGSERROR(WINAPI* FunctionAddDlsA_k)(void* p, LPCSTR fileName);
	typedef GGSERROR(WINAPI* FunctionPlay_k)(void* p, int option, int musicId, int seek, int fadeInTime, int keyShift);
	typedef void (WINAPI* FunctionStop_k)(void* p, int fadeOutTime);
	typedef void (WINAPI* FunctionPause_k)(void* p);
	typedef void (WINAPI* FunctionRestart_k)(void* p);
	typedef void (WINAPI* FunctionSetMasterTempo_k)(void* p, float tempo);
	typedef void (WINAPI* FunctionSetMasterVolume_k)(void* p, int volume);
	typedef void (WINAPI* FunctionSetMasterPitch_k)(void* p, int pitch);
	typedef void (WINAPI* FunctionGetPlayerStatus_k)(void* p, PlayerStatus* status, int size);
	typedef GGSERROR(WINAPI* FunctionAddListFromFileW_k)(void* p, LPCWSTR fileName, int option, int musicId);
	typedef GGSERROR(WINAPI* FunctionAddListFromFileA_k)(void* p, LPCSTR fileName, int option, int musicId);
	typedef GGSERROR(WINAPI* FunctionAddListFromMemory_k)(void* p, LPCBYTE smfBinary, int length, int option, int musicId);
	typedef void (WINAPI* FunctionDeleteListItem_k)(void* p, int musicId);
	typedef void (WINAPI* FunctionClearList_k)(void* p);
	typedef const SmfListKeys* (WINAPI* FunctionEnumList_k)(void* p);
	typedef GGSERROR(WINAPI* FunctionGetSmfInformation_k)(void* p, SmfInformation* info, int size, int musicId);

	// 関数ポインタ置き場
	static FunctionCreateInstance_k DllCreateInstance_k = 0;
	static FunctionFreeInstance_k DllFreeInstance_k = 0;
	static FunctionOpenDevice_k DllOpenDevice_k = 0;
	static FunctionCloseDevice_k DllCloseDevice_k = 0;
	static FunctionAddDlsW_k DllAddDlsW_k = 0;
	static FunctionAddDlsA_k DllAddDlsA_k = 0;
	static FunctionPlay_k DllPlay_k = 0;
	static FunctionStop_k DllStop_k = 0;
	static FunctionPause_k DllPause_k = 0;
	static FunctionRestart_k DllRestart_k = 0;
	static FunctionSetMasterTempo_k DllSetMasterTempo_k = 0;
	static FunctionSetMasterVolume_k DllSetMasterVolume_k = 0;
	static FunctionSetMasterPitch_k DllSetMasterPitch_k = 0;
	static FunctionGetPlayerStatus_k DllGetPlayerStatus_k = 0;
	static FunctionAddListFromFileW_k DllAddListFromFileW_k = 0;
	static FunctionAddListFromFileA_k DllAddListFromFileA_k = 0;
	static FunctionAddListFromMemory_k DllAddListFromMemory_k = 0;
	static FunctionDeleteListItem_k DllDeleteListItem_k = 0;
	static FunctionClearList_k DllClearList_k = 0;
	static FunctionEnumList_k DllEnumList_k = 0;
	static FunctionGetSmfInformation_k DllGetSmfInformation_k = 0;


	Ggs4* Ggs4::instance = 0;	// インスタンス置き場
	int Ggs4::instance_count = 0;
	static HMODULE DllHandle = 0;	// DLLハンドル置き場
	
	// インスタンス作成
	Ggs4* Ggs4::CreateInstance(void)
	{
		if (instance) {
			Ggs4* ret = instance;//使い回す
			instance = NULL;
			return ret;
		}
		if (DllCreateInstance_k) {//マルチプルインスタンス対応
			void* ggs = DllCreateInstance_k();
			return new Ggs4(ggs);
		}
		if (instance_count > 0)return NULL;//2個以上は作成不可
		return new Ggs4;
	}
	// インスタンス破棄
	void Ggs4::FreeInstance()
	{
		if(instance == NULL){
		//使い回す為削除しないで残しておく
			ClearList();
			CloseDevice();
			instance = this;
			return;
		}
		delete this;
	}
	bool Ggs4::IsMultipleInstance()
	{
		return DllCreateInstance_k != NULL;
	}

	// GuruGuruSMF4.dll をアンロード
	void Ggs4::UnloadDll()
	{
		if (DllHandle) {
			delete instance;instance = NULL;
			if(DllUninitialize){
				DllUninitialize();
			}
			FreeLibrary(DllHandle);
			DllHandle = 0;
			
			DllOpenDevice = 0;
			DllCloseDevice = 0;
			DllAddDlsW = 0;
			DllAddDlsA = 0;
			DllPlay = 0;
			DllStop = 0;
			DllPause = 0;
			DllRestart = 0;
			DllSetMasterTempo = 0;
			DllSetMasterVolume = 0;
			DllSetMasterPitch = 0;
			DllGetPlayerStatus = 0;
			DllAddListFromFileW = 0;
			DllAddListFromFileA = 0;
			DllAddListFromMemory = 0;
			DllDeleteListItem = 0;
			DllClearList = 0;
			DllEnumList = 0;
			DllGetSmfInformation = 0;
			DllUninitialize = 0;
			//マルチプルインスタンス用
			DllCreateInstance_k = NULL;
			DllFreeInstance_k = NULL;
			DllOpenDevice_k = NULL;
			DllCloseDevice_k = NULL;
			DllAddDlsW_k = NULL;
			DllAddDlsA_k = NULL;
			DllPlay_k = NULL;
			DllStop_k = NULL;
			DllPause_k = NULL;
			DllRestart_k = NULL;
			DllSetMasterTempo_k = NULL;
			DllSetMasterVolume_k = NULL;
			DllSetMasterPitch_k = NULL;
			DllGetPlayerStatus_k = NULL;
			DllAddListFromFileW_k = NULL;
			DllAddListFromFileA_k = NULL;
			DllAddListFromMemory_k = NULL;
			DllDeleteListItem_k = NULL;
			DllClearList_k = NULL;
			DllEnumList_k = NULL;
			DllGetSmfInformation_k = NULL;
		}
	}
	// 初期化
	GGSERROR Ggs4::Initialize(const wchar_t * dllpath)
	{
		if(DllHandle) return GgsError::NoError;
		DllHandle = LoadLibraryW(dllpath);
		if(DllHandle == 0) return GgsError::Failed;
		//公式版DLL用
		DllOpenDevice = (FunctionOpenDevice)GetProcAddress(DllHandle, "GGS4OpenDevice");
		DllCloseDevice = (FunctionCloseDevice)GetProcAddress(DllHandle, "GGS4CloseDevice");
		DllAddDlsW = (FunctionAddDlsW)GetProcAddress(DllHandle, "GGS4AddDlsW");
		DllAddDlsA = (FunctionAddDlsA)GetProcAddress(DllHandle, "GGS4AddDlsA");
		DllPlay = (FunctionPlay)GetProcAddress(DllHandle, "GGS4Play");
		DllStop = (FunctionStop)GetProcAddress(DllHandle, "GGS4Stop");
		DllPause = (FunctionPause)GetProcAddress(DllHandle, "GGS4Pause");
		DllRestart = (FunctionRestart)GetProcAddress(DllHandle, "GGS4Restart");
		DllSetMasterTempo = (FunctionSetMasterTempo)GetProcAddress(DllHandle, "GGS4SetMasterTempo");
		DllSetMasterVolume = (FunctionSetMasterVolume)GetProcAddress(DllHandle, "GGS4SetMasterVolume");
		DllSetMasterPitch = (FunctionSetMasterPitch)GetProcAddress(DllHandle, "GGS4SetMasterPitch");
		DllGetPlayerStatus = (FunctionGetPlayerStatus)GetProcAddress(DllHandle, "GGS4GetPlayerStatus");
		DllAddListFromFileW = (FunctionAddListFromFileW)GetProcAddress(DllHandle, "GGS4AddListFromFileW");
		DllAddListFromFileA = (FunctionAddListFromFileA)GetProcAddress(DllHandle, "GGS4AddListFromFileA");
		DllAddListFromMemory = (FunctionAddListFromMemory)GetProcAddress(DllHandle, "GGS4AddListFromMemory");
		DllDeleteListItem = (FunctionDeleteListItem)GetProcAddress(DllHandle, "GGS4DeleteListItem");
		DllClearList = (FunctionClearList)GetProcAddress(DllHandle, "GGS4ClearList");
		DllEnumList = (FunctionEnumList)GetProcAddress(DllHandle, "GGS4EnumList");
		DllGetSmfInformation = (FunctionGetSmfInformation)GetProcAddress(DllHandle, "GGS4GetSmfInformation");
		//後始末用(マルチプルインスタンス用APIだけを使用する分には必要ない)
		DllUninitialize = (FunctionUninitialize)GetProcAddress(DllHandle, "GGS4Uninitialize_k");
		//マルチプルインスタンス用
		DllCreateInstance_k = (FunctionCreateInstance_k)GetProcAddress(DllHandle, "GGS4CreateInstance_k");
		DllFreeInstance_k = (FunctionFreeInstance_k)GetProcAddress(DllHandle, "GGS4FreeInstance_k");
		DllOpenDevice_k = (FunctionOpenDevice_k)GetProcAddress(DllHandle, "GGS4OpenDevice_k");
		DllCloseDevice_k = (FunctionCloseDevice_k)GetProcAddress(DllHandle, "GGS4CloseDevice_k");
		DllAddDlsW_k = (FunctionAddDlsW_k)GetProcAddress(DllHandle, "GGS4AddDlsW_k");
		DllAddDlsA_k = (FunctionAddDlsA_k)GetProcAddress(DllHandle, "GGS4AddDlsA_k");
		DllPlay_k = (FunctionPlay_k)GetProcAddress(DllHandle, "GGS4Play_k");
		DllStop_k = (FunctionStop_k)GetProcAddress(DllHandle, "GGS4Stop_k");
		DllPause_k = (FunctionPause_k)GetProcAddress(DllHandle, "GGS4Pause_k");
		DllRestart_k = (FunctionRestart_k)GetProcAddress(DllHandle, "GGS4Restart_k");
		DllSetMasterTempo_k = (FunctionSetMasterTempo_k)GetProcAddress(DllHandle, "GGS4SetMasterTempo_k");
		DllSetMasterVolume_k = (FunctionSetMasterVolume_k)GetProcAddress(DllHandle, "GGS4SetMasterVolume_k");
		DllSetMasterPitch_k = (FunctionSetMasterPitch_k)GetProcAddress(DllHandle, "GGS4SetMasterPitch_k");
		DllGetPlayerStatus_k = (FunctionGetPlayerStatus_k)GetProcAddress(DllHandle, "GGS4GetPlayerStatus_k");
		DllAddListFromFileW_k = (FunctionAddListFromFileW_k)GetProcAddress(DllHandle, "GGS4AddListFromFileW_k");
		DllAddListFromFileA_k = (FunctionAddListFromFileA_k)GetProcAddress(DllHandle, "GGS4AddListFromFileA_k");
		DllAddListFromMemory_k = (FunctionAddListFromMemory_k)GetProcAddress(DllHandle, "GGS4AddListFromMemory_k");
		DllDeleteListItem_k = (FunctionDeleteListItem_k)GetProcAddress(DllHandle, "GGS4DeleteListItem_k");
		DllClearList_k = (FunctionClearList_k)GetProcAddress(DllHandle, "GGS4ClearList_k");
		DllEnumList_k = (FunctionEnumList_k)GetProcAddress(DllHandle, "GGS4EnumList_k");
		DllGetSmfInformation_k = (FunctionGetSmfInformation_k)GetProcAddress(DllHandle, "GGS4GetSmfInformation_k");
		if( !DllCreateInstance_k || 
		    !DllFreeInstance_k ||
			!DllOpenDevice_k ||
			!DllCloseDevice_k ||
			!DllAddDlsW_k ||
			!DllPlay_k ||
			!DllStop_k ||
			!DllPause_k ||
			!DllRestart_k ||
			!DllSetMasterTempo_k ||
			!DllSetMasterVolume_k ||
			!DllSetMasterPitch_k ||
			!DllGetPlayerStatus_k ||
			!DllAddListFromFileW_k ||
			!DllAddListFromFileA_k ||
			!DllAddListFromMemory_k ||
			!DllDeleteListItem_k ||
			!DllClearList_k ||
			!DllEnumList_k ||
			!DllGetSmfInformation_k){

			DllCreateInstance_k = NULL;
			DllFreeInstance_k = NULL;
			DllOpenDevice_k = NULL;
			DllCloseDevice_k = NULL;
			DllAddDlsW_k = NULL;
			DllAddDlsA_k = NULL;
			DllPlay_k = NULL;
			DllStop_k = NULL;
			DllPause_k = NULL;
			DllRestart_k = NULL;
			DllSetMasterTempo_k = NULL;
			DllSetMasterVolume_k = NULL;
			DllSetMasterPitch_k = NULL;
			DllGetPlayerStatus_k = NULL;
			DllAddListFromFileW_k = NULL;
			DllAddListFromFileA_k = NULL;
			DllAddListFromMemory_k = NULL;
			DllDeleteListItem_k = NULL;
			DllClearList_k = NULL;
			DllEnumList_k = NULL;
			DllGetSmfInformation_k = NULL;
		}
			
		return GgsError::NoError;
	}
	// デストラクタ
	Ggs4::~Ggs4()
	{
		CloseDevice();
		if(ggs){
			DllFreeInstance_k(ggs);
		}
		instance_count--;
	}
	// デバイスを開く
	GGSERROR Ggs4::OpenDevice(int deviceId, HWND handle)
	{
		if(ggs){return DllOpenDevice_k(ggs, deviceId, handle);}
		if(!DllOpenDevice) return GgsError::ApiNull;
		return DllOpenDevice(deviceId, handle);
	}
	
	// デバイスを閉じる
	void Ggs4::CloseDevice()
	{
		if (ggs){DllCloseDevice_k(ggs);return;}
		if(!DllCloseDevice) return;
		DllCloseDevice();
	}
	
	// DLSを追加(UNICODE)
	GGSERROR Ggs4::AddDlsW(LPCWSTR fileName)
	{
		if (ggs) { return DllAddDlsW_k(ggs, fileName); }
		if(!DllAddDlsW) return GgsError::ApiNull;
		return DllAddDlsW(fileName);
	}
	
	// DLSを追加(Ansi)
	GGSERROR Ggs4::AddDlsA(LPCSTR fileName)
	{
		if (ggs) { return DllAddDlsA_k(ggs, fileName); }
		if(!DllAddDlsA) return GgsError::ApiNull;
		return DllAddDlsA(fileName);
	}
	
	// 演奏！
	GGSERROR Ggs4::Play(int option, int musicId, int seek, int fadeInTime, int keyShift)
	{
		if (ggs) { return DllPlay_k(ggs, option, musicId, seek, fadeInTime, keyShift); }
		if(!DllPlay) return GgsError::ApiNull;
		return DllPlay(option, musicId, seek, fadeInTime, keyShift);
	}
	
	// 停止
	void Ggs4::Stop(int fadeOutTime)
	{
		if (ggs) { DllStop_k(ggs, fadeOutTime); return;}
		if(!DllStop) return;
		DllStop(fadeOutTime);
	}
	
	// 一時停止
	void Ggs4::Pause()
	{
		if (ggs) { DllPause_k(ggs); return; }
		if(!DllPause) return;
		DllPause();
	}
	
	// 一時停止解除
	void Ggs4::Restart()
	{
		if (ggs) { DllRestart_k(ggs); return; }
		if(!DllRestart) return;
		DllRestart();
	}
	
	// マスターテンポ
	void Ggs4::SetMasterTempo(float tempo)
	{
		if (ggs) { DllSetMasterTempo_k(ggs, tempo); return; }
		if(!DllSetMasterTempo) return;
		DllSetMasterTempo(tempo);
	}
	
	// マスターボリューム
	void Ggs4::SetMasterVolume(int volume)
	{
		if (ggs) { DllSetMasterVolume_k(ggs, volume); return; }
		if(!DllSetMasterVolume) return;
		DllSetMasterVolume(volume);
	}
	
	// マスターピッチ
	void Ggs4::SetMasterPitch(int pitch)
	{
		if (ggs) { DllSetMasterPitch_k(ggs, pitch); return; }
		if(!DllSetMasterPitch) return;
		DllSetMasterPitch(pitch);
	}
	
	// 演奏情報取得
	void Ggs4::GetPlayerStatus(PlayerStatus* status)
	{
		if (ggs) { DllGetPlayerStatus_k(ggs, status, sizeof(PlayerStatus)); return; }
		if(!DllGetPlayerStatus) return;
		DllGetPlayerStatus(status, sizeof(PlayerStatus));
	}
	
	// ファイルからリストへ追加(UNICODE)
	GGSERROR Ggs4::AddListFromFileW(LPCWSTR fileName, int option, int musicId)
	{
		if (ggs) { return DllAddListFromFileW_k(ggs, fileName, option, musicId); }
		if(!DllAddListFromFileW) return GgsError::ApiNull;
		return DllAddListFromFileW(fileName, option, musicId);
	}
	
	// ファイルからリストへ追加(Ansi)
	GGSERROR Ggs4::AddListFromFileA(LPCSTR fileName, int option, int musicId)
	{
		if (ggs) { return DllAddListFromFileA_k(ggs, fileName, option, musicId); }
		if(!DllAddListFromFileA) return GgsError::ApiNull;
		return DllAddListFromFileA(fileName, option, musicId);
	}
	
	// メモリからリストへ追加
	GGSERROR Ggs4::AddListFromMemory(LPCBYTE smfBinary, int length, int option, int musicId)
	{
		if (ggs) { return DllAddListFromMemory_k(ggs, smfBinary, length, option, musicId); }
		if(!DllAddListFromMemory) return GgsError::ApiNull;
		return DllAddListFromMemory(smfBinary, length, option, musicId);
	}
	
	// リストから1つ削除
	void Ggs4::DeleteListItem(int musicId)
	{
		if (ggs) { DllDeleteListItem_k(ggs, musicId); return;}
		if(!DllDeleteListItem) return;
		DllDeleteListItem(musicId);
	}
	
	// リストをクリア
	void Ggs4::ClearList()
	{
		if (ggs) { DllClearList_k(ggs); return; }
		if(!DllClearList) return;
		DllClearList();
	}
	
	// リストを列挙
	const SmfListKeys* Ggs4::EnumList()
	{
		if (ggs) { return DllEnumList_k(ggs); }
		if(!DllEnumList) return 0;
		return DllEnumList();
	}
	
	// SMFの情報を取得
	GGSERROR Ggs4::GetSmfInformation(SmfInformation* info, int musicId)
	{
		if (ggs) { return DllGetSmfInformation_k(ggs, info, sizeof(SmfInformation), musicId); }
		if(!DllGetSmfInformation) return GgsError::ApiNull;
		return DllGetSmfInformation(info, sizeof(SmfInformation), musicId);
	}
	
}


