#include <windows.h>
#include <stdio.h>
#include "kbfpd_module.h"
#include "kbfpd_decoder.h"
#include "kbfpd_config.h"
////////////////////////////////////////////////////////
#ifdef _DEBUG
static const DWORD kbfpd_Version = 0x7FFFFFFF;
#define KBFPD_VERSION_STR L"0x7FFFFFFF(Debug)"
#else
static const DWORD kbfpd_Version = 21;
#define KBFPD_VERSION_STR L"0.21"
#endif

static const wchar_t kbfpd_Description[] = L"FPD Decoder v" KBFPD_VERSION_STR " based on fpd98.dll v3.30/fpd98sub.dll v1.05";
static const wchar_t kbfpd_Copyright[] =   L"kbfpd.kpi Copyright (C) 2003-2019 Kobarin\n"
                                           L"fpd98.dll Copyright (C) 1998-2001 rat Corporation\n"
                                           L"fpd98sub.dll Copyright (C) 1998-2001 KYU";
// {86FBE006-FFCD-46E0-BF1E-48C9F69D71DD}
static const GUID kbfpd_GUID = 
{ 0x86fbe006, 0xffcd, 0x46e0, { 0xbf, 0x1e, 0x48, 0xc9, 0xf6, 0x9d, 0x71, 0xdd } };
#ifdef _DEBUG
static const DWORD kbfpd_MultipleInstance = KPI_MULTINST_ONE;//KPI_MULTINST_ZERO だとデバッグしづらい
#else
//static const DWORD kbfpd_MultipleInstance = KPI_MULTINST_ONE;
static const DWORD kbfpd_MultipleInstance = KPI_MULTINST_ZERO;
#endif
static const wchar_t kbfpd_SupportExts[] = L".fpd/.fm";
static const wchar_t kbfpd_MultiSongExts[] = L"";
static const DWORD kbfpd_SupportTagInfo = KPI_DECODER_MODULEINFO::TAG_TITLE;
static const DWORD kbfpd_SupportConfig = 1;
static void* kbfpd_Reserved1 = NULL;
static void* kbfpd_Reserved2 = NULL;

DWORD g_dwPlatform;
LONG KbFpdDecoderModule::s_lInitialized = -1;//未初期化時は -1, 初期終了後は 1, 初期化中は 0
//////////////////////////////////////////////////////////////////////////////
KbFpdDecoderModule::KbFpdDecoderModule(IKpiConfig *pConfig)
    :m_ModuleInfo{
        sizeof(KPI_DECODER_MODULEINFO), //cb(=sizeof(KPI_DECODER_MODULEINFO))
        KPI_DECODER_MODULE_VERSION,     //dwModuleVersion(=KPI_DECODER_MODULE_VERSION)
        kbfpd_Version,
        kbfpd_MultipleInstance,
        kbfpd_GUID,
        kbfpd_Description,
        kbfpd_Copyright,
        kbfpd_SupportExts,
        kbfpd_MultiSongExts,
        kbfpd_Reserved1,
        kbfpd_Reserved2,
        kbfpd_SupportTagInfo,
        kbfpd_SupportConfig,
        0, 0, 0, 0                   //reserved
     }
{
    m_pConfig = pConfig;
    pConfig->AddRef();
}
//////////////////////////////////////////////////////////////////////////////
KbFpdDecoderModule::~KbFpdDecoderModule(void)
{
    if(InterlockedCompareExchange(&s_lInitialized, 0, 1) == 1){
        KbFpdDecoder::Uninitialize();
        InterlockedExchange(&s_lInitialized, -1);
    }
    m_pConfig->Release();
}
//////////////////////////////////////////////////////////////////////////////
void  WINAPI KbFpdDecoderModule::GetModuleInfo(const KPI_DECODER_MODULEINFO **ppInfo)
{
    bool bViaRunkpi = kbfpd_GetViaRunkpi(m_pConfig);
#ifdef _DEBUG
#if 1
    bViaRunkpi = false;
#endif
#endif
    m_ModuleInfo.dwMultipleInstance = bViaRunkpi ? KPI_MULTINST_ZERO :
                                                   KPI_MULTINST_ONE;
    if(!bViaRunkpi){
    //本体が未対応(MULTIPLE_ZERO の場合はタグ取得も常に別プロセス経由)
        m_ModuleInfo.dwSupportTagInfo |= KPI_DECODER_MODULEINFO::TAG_DECODER_EXCLUSIVE;
    }
    *ppInfo = &m_ModuleInfo;
}
//////////////////////////////////////////////////////////////////////////////
DWORD WINAPI KbFpdDecoderModule::Open(const KPI_MEDIAINFO *cpRequest,
                                      IKpiFile     *pFile,   //音楽データ
                                      IKpiFolder   *pFolder, //音楽データがあるフォルダ
                                      IKpiDecoder **ppDecoder)
{
    if(InterlockedCompareExchange(&s_lInitialized, 0, -1) == -1){
        KbFpdDecoder::Initialize();
        InterlockedExchange(&s_lInitialized, 1);
    }
    while(InterlockedCompareExchange(&s_lInitialized, 1, 1) == 0){
        Sleep(1);
    }
    kbfpd_CheckTemporary(m_pConfig);
    KbFpdDecoder *pDecoder = new KbFpdDecoder(m_pConfig);
    DWORD dwCount = pDecoder->Open(cpRequest, pFile, pFolder);
    if(dwCount == 0){
        *ppDecoder = NULL;
        delete pDecoder;
        return 0;
    }
    *ppDecoder = pDecoder;
    return dwCount;
}
//////////////////////////////////////////////////////////////////////////////
BOOL  WINAPI KbFpdDecoderModule::EnumConfig(IKpiConfigEnumerator *pEnumerator)
{
    return kbfpd_EnumConfig(m_pConfig, pEnumerator);

}
//////////////////////////////////////////////////////////////////////////////
DWORD WINAPI KbFpdDecoderModule::ApplyConfig(const wchar_t *cszSection, //セクション名
                              const wchar_t *cszKey, //キー名
                              INT64  nValue, //変更後の値(BOOL/INT の場合)
                              double dValue, //変更後の値(FLOAT の場合)
                              const wchar_t *cszValue)//変更後の値(文字列)
{
    return kbfpd_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 = NULL;
    kpi_CreateConfig(pUnknown, &kbfpd_GUID, &g_dwPlatform, &pConfig);
    IKpiDecoderModule *pDecoderModule = new KbFpdDecoderModule(pConfig);
    *ppvObject = pDecoderModule;
    pConfig->Release();
    return S_OK;
}
/////////////////////////////////////////////////////////////////////////////
