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

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

#include "kbungca_module.h"
#include "kbungca_config.h"
#include "KbUnGca.h"

#ifdef _DEBUG
static const DWORD kbungca_Version = 0x7FFFFFFF; //デバッグ時は優先度最大
#define KBUNGCA_VERSION_STR L"0x7FFFFFFF(Debug)"
#else
static const DWORD kbungca_Version = 7; //プラグインのバージョン
#define KBUNGCA_VERSION_STR L"0.07"
#endif

static const wchar_t kbungca_Description[] = L"GCA Archive Decoder v" KBUNGCA_VERSION_STR L" based on GcaSDK v0.9k2";
static const wchar_t kbungca_Copyright[] = L"kbungca.kpi Copyright (C) 2016-2024 Kobarin\n"
                                           L"GcaSDK Copyright (C) 2000-2003 SYN((Shin-ichi TSURUTA) All Rights Reserved.";

// {E6705BAE-3274-4EF3-9271-278582099547}
static const GUID kbungca_GUID =
{ 0xe6705bae, 0x3274, 0x4ef3, { 0x92, 0x71, 0x27, 0x85, 0x82, 0x9, 0x95, 0x47 } };

static const DWORD kbungca_MultipleInstance = KPI_MULTINST_INFINITE;//同時に何個でも作成可能
                                              //KPI_MULTINST_ZERO;  //常に別プロセス起動
                                              //KPI_MULTINST_ONE;   //2個目以降は別プロセス起動
                                              //KPI_MULTINST_UNIQUE;//プロセスをまたいでも１つまで
                                              //KPI_MULTINST_ZERO + N;//(N+1)個目以降は別プロセス起動
                                              //↑どれか１つを選択
static const wchar_t kbungca_SupportExts[] = L".gca";
static const wchar_t kbungca_SolidExts[] = L".gca";
static const DWORD   kbungca_SupportConfig = 1;

IKpiUnkProvider *g_pProvider = NULL;
//////////////////////////////////////////////////////////////////////////////
KbUnGcaModule::KbUnGcaModule(IKpiConfig *pConfig)
    :m_ModuleInfo{
        sizeof(KPI_UNARC_MODULEINFO), //cb(=sizeof(KPI_UNARC_MODULEINFO))
        KPI_UNARC_MODULE_VERSION,     //dwModuleVersion(=KPI_UNARC_MODULE_VERSION)
        kbungca_Version,
        kbungca_MultipleInstance,
        kbungca_GUID,
        kbungca_Description,
        kbungca_Copyright,
        kbungca_SupportExts,
        kbungca_SolidExts,
        kbungca_SupportConfig,
        0, 0, 0, 0 //reserved
    }                     
    
{
    m_pConfig = pConfig;
    pConfig->AddRef();
}
//////////////////////////////////////////////////////////////////////////////
KbUnGcaModule::~KbUnGcaModule(void)
{
    KbUnGca::Uninitialize();
    m_pConfig->Release();
    if(g_pProvider){
        g_pProvider->Release();
        g_pProvider = NULL;
    }
}
//////////////////////////////////////////////////////////////////////////////
void  WINAPI KbUnGcaModule::GetModuleInfo(const KPI_UNARC_MODULEINFO **ppInfo)
{
    *ppInfo = &m_ModuleInfo;
}
//////////////////////////////////////////////////////////////////////////////
BOOL WINAPI KbUnGcaModule::Open(IKpiFile   *pFile,  //アーカイブファイル
                                IKpiFolder *pFolder,//アーカイブファイルがあるフォルダ
                                const wchar_t *cszOutputPath,//作業用フォルダ
                                IKpiUnArc **ppUnArc)
{
    *ppUnArc = NULL;
    KbUnGca *pUnGca = new KbUnGca(m_pConfig);
    if(pUnGca->Open(pFile, pFolder, cszOutputPath)){
        *ppUnArc = pUnGca;
        return TRUE;
    }
    pUnGca->Release();
    return FALSE;
}
//////////////////////////////////////////////////////////////////////////////
BOOL  WINAPI KbUnGcaModule::EnumConfig(IKpiConfigEnumerator *pEnumerator)
{
    return kbungca_EnumConfig(m_pConfig, pEnumerator);
}
//////////////////////////////////////////////////////////////////////////////
DWORD WINAPI KbUnGcaModule::ApplyConfig(const wchar_t *cszSection,
                                        const wchar_t *cszKey,
                                        INT64 nValue,
                                        double dValue,
                                        const wchar_t *cszValue)
{
    return kbungca_ApplyConfig(m_pConfig, cszSection, cszKey, nValue, dValue, cszValue);
}
//////////////////////////////////////////////////////////////////////////////
HRESULT WINAPI kpi_CreateInstance(REFIID riid, void **ppvObject, IKpiUnknown *pUnknown)
{
    *ppvObject = NULL;
    if(!IsEqualIID(riid, IID_IKpiUnArcModule)){
        return E_NOINTERFACE;
    }
    if(!g_pProvider){
        pUnknown->QueryInterface(IID_IKpiUnkProvider, (void**)&g_pProvider);
    }
    if(!g_pProvider){
        return E_NOINTERFACE;
    }
    IKpiConfig *pConfig;
    kpi_CreateConfig(pUnknown, &kbungca_GUID, NULL, &pConfig);
    IKpiUnArcModule *pUnArcModule = new KbUnGcaModule(pConfig);
    *ppvObject = pUnArcModule;
    pConfig->Release();//KbUnGcaModule 内で AddRef しているので必ず必要
    return S_OK;
}
//////////////////////////////////////////////////////////////////////////////
