#include <windows.h>
#include <stdio.h>
#include "kbvsti_module.h"
#include "kbvsti_decoder.h"
#include "kbvsti_config.h"
////////////////////////////////////////////////////////
#ifdef _DEBUG
#define LEAK_CHECK
static const DWORD kbvsti_Version = 0x7FFFFFFF;
#define KBVSTI_VERSION_STR L"0x7FFFFFFF(Debug)"
#else
static const DWORD kbvsti_Version = 12;
#define KBVSTI_VERSION_STR L"0.12"
#endif

static const wchar_t kbvsti_Description[] = L"VSTi MIDI Decoder v" KBVSTI_VERSION_STR " based on kpi_vsti.kpi v1.01";
static const wchar_t kbvsti_Copyright[] =   L"kbvsti.kpi Copyright (C) 2017-2022 Kobarin\n"
                                            L"kpi_vsti.kpi Copyright (C) 2016 Yoshi";
// {93A7BF43-6C0A-4BD3-AB10-A101AD7D7829}
static const GUID kbvsti_GUID = 
{ 0x93a7bf43, 0x6c0a, 0x4bd3, { 0xab, 0x10, 0xa1, 0x1, 0xad, 0x7d, 0x78, 0x29 } };
static const DWORD kbvsti_MultipleInstance = KPI_MULTINST_INFINITE;

static const wchar_t kbvsti_SupportExts[] = L".mid";
static const wchar_t kbvsti_MultiSongExts[] = L"";
static const DWORD kbvsti_SupportTagInfo = 0;//KPI_DECODER_MODULEINFO::TAG_TITLE;
static const DWORD kbvsti_SupportConfig = 1;
static void* kbvsti_Reserved1 = NULL;
static void* kbvsti_Reserved2 = NULL;

HINSTANCE g_hKpi;
//////////////////////////////////////////////////////////////////////////////
KbVstiDecoderModule::KbVstiDecoderModule(IKpiConfig *pConfig)
    :m_ModuleInfo{
        sizeof(KPI_DECODER_MODULEINFO), //cb(=sizeof(KPI_DECODER_MODULEINFO))
        KPI_DECODER_MODULE_VERSION,     //dwModuleVersion(=KPI_DECODER_MODULE_VERSION)
        kbvsti_Version,
        kbvsti_MultipleInstance,
        kbvsti_GUID,
        kbvsti_Description,
        kbvsti_Copyright,
        kbvsti_SupportExts,
        kbvsti_MultiSongExts,
        kbvsti_Reserved1,
        kbvsti_Reserved2,
        kbvsti_SupportTagInfo,
        kbvsti_SupportConfig,
        0, 0, 0, 0                   //reserved
     }
{
    KbVstiDecoder::Initialize();
    m_pConfig = pConfig;
    pConfig->AddRef();
}
//////////////////////////////////////////////////////////////////////////////
KbVstiDecoderModule::~KbVstiDecoderModule(void)
{
    KbVstiDecoder::Uninitialize();
    m_pConfig->Release();
}
//////////////////////////////////////////////////////////////////////////////
void  WINAPI KbVstiDecoderModule::GetModuleInfo(const KPI_DECODER_MODULEINFO **ppInfo)
{
    *ppInfo = &m_ModuleInfo;
}
//////////////////////////////////////////////////////////////////////////////
DWORD WINAPI KbVstiDecoderModule::Open(const KPI_MEDIAINFO *cpRequest,
                                      IKpiFile     *pFile,   //音楽データ
                                      IKpiFolder   *pFolder, //音楽データがあるフォルダ
                                      IKpiDecoder **ppDecoder)
{
    KbVstiDecoder *pDecoder = new KbVstiDecoder(m_pConfig);
    DWORD dwCount = pDecoder->Open(cpRequest, pFile, pFolder);
    if(dwCount == 0){
        *ppDecoder = NULL;
        delete pDecoder;
        return 0;
    }
    *ppDecoder = pDecoder;
    return dwCount;
}
//////////////////////////////////////////////////////////////////////////////
BOOL  WINAPI KbVstiDecoderModule::EnumConfig(IKpiConfigEnumerator *pEnumerator)
{
    return kbvsti_EnumConfig(m_pConfig, pEnumerator);

}
//////////////////////////////////////////////////////////////////////////////
DWORD WINAPI KbVstiDecoderModule::ApplyConfig(const wchar_t *cszSection, //セクション名
                              const wchar_t *cszKey, //キー名
                              INT64  nValue, //変更後の値(BOOL/INT の場合)
                              double dValue, //変更後の値(FLOAT の場合)
                              const wchar_t *cszValue)//変更後の値(文字列)
{
    return kbvsti_ApplyConfig(m_pConfig, cszSection, cszKey, nValue, dValue, cszValue);
}
/////////////////////////////////////////////////////////////////////////////
HRESULT WINAPI kpi_CreateInstance(REFIID riid, void **ppvObject, IKpiUnknown *pUnknown)
{
    *ppvObject = NULL;
    if(!IsEqualIID(riid, IID_IKpiDecoderModule)){
        return E_NOINTERFACE;
    }
    IKpiConfig *pConfig = NULL;
    kpi_CreateConfig(pUnknown, &kbvsti_GUID, NULL, &pConfig);
    IKpiDecoderModule *pDecoderModule = new KbVstiDecoderModule(pConfig);
    *ppvObject = pDecoderModule;
    pConfig->Release();
    return S_OK;
}
/////////////////////////////////////////////////////////////////////////////
BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
					 )
{
	switch (ul_reason_for_call)
	{
	case DLL_PROCESS_ATTACH:{
#ifdef LEAK_CHECK
        //メモリリーク検出
        int tmpDbgFlag = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG);
        //tmpDbgFlag |= _CRTDBG_DELAY_FREE_MEM_DF;
        tmpDbgFlag |= _CRTDBG_LEAK_CHECK_DF;
        //tmpDbgFlag |= _CRTDBG_CHECK_ALWAYS_DF;
        _CrtSetDbgFlag(tmpDbgFlag);
#endif
        g_hKpi = (HINSTANCE)hModule;
        DisableThreadLibraryCalls((HMODULE)hModule);
        break;
    }
	case DLL_PROCESS_DETACH:
		break;
	}
	return TRUE;
}
