#include <windows.h>
#include <stdio.h>
#include "kbgme_module.h"
#include "kbgme_decoder.h"
#include "kbgme_config.h" //IKpiConfig 未対応ならコメントアウト

//////////////////////////////////////////////////////////////////////////////
#ifdef _DEBUG
static const DWORD kbgme_Version = 0x7FFFFFFF;//デバッグ時は優先度最大
#define KBGME_VERSION_STR L"0x7FFFFFFF(Debug)"
#else
static const DWORD kbgme_Version = 1;
#define KBGME_VERSION_STR L"0.01"
#endif

static const wchar_t kbgme_Description[] = L"game-music-emu Decoder v" KBGME_VERSION_STR " based on libgme 0.6.4";
static const wchar_t kbgme_Copyright[] =   L"kbgme.kpi Copyright(C)2024 Kobarin\n"
                                           L"libgme Copyright(C)2024 Shay Green, Vitaly Novichkov, Michael Pyne";

// {6522CFCA-FA20-42CB-BA92-282D6462117B}
static const GUID kbgme_GUID =
{ 0x6522cfca, 0xfa20, 0x42cb, { 0xba, 0x92, 0x28, 0x2d, 0x64, 0x62, 0x11, 0x7b } };

static const DWORD kbgme_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 kbgme_SupportExts[] = L".ay/.gbs/.gym/.hes/.kss/.nsf/.nsfe/.sap/.spc/.vgm/.vgz";
static const wchar_t kbgme_MultiSongExts[] = L".ay/.gbs/.hes/.kss/.nsf/.nsfe/.sap";//SupportExts に含まないものを指定しても無視される
static const DWORD kbgme_SupportTagInfo = KPI_DECODER_MODULEINFO::TAG_TITLE | //未対応ならコメントアウト
                                           //KPI_DECODER_MODULEINFO::TAG_EXTRA | //未対応ならコメントアウト
                                          0;
static const DWORD kbgme_SupportConfig = 1;
static void* kbgme_Reserved1 = NULL;
static void* kbgme_Reserved2 = NULL;

//////////////////////////////////////////////////////////////////////////////
KbGmeDecoderModule::KbGmeDecoderModule(IKpiConfig *pConfig) //IKpiConfig 未対応なら KbGmeDecoderModle(void)
    :m_ModuleInfo{
        sizeof(KPI_DECODER_MODULEINFO), //cb(=sizeof(KPI_DECODER_MODULEINFO))
        KPI_DECODER_MODULE_VERSION,     //dwModuleVersion(=KPI_DECODER_MODULE_VERSION)
        kbgme_Version,
        kbgme_MultipleInstance,
        kbgme_GUID,
        kbgme_Description,
        kbgme_Copyright,
        kbgme_SupportExts,
        kbgme_MultiSongExts,
        kbgme_Reserved1,
        kbgme_Reserved2,
        kbgme_SupportTagInfo,
        kbgme_SupportConfig,
        0, 0, 0, 0                   //reserved
     }
{
    pConfig->AddRef();  //IKpiConfig未対応なら
    m_pConfig = pConfig;//ここまでコメントアウト
    KbGmeDecoder::Initialize(pConfig);
}
//////////////////////////////////////////////////////////////////////////////
KbGmeDecoderModule::~KbGmeDecoderModule(void)
{
    m_pConfig->Release();
    KbGmeDecoder::Uninitialize();
    if(m_ModuleInfo.cszSupportExts != kbgme_SupportExts){
        free((wchar_t*)m_ModuleInfo.cszSupportExts);
    }
}
//////////////////////////////////////////////////////////////////////////////
void  WINAPI KbGmeDecoderModule::GetModuleInfo(const KPI_DECODER_MODULEINFO **ppInfo)
{
    if(m_ModuleInfo.cszSupportExts != kbgme_SupportExts){
        free((wchar_t*)m_ModuleInfo.cszSupportExts);
    }
    wchar_t *pszSupportExts;
    bool bHighPriority;
    kbgme_GetSupportExts(m_pConfig, &pszSupportExts, &bHighPriority);
    m_ModuleInfo.cszSupportExts = pszSupportExts;
    if(bHighPriority){
        m_ModuleInfo.dwPluginVersion = INT_MAX;
    }
    else{
        m_ModuleInfo.dwPluginVersion = kbgme_Version;
    }
    *ppInfo = &m_ModuleInfo;
}
//////////////////////////////////////////////////////////////////////////////
DWORD WINAPI KbGmeDecoderModule::Open(const KPI_MEDIAINFO *cpRequest,
                                      IKpiFile     *pFile,   //音楽データ
                                      IKpiFolder   *pFolder, //音楽データがあるフォルダ
                                      IKpiDecoder **ppDecoder)
{
    KbGmeDecoder *pDecoder = new KbGmeDecoder(m_pConfig);
    DWORD dwCount = pDecoder->Open(cpRequest, pFile, pFolder);
    if(dwCount == 0){
        *ppDecoder = NULL;
        delete pDecoder;
        return 0;
    }
    *ppDecoder = pDecoder;
    return dwCount;
}
/////////////////////////////////////////////////////////////////////////////
BOOL  WINAPI KbGmeDecoderModule::EnumConfig(IKpiConfigEnumerator *pEnumerator)
{
    return kbgme_EnumConfig(pEnumerator);
}
/////////////////////////////////////////////////////////////////////////////
DWORD WINAPI KbGmeDecoderModule::ApplyConfig(const wchar_t *cszSection,//セクション名
                             const wchar_t *cszKey,    //キー名
                             INT64  nValue, //変更後の値(BOOL/INT の場合)
                             double dValue, //変更後の値(FLOAT の場合)
                             const wchar_t *cszValue)////変更後の値(文字列)
{
    return kbgme_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, &kbgme_GUID, NULL, &pConfig);
    IKpiDecoderModule *pDecoderModule = new KbGmeDecoderModule(pConfig);
    *ppvObject = pDecoderModule;
    pConfig->Release();//KbGmeDecoderModule 内部でインクリメント/デクリメントする
    return S_OK;
}
/////////////////////////////////////////////////////////////////////////////
