#include <windows.h>
#include <wchar.h>

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

#include "kbum_module.h"
#include "kbum_decoder.h"

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

static const wchar_t kbum_Description[] = L"UltraMarine Decoder v" KBUM_VERSION_STR " based on umut.dll v1.2b";
static const wchar_t kbum_Copyright[] = L"kbum.kpi Copyright (C) 2004-2019 Kobarin\n"
                                        L"umut.dll Copyright (C) 1996-1998 Club Suppoko/Miamo"; 

// {876AE38B-796D-420F-B421-7DCA3C81F286}
static const GUID kbum_GUID =
{ 0x876ae38b, 0x796d, 0x420f, { 0xb4, 0x21, 0x7d, 0xca, 0x3c, 0x81, 0xf2, 0x86 } };

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

HINSTANCE g_hKpi = NULL;
//////////////////////////////////////////////////////////////////////////////
KbUmDecoderModule::KbUmDecoderModule(IKpiConfig *pConfig)
    :m_ModuleInfo{
        sizeof(KPI_DECODER_MODULEINFO), //cb(=sizeof(KPI_DECODER_MODULEINFO))
        KPI_DECODER_MODULE_VERSION,     //dwModuleVersion(=KPI_DECODER_MODULE_VERSION)
        kbum_Version,
        kbum_MultipleInstance,
        kbum_GUID,
        kbum_Description,
        kbum_Copyright,
        kbum_SupportExts,
        kbum_MultiSongExts,
        kbum_Reserved1,
        kbum_Reserved2,
        kbum_SupportTagInfo,
        kbum_SupportConfig,
        0, 0, 0, 0                      //reserved
     }
{
    m_pConfig = pConfig;
    pConfig->AddRef();
}
//////////////////////////////////////////////////////////////////////////////
KbUmDecoderModule::~KbUmDecoderModule(void)
{
    KbUmDecoder::Uninitialize();
    m_pConfig->Release();
}
//////////////////////////////////////////////////////////////////////////////
void  WINAPI KbUmDecoderModule::GetModuleInfo(const KPI_DECODER_MODULEINFO **ppInfo)
{
    *ppInfo = &m_ModuleInfo;
}
//////////////////////////////////////////////////////////////////////////////
DWORD WINAPI KbUmDecoderModule::Open(const KPI_MEDIAINFO *cpRequest,
                                          IKpiFile     *pFile,   //音楽データ
                                          IKpiFolder   *pFolder, //音楽データがあるフォルダ
                                          IKpiDecoder **ppDecoder)
{
    KbUmDecoder *pDecoder = new KbUmDecoder(m_pConfig);
    DWORD dwCount = pDecoder->Open(cpRequest, pFile, pFolder);
    if(dwCount == 0){
        *ppDecoder = NULL;
        delete pDecoder;
        return 0;
    }
    *ppDecoder = pDecoder;
    return dwCount;
}
//////////////////////////////////////////////////////////////////////////////
BOOL  WINAPI KbUmDecoderModule::EnumConfig(IKpiConfigEnumerator *pEnumerator)
{
    static const KPI_CFG_SECTION sec[] = {
        {SEC_GENERAL, NULL, L"kbum.kpi に関する一般的な設定です。"},
        {NULL, NULL, NULL}
    };
    static const KPI_CFG_KEY key[] = {
    //   type, section, key, keydesc, default, min, max, list, listdesc, help
        {KPI_CFG_TYPE_FOLDER, SEC_GENERAL, KEY_PCMPATH, L"PCM(*.PAC)検索パス", 
            L"", NULL, NULL, //default/min/max
            NULL, //list
            NULL, //listdesc 
            L"PCM(*.PAC ファイル) の検索パスを指定します。\r\n"
            L"サブフォルダを検索しないため、指定したフォルダの直下に全ての PCM ファイルを置く必要があります。"},//help
         {0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}
    };
    for(int i = 0; sec[i].cszSection; i++){
        pEnumerator->EnumSection(&sec[i]);
    }
    for(int i = 0; key[i].cszSection; i++){
        pEnumerator->EnumKey(&key[i]);
    }
    return TRUE;
}
//////////////////////////////////////////////////////////////////////////////
DWORD WINAPI KbUmDecoderModule::ApplyConfig(const wchar_t *cszSection,
                                                 const wchar_t *cszKey,
                                                 INT64 nValue,
                                                 double dValue,
                                                 const wchar_t *cszValue)
{//
    m_pConfig->SetStr(cszSection, cszKey, cszValue);
    return KPI_CFGRET_RELOAD_DATA;
}
/////////////////////////////////////////////////////////////////////////////
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, &kbum_GUID, NULL, &pConfig);
    IKpiDecoderModule *pDecoderModule = new KbUmDecoderModule(pConfig);
    *ppvObject = pDecoderModule;
    pConfig->Release();//KbUmDecoderModule 内で AddRef しているので必ず必要
    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;
}
/////////////////////////////////////////////////////////////////////////////
