#include <windows.h>
#include <stdio.h>
#include "kbpxtone_module.h"
#include "kbpxtone_decoder.h"
#include "kbpxtone_config.h" //IKpiConfig 未対応ならコメントアウト

//必要に応じて kbpxtone を適切な文字列に置換

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

static const wchar_t kbpxtone_Description[] = L"Pxtone Collage Decoder v" KBPXTONE_VERSION_STR " based on pxtone-source-code 220910a";
static const wchar_t kbpxtone_Copyright[] =   L"kbpxtone.kpi Copyright(C) 2019-2022 Kobarin\n"
                                              L"Pxtone Collage Copyright(C) Studio-Pixel\n"
                                              L"libvorbis Copyright (C) 2000-2020 Monty, Xiph.Org\n"
                                              L"libogg Copyright (C) 2000-2021 Xiph.Org";

// {411A7B3B-06E9-4BAD-9EF6-324EDB03240D}
static const GUID kbpxtone_GUID =
{ 0x411a7b3b, 0x6e9, 0x4bad, { 0x9e, 0xf6, 0x32, 0x4e, 0xdb, 0x3, 0x24, 0xd } };

static const DWORD kbpxtone_MultipleInstance = KPI_MULTINST_INFINITE;   //同時に何個でも作成可能
                                            //KPI_MULTINST_ZERO;     //常に別プロセス起動
                                            //KPI_MULTINST_ONE;      //2個目以降は別プロセス起動
                                            //KPI_MULTINST_UNIQUE;   //プロセスをまたいでも１つまで
                                            //KPI_MULTINST_ZERO + N; //(N+1)個目以降は別プロセス起動
                                            //↑どれか1つを選択
static const wchar_t kbpxtone_SupportExts[] = L".pttune/.ptcop";
static const wchar_t kbpxtone_MultiSongExts[] = L"";//SupportExts に含まないものを指定しても無視される
static const DWORD kbpxtone_SupportTagInfo = KPI_DECODER_MODULEINFO::TAG_TITLE | //未対応ならコメントアウト
                                          //KPI_DECODER_MODULEINFO::TAG_EXTRA | //未対応ならコメントアウト
                                          0;
static const DWORD kbpxtone_SupportConfig = 1;
static void* kbpxtone_Reserved1 = NULL;
static void* kbpxtone_Reserved2 = NULL;

//////////////////////////////////////////////////////////////////////////////
KbPxtoneDecoderModule::KbPxtoneDecoderModule(IKpiConfig *pConfig) //IKpiConfig 未対応なら KbPxtoneDecoderModle(void)
    :m_ModuleInfo{
        sizeof(KPI_DECODER_MODULEINFO), //cb(=sizeof(KPI_DECODER_MODULEINFO))
        KPI_DECODER_MODULE_VERSION,     //dwModuleVersion(=KPI_DECODER_MODULE_VERSION)
        kbpxtone_Version,
        kbpxtone_MultipleInstance,
        kbpxtone_GUID,
        kbpxtone_Description,
        kbpxtone_Copyright,
        kbpxtone_SupportExts,
        kbpxtone_MultiSongExts,
        kbpxtone_Reserved1,
        kbpxtone_Reserved2,
        kbpxtone_SupportTagInfo,
        kbpxtone_SupportConfig,
        0, 0, 0, 0                   //reserved
     }
{
    pConfig->AddRef();  //IKpiConfig未対応なら
    m_pConfig = pConfig;//ここまでコメントアウト
}
//////////////////////////////////////////////////////////////////////////////
KbPxtoneDecoderModule::~KbPxtoneDecoderModule(void)
{
    m_pConfig->Release();
}
//////////////////////////////////////////////////////////////////////////////
void  WINAPI KbPxtoneDecoderModule::GetModuleInfo(const KPI_DECODER_MODULEINFO **ppInfo)
{
    *ppInfo = &m_ModuleInfo;
}
//////////////////////////////////////////////////////////////////////////////
DWORD WINAPI KbPxtoneDecoderModule::Open(const KPI_MEDIAINFO *cpRequest,
                                      IKpiFile     *pFile,   //音楽データ
                                      IKpiFolder   *pFolder, //音楽データがあるフォルダ
                                      IKpiDecoder **ppDecoder)
{
    KbPxtoneDecoder *pDecoder = new KbPxtoneDecoder(m_pConfig);
    DWORD dwCount = pDecoder->Open(cpRequest, pFile, pFolder);
    if(dwCount == 0){
        *ppDecoder = NULL;
        delete pDecoder;
        return 0;
    }
    *ppDecoder = pDecoder;
    return dwCount;
}
/////////////////////////////////////////////////////////////////////////////
BOOL  WINAPI KbPxtoneDecoderModule::EnumConfig(IKpiConfigEnumerator *pEnumerator)
{
    return kbpxtone_EnumConfig(pEnumerator);
}
/////////////////////////////////////////////////////////////////////////////
DWORD WINAPI KbPxtoneDecoderModule::ApplyConfig(const wchar_t *cszSection,//セクション名
                             const wchar_t *cszKey,    //キー名
                             INT64  nValue, //変更後の値(BOOL/INT の場合)
                             double dValue, //変更後の値(FLOAT の場合)
                             const wchar_t *cszValue)////変更後の値(文字列)
{
    return kbpxtone_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.cpp をプロジェクトに追加すること
    //呼び出し元が未対応でも NULL が返ることはない
    kpi_CreateConfig(pUnknown, &kbpxtone_GUID, NULL, &pConfig);
    IKpiDecoderModule *pDecoderModule = new KbPxtoneDecoderModule(pConfig);
    *ppvObject = pDecoderModule;
    pConfig->Release();//KbPxtoneDecoderModule 内部でインクリメント/デクリメントする
    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:
        break;
    case DLL_THREAD_DETACH:
        break;
    case DLL_PROCESS_DETACH:
        break;
    }
    return TRUE;
}
///////////////////////////////////////////////////////////////////////////////
