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

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

#include "kbtak_module.h"
#include "kbtak_decoder.h"

#ifdef _DEBUG
static const DWORD kbtak_Version = 0x7FFFFFFF; //デバッグ時は優先度最大
#define KBTAK_VERSION_STR L"0x7FFFFFFF(Debug)" 
#else
static const DWORD kbtak_Version = 13;
#define KBTAK_VERSION_STR L"0.13"
#endif

// {DB1B5325-92BC-43E3-8E8C-1D0F6DE1AED5}
static const GUID kbtak_GUID = 
{ 0xdb1b5325, 0x92bc, 0x43e3, { 0x8e, 0x8c, 0x1d, 0xf, 0x6d, 0xe1, 0xae, 0xd5 } };

static const wchar_t kbtak_Description[] = L"TAK Decoder v" KBTAK_VERSION_STR " based on tak_deco_lib.dll %s";
static const wchar_t kbtak_Copyright[] = L"Copyright (C) 2015-2022 Kobarin\n"
                                         L"Copyright (C) 2007-2022 Thomas Becker, D-49080 Osnabrück";
//////////////////////////////////////////////////////////////////////////////
static const DWORD kbtak_MultipleInstance = KPI_MULTINST_INFINITE;
static const wchar_t kbtak_SupportExts[] = L".tak";
static const wchar_t kbtak_MultiSongExts[] = L"";
static const DWORD kbtak_SupportTagInfo = KPI_DECODER_MODULEINFO::TAG_TITLE |
                                          KPI_DECODER_MODULEINFO::TAG_EXTRA |
                                          0;
static const DWORD kbtak_SupportConfig = 0;
static void* kbtak_Reserved1 = NULL;
static void* kbtak_Reserved2 = NULL;

static HINSTANCE g_hKpi = NULL;

//////////////////////////////////////////////////////////////////////////////
KbTakDecoderModule::KbTakDecoderModule(void)
    :m_ModuleInfo{
        sizeof(KPI_DECODER_MODULEINFO), //cb(=sizeof(KPI_DECODER_MODULEINFO))
        KPI_DECODER_MODULE_VERSION,     //dwModuleVersion(=KPI_DECODER_MODULE_VERSION)
        kbtak_Version,                  //dwPluginVersion
        kbtak_MultipleInstance,
        kbtak_GUID,
        kbtak_Description,
        kbtak_Copyright,
        kbtak_SupportExts,
        kbtak_MultiSongExts,
        kbtak_Reserved1,
        kbtak_Reserved1,
        kbtak_SupportTagInfo,
        kbtak_SupportConfig,
        0, 0, 0, 0                      //reserved
     }
{
    wchar_t szVersion[32];
    wchar_t szDescription[1024];
    TtakInt32 Version, Compatibility;

    if(KbTakDecoder::Initialize(g_hKpi, &Version, &Compatibility)){
        int major = Version >> 16;
        int minor = (Version >> 8) & 0xFF;
        int build = (Version & 0xFF);
        swprintf_s(szVersion, L"v%d.%d.%d", major, minor, build);
    }
    else{
        wcsncpy_s(szVersion, L"(failed to load dll)", _TRUNCATE);
    }
    swprintf_s(szDescription, kbtak_Description, szVersion);
    m_ModuleInfo.cszDescription = _wcsdup(szDescription);
}
//////////////////////////////////////////////////////////////////////////////
KbTakDecoderModule::~KbTakDecoderModule(void)
{
    free((void*)m_ModuleInfo.cszDescription);
    KbTakDecoder::Uninitialize();
}
//////////////////////////////////////////////////////////////////////////////
void  WINAPI KbTakDecoderModule::GetModuleInfo(const KPI_DECODER_MODULEINFO **ppInfo)
{
    *ppInfo = &m_ModuleInfo;
}
//////////////////////////////////////////////////////////////////////////////
DWORD WINAPI KbTakDecoderModule::Open(const KPI_MEDIAINFO *cpRequest,
                                         IKpiFile     *pFile,   //音楽データ
                                         IKpiFolder   *pFolder, //音楽データがあるフォルダ
                                         IKpiDecoder **ppDecoder)
{
    KbTakDecoder *pDecoder = new KbTakDecoder;
    DWORD dwCount = pDecoder->Open(cpRequest, pFile, pFolder);
    if(dwCount == 0){
        *ppDecoder = NULL;
        delete pDecoder;
        return 0;
    }
    *ppDecoder = pDecoder;
    return dwCount;
}
/////////////////////////////////////////////////////////////////////////////
HRESULT WINAPI kpi_CreateInstance(REFIID riid, void **ppvObject, IKpiUnknown *pUnknown)
{
    *ppvObject = NULL;
    if(!IsEqualIID(riid, IID_IKpiDecoderModule)){
        return E_NOINTERFACE;
    }
    IKpiDecoderModule *pDecoderModule = new KbTakDecoderModule();
    *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:
    {
        g_hKpi = hModule;
#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_PROCESS_DETACH:
        break;
    }
    return TRUE;
}
/////////////////////////////////////////////////////////////////////////////
