#include <windows.h>
#include <wchar.h>
#include "kbfmmidi_module.h"
#include "kbfmmidi_decoder.h"

#ifdef _DEBUG
#define LEAK_CHECK //メモリリーク検出（しない場合はコメントアウト）
#endif
#ifdef LEAK_CHECK
#include <crtdbg.h>
#endif

#ifdef _DEBUG
static const DWORD kbfmmidi_Version = 0x7FFFFFFF; //デバッグ時は優先度最大
#define KBFMMIDI_VERSION_STR L"0x7FFFFFFF(Debug)"
#else
static const DWORD kbfmmidi_Version = 13; //プラグインのバージョン
#define KBFMMIDI_VERSION_STR L"0.13"
#endif

static const wchar_t kbfmmidi_Description[] = L"fmmidi MIDI Decoder v" KBFMMIDI_VERSION_STR " based on fmmidi v1.8";
static const wchar_t kbfmmidi_Copyright[] = L"kbfmmidi.kpi Copyright (C) 2005-2019 Kobarin\n"
                                            L"fmmidi Copyright (C) 2003-2004 yuno";

// {9ECC972E-114D-4CAF-A88C-6435B431B336}
static const GUID kbfmmidi_GUID = 
{ 0x9ecc972e, 0x114d, 0x4caf, { 0xa8, 0x8c, 0x64, 0x35, 0xb4, 0x31, 0xb3, 0x36 } };

static const DWORD kbfmmidi_MultipleInstance = KPI_MULTINST_INFINITE;//同時に何個でも作成可能
                                           //KPI_MULTINST_ZERO;  //常に別プロセス起動
                                           //KPI_MULTINST_ONE;   //2個目以降は別プロセス起動
                                           //KPI_MULTINST_UNIQUE;//プロセスをまたいでも１つまで
                                           //KPI_MULTINST_ZERO + N;//(N+1)個目以降は別プロセス起動
                                                //↑どれか１つを選択
static const wchar_t kbfmmidi_SupportExts[] = L".mid";
static const wchar_t kbfmmidi_MultiSongExts[] = L"";
static const DWORD kbfmmidi_SupportTagInfo = //KPI_DECODER_MODULEINFO::TAG_EXTRA | 
                                             //   KPI_DECODER_MODULEINFO::TAG_TITLE;
                                             0;
static const DWORD kbfmmidi_SupportConfig = 0;
static void* kbfmmidi_Reserved1 = NULL;
static void* kbfmmidi_Reserved2 = NULL;

HINSTANCE g_hKpi = NULL;
//////////////////////////////////////////////////////////////////////////////
KbFmMidiDecoderModule::KbFmMidiDecoderModule(void)
    :m_ModuleInfo{
        sizeof(KPI_DECODER_MODULEINFO), //cb(=sizeof(KPI_DECODER_MODULEINFO))
        KPI_DECODER_MODULE_VERSION,     //dwModuleVersion(=KPI_DECODER_MODULE_VERSION)
        kbfmmidi_Version,
        kbfmmidi_MultipleInstance,
        kbfmmidi_GUID,
        kbfmmidi_Description,
        kbfmmidi_Copyright,
        kbfmmidi_SupportExts,
        kbfmmidi_MultiSongExts,
        kbfmmidi_Reserved1,
        kbfmmidi_Reserved2,
        kbfmmidi_SupportTagInfo,
        kbfmmidi_SupportConfig,
        0, 0, 0, 0                      //reserved
     }
{
}
//////////////////////////////////////////////////////////////////////////////
KbFmMidiDecoderModule::~KbFmMidiDecoderModule(void)
{
}
//////////////////////////////////////////////////////////////////////////////
void  WINAPI KbFmMidiDecoderModule::GetModuleInfo(const KPI_DECODER_MODULEINFO **ppInfo)
{
    *ppInfo = &m_ModuleInfo;
}
//////////////////////////////////////////////////////////////////////////////
DWORD WINAPI KbFmMidiDecoderModule::Open(const KPI_MEDIAINFO *cpRequest,
                                          IKpiFile     *pFile,   //音楽データ
                                          IKpiFolder   *pFolder, //音楽データがあるフォルダ
                                          IKpiDecoder **ppDecoder)
{
    KbFmMidiDecoder *pDecoder = new KbFmMidiDecoder;
    DWORD dwCount = pDecoder->Open(cpRequest, pFile, pFolder);
    if(dwCount == 0){
        *ppDecoder = NULL;
        delete pDecoder;
        return 0;
    }
    *ppDecoder = pDecoder;
    return dwCount;
}
//////////////////////////////////////////////////////////////////////////////
BOOL  WINAPI KbFmMidiDecoderModule::EnumConfig(IKpiConfigEnumerator *pEnumerator)
{
    return TRUE;
}
//////////////////////////////////////////////////////////////////////////////
DWORD WINAPI KbFmMidiDecoderModule::ApplyConfig(const wchar_t *cszSection,
                                                 const wchar_t *cszKey,
                                                 INT64 nValue,
                                                 double dValue,
                                                 const wchar_t *cszValue)
{
    return KPI_CFGRET_OK;
}
/////////////////////////////////////////////////////////////////////////////
HRESULT WINAPI kpi_CreateInstance(REFIID riid, void **ppvObject, IKpiUnknown *pUnknown)
{
    *ppvObject = NULL;
    if(!IsEqualIID(riid, IID_IKpiDecoderModule)){
        return E_NOINTERFACE;
    }
    IKpiDecoderModule *pDecoderModule = new KbFmMidiDecoderModule();
    *ppvObject = pDecoderModule;
    return S_OK;
}
/////////////////////////////////////////////////////////////////////////////
//DllMain
/////////////////////////////////////////////////////////////////////////////
BOOL APIENTRY DllMain(HINSTANCE 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 = hModule;
        DisableThreadLibraryCalls(hModule);
        break;
    }
    case DLL_PROCESS_DETACH:
        break;
    }
    return TRUE;
}
/////////////////////////////////////////////////////////////////////////////
