#include <windows.h>
#include <stdio.h>
#include "kbnezplug_module.h"
#include "kbnezplug_decoder.h"
#include "kbnezplug_config.h"
//////////////////////////////////////////////////////////////////////////////
#ifdef _DEBUG
static const DWORD nezplug_Version = 0x7FFFFFFF;//デバッグ時は優先度最大
#define NEZPLUG_VERSION_STR L"0x7FFFFFFF(Debug)"
#else
static const DWORD nezplug_Version = 7;
#define NEZPLUG_VERSION_STR L"0.07"
#endif
static const wchar_t nezplug_Description[] = L"NEZplug Decoder v" NEZPLUG_VERSION_STR " based on NEZplug++ 0.9.4.8 + 3 + 24.10";
static const wchar_t nezplug_Copyright[] =   L"kbnezplug.kpi Copyright (C) 2016-2019 Kobarin\n"
                                             L"NEZplug++ 0.9.4.8 + 3 + 24.10 Copyright (C) 2000-2019 Mamiya, RuRuRu, Offgao";

// {09FC985F-6AFE-4204-8A1C-75840FD89FAA}
static const GUID nezplug_GUID = 
{ 0x9fc985f, 0x6afe, 0x4204, { 0x8a, 0x1c, 0x75, 0x84, 0xf, 0xd8, 0x9f, 0xaa } };

static const DWORD nezplug_MultipleInstance = KPI_MULTINST_ONE;//KPI_MULTINST_INFINITE;
static const wchar_t nezplug_SupportExts[] = L".nsf/.nez/.nsz/.nsd/.gbr/.gbs/.hes/.kss/.ay/.cpc/.sgc";
static const wchar_t nezplug_MultiSongExts[] = L".nsf/.nez/.nsz/.nsd/.gbr/.gbs/.hes/.kss/.ay/.cpc/.sgc";
static const DWORD nezplug_SupportTagInfo = KPI_DECODER_MODULEINFO::TAG_EXTRA;
static const DWORD nezplug_SupportConfig = 1;
static void* nezplug_Reserved1 = NULL;
static void* nezplug_Reserved2 = NULL;
//////////////////////////////////////////////////////////////////////////////
KbNEZplugDecoderModule::KbNEZplugDecoderModule(IKpiConfig *pConfig)
    :m_ModuleInfo{
        sizeof(KPI_DECODER_MODULEINFO), //cb(=sizeof(KPI_DECODER_MODULEINFO))
        KPI_DECODER_MODULE_VERSION,     //dwModuleVersion(=KPI_DECODER_MODULE_VERSION)
        nezplug_Version,
        nezplug_MultipleInstance,
        nezplug_GUID,
        nezplug_Description,
        nezplug_Copyright,
        nezplug_SupportExts,
        nezplug_MultiSongExts,
        nezplug_Reserved1,
        nezplug_Reserved2,
        nezplug_SupportTagInfo,
        nezplug_SupportConfig,
        0, 0, 0, 0                   //reserved
     }
{
    pConfig->AddRef();
    m_pConfig = pConfig;
}
//////////////////////////////////////////////////////////////////////////////
KbNEZplugDecoderModule::~KbNEZplugDecoderModule(void)
{
    m_pConfig->Release();
    if(m_ModuleInfo.cszSupportExts != nezplug_SupportExts){
        free((void*)m_ModuleInfo.cszSupportExts);
    }
}
//////////////////////////////////////////////////////////////////////////////
void  WINAPI KbNEZplugDecoderModule::GetModuleInfo(const KPI_DECODER_MODULEINFO **ppInfo)
{
    wchar_t szSupportExts[1024];
    kbnezplug_GetSupportExts(m_pConfig, szSupportExts, _countof(szSupportExts));
    if(m_ModuleInfo.cszSupportExts != nezplug_SupportExts){
        free((void*)m_ModuleInfo.cszSupportExts);
    }
    if(szSupportExts[0]){
        m_ModuleInfo.cszSupportExts = _wcsdup(szSupportExts);
    }
    else{
        m_ModuleInfo.cszSupportExts = nezplug_SupportExts;
    }
    *ppInfo = &m_ModuleInfo;
}
//////////////////////////////////////////////////////////////////////////////
DWORD WINAPI KbNEZplugDecoderModule::Open(const KPI_MEDIAINFO *cpRequest,
                                      IKpiFile     *pFile,   //音楽データ
                                      IKpiFolder   *pFolder, //音楽データがあるフォルダ
                                      IKpiDecoder **ppDecoder)
{
    static LONG lInitialized = -1;
    if(InterlockedCompareExchange(&lInitialized, 0, -1) < 0){
        kbnezplug_GetGlobalSettings(m_pConfig);
    }
    KbNEZplugDecoder *pDecoder = new KbNEZplugDecoder;
    DWORD dwCount = pDecoder->Open(cpRequest, pFile, pFolder, m_pConfig);
    if(dwCount == 0){
        *ppDecoder = NULL;
        delete pDecoder;
        return 0;
    }
    *ppDecoder = pDecoder;
    return dwCount;
}
/////////////////////////////////////////////////////////////////////////////
BOOL  WINAPI KbNEZplugDecoderModule::EnumConfig(IKpiConfigEnumerator *pEnumerator)
{
    return kbnezplug_EnumConfig(pEnumerator);
}
/////////////////////////////////////////////////////////////////////////////
DWORD WINAPI KbNEZplugDecoderModule::ApplyConfig(const wchar_t *cszSection,//セクション名
                             const wchar_t *cszKey,    //キー名
                             INT64  nValue, //変更後の値(BOOL/INT の場合)
                             double dValue, //変更後の値(FLOAT の場合)
                             const wchar_t *cszValue)////変更後の値(文字列)
{
    return kbnezplug_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, &nezplug_GUID, NULL, &pConfig);
    IKpiDecoderModule *pDecoderModule = new KbNEZplugDecoderModule(pConfig);
    *ppvObject = pDecoderModule;
    pConfig->Release();
    return S_OK;
}
