#include <windows.h>
#include <stdio.h>
#include "kbmdx_module.h"
#include "kbmdx_decoder.h"
#include "kbmdx_config.h"

#ifdef _DEBUG
#define LEAK_CHECK //メモリリーク検出（しない場合はコメントアウト）
#endif
#ifdef LEAK_CHECK
#include <crtdbg.h>
#endif
//////////////////////////////////////////////////////////////////////////////
#ifdef _DEBUG
static const DWORD kbmdx_Version = 0x7FFFFFFF;//デバッグ時は優先度最大
#define KBMDX_VERSION_STR L"0x7FFFFFFF(Debug)"
#else
static const DWORD kbmdx_Version = 6;
#define KBMDX_VERSION_STR L"0.06"
#endif

static const wchar_t kbmdx_Description[] = L"MDX Decoder v" KBMDX_VERSION_STR " based on Portable mdx decoder(2023/12/26)";
static const wchar_t kbmdx_Copyright[] =   L"kbmdx.kpi Copyright (C) 2016-2024 Kobarin\n"
                                           L"Portable mdx decoder Copyright (C) 2018-2023 Yosshin\n"
                                           L"mdxdvg.kpi Copyright (C) 2009 Mamiya\n"
                                           L"X68k MXDRV music driver version 2.06+17 Rel.X5-S Copyright(C) 1988-1992 milk.,K.MAEKAWA, Missy.M, Yatsube\n"
                                           L"MXDRVg V2.00b Copyright(C) 2000-2002 GORRY\n"
                                           L"X68Sound.dll 20020615 by m_puusan";

// {F8F88C4F-65B2-47CC-9669-287379846CA5}
static const GUID kbmdx_GUID = 
{ 0xf8f88c4f, 0x65b2, 0x47cc, { 0x96, 0x69, 0x28, 0x73, 0x79, 0x84, 0x6c, 0xa5 } };

static const DWORD kbmdx_MultipleInstance = KPI_MULTINST_INFINITE;
static const wchar_t kbmdx_SupportExts[] = L".mdx/.mdc";
static const wchar_t kbmdx_MultiSongExts[] = L"";
static const DWORD kbmdx_SupportTagInfo = KPI_DECODER_MODULEINFO::TAG_EXTRA;
static const DWORD kbmdx_SupportConfig = 1;
static void* kbmdx_Reserved1 = NULL;
static void* kbmdx_Reserved2 = NULL;

//////////////////////////////////////////////////////////////////////////////
KbMdxDecoderModule::KbMdxDecoderModule(IKpiConfig *pConfig)
    :m_ModuleInfo{
        sizeof(KPI_DECODER_MODULEINFO), //cb(=sizeof(KPI_DECODER_MODULEINFO))
        KPI_DECODER_MODULE_VERSION,     //dwModuleVersion(=KPI_DECODER_MODULE_VERSION)
        kbmdx_Version,
        kbmdx_MultipleInstance,
        kbmdx_GUID,
        kbmdx_Description,
        kbmdx_Copyright,
        kbmdx_SupportExts,
        kbmdx_MultiSongExts,
        kbmdx_Reserved1,
        kbmdx_Reserved2,
        kbmdx_SupportTagInfo,
        kbmdx_SupportConfig,
        0, 0, 0, 0                   //reserved
     }
{
    pConfig->AddRef();
    m_pConfig = pConfig;
}
//////////////////////////////////////////////////////////////////////////////
KbMdxDecoderModule::~KbMdxDecoderModule(void)
{
    m_pConfig->Release();
}
//////////////////////////////////////////////////////////////////////////////
void  WINAPI KbMdxDecoderModule::GetModuleInfo(const KPI_DECODER_MODULEINFO **ppInfo)
{
    *ppInfo = &m_ModuleInfo;
}
//////////////////////////////////////////////////////////////////////////////
DWORD WINAPI KbMdxDecoderModule::Open(const KPI_MEDIAINFO *cpRequest,
                                      IKpiFile     *pFile,   //音楽データ
                                      IKpiFolder   *pFolder, //音楽データがあるフォルダ
                                      IKpiDecoder **ppDecoder)
{
    KbMdxDecoder *pDecoder = new KbMdxDecoder(m_pConfig);
    DWORD dwCount = pDecoder->Open(cpRequest, pFile, pFolder, m_pConfig);
    if(dwCount == 0){
        *ppDecoder = NULL;
        delete pDecoder;
        return 0;
    }
    *ppDecoder = pDecoder;
    return dwCount;
}
/////////////////////////////////////////////////////////////////////////////
BOOL  WINAPI KbMdxDecoderModule::EnumConfig(IKpiConfigEnumerator *pEnumerator)
{
    return kbmdx_EnumConfig(pEnumerator);
}
/////////////////////////////////////////////////////////////////////////////
DWORD WINAPI KbMdxDecoderModule::ApplyConfig(const wchar_t *cszSection,//セクション名
                             const wchar_t *cszKey,    //キー名
                             INT64  nValue, //変更後の値(BOOL/INT の場合)
                             double dValue, //変更後の値(FLOAT の場合)
                             const wchar_t *cszValue)////変更後の値(文字列)
{
    return kbmdx_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;
    kpi_CreateConfig(pUnknown, &kbmdx_GUID, NULL, &pConfig);
    IKpiDecoderModule *pDecoderModule = new KbMdxDecoderModule(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
        DisableThreadLibraryCalls(hModule);
        break;
    }
	case DLL_THREAD_ATTACH:
	case DLL_THREAD_DETACH:
	case DLL_PROCESS_DETACH:
		break;
	}
	return TRUE;
}
