#include <windows.h>
#include <mmreg.h>
#include <ks.h>

#include "kbwavefile_module.h"
#include "kbwavefile_device.h"
#include "kbwavefile_config.h"
#include "kbbenchmark_device.h"

// {D9219596-0896-49D6-81E8-A0C4CB9C6367}
static const GUID kbwavefile_GUID =
{ 0xd9219596, 0x896, 0x49d6, { 0x81, 0xe8, 0xa0, 0xc4, 0xcb, 0x9c, 0x63, 0x67 } };

#define KBWAVEFILE_VERSION 7
#define KBWAVEFILE_VERSION_STR "0.07"

static const DWORD   kbwavefile_PluginVersion = KBWAVEFILE_VERSION;
static const wchar_t kbwavefile_Description[] = L"WaveFile Device v" KBWAVEFILE_VERSION_STR ;
static const wchar_t kbwavefile_Copyright[] = L"Copyright (C) 2016-2022 Kobarin";
static const wchar_t kbwavefile_TypeName[] = L"WaveFile";
static const DWORD   kbwavefile_SupportConfig = 1;
static const DWORD   kbwavefile_SupportFlags = //KPI_DEVICE_MODULEINFO::SUPPORT_FLAG_VOLUME |
                                              //KPI_DEVICE_MODULEINFO::SUPPORT_FLAG_RATE |
                                              KPI_DEVICE_MODULEINFO::SUPPORT_FLAG_BITPERFECT |
                                              KPI_DEVICE_MODULEINFO::SUPPORT_FLAG_DISKWRITE |
                                              0;
static const DWORD   kbwavefile_MultipleInstance = KPI_MULTINST_INFINITE |
                                                  //KPI_MULTINST_ZERO |
                                                  //KPI_MULTINST_ONE |
                                                  //KPI_MULTINST_UNIQUE |
                                                  0;
static const wchar_t device_WaveFile[] = L"Wave File";
static const wchar_t device_Benchmark[]= L"Benchmark Test";

HINSTANCE g_hKpi;
///////////////////////////////////////////////////////////////////////////////
//KbWaveFileDeviceModule
///////////////////////////////////////////////////////////////////////////////
KbWaveFileDeviceModule::KbWaveFileDeviceModule(IKpiConfig *pConfig)
    :m_ModuleInfo{
        sizeof(KPI_DEVICE_MODULEINFO),
        KPI_OUTDEVICE_MODULE_VERSION,
        kbwavefile_PluginVersion,
        kbwavefile_MultipleInstance,
        kbwavefile_GUID,
        kbwavefile_Description,
        kbwavefile_Copyright,
        kbwavefile_TypeName,
        kbwavefile_SupportConfig,
        kbwavefile_SupportFlags,
        0, 0, 0, 0 //reservved
    }
{//必要な初期化はここで行う
    m_pConfig = pConfig;
    pConfig->AddRef();
}
///////////////////////////////////////////////////////////////////////////////
KbWaveFileDeviceModule::~KbWaveFileDeviceModule(void)
{//必要な後始末はここで行う
    m_pConfig->Release();
}
///////////////////////////////////////////////////////////////////////////////
void  WINAPI KbWaveFileDeviceModule::GetModuleInfo(const KPI_DEVICE_MODULEINFO **ppInfo)
{
    *ppInfo = &m_ModuleInfo;
}
///////////////////////////////////////////////////////////////////////////////
BOOL WINAPI KbWaveFileDeviceModule::Open(const wchar_t *cszDeviceName, //デバイス名
                                        const wchar_t *cszId,         //識別文字列
                                        const KPI_DEVICE_FORMAT *cpFormat, //再生周波数等
                                        int nBufferSizeSample,     //再生バッファサイズ（サンプル単位）
                                        IKpiOutDevice **ppOutDevice)
{
    *ppOutDevice = NULL;
    if(cpFormat->dwFormatType != KPI_MEDIAINFO::FORMAT_PCM){
        return FALSE;
    }
    if(wcscmp(cszDeviceName, device_WaveFile) == 0){
        KbWaveFileDevice *pDevice = new KbWaveFileDevice;
        if(pDevice->Open(m_pConfig, cszDeviceName, cszId, cpFormat, nBufferSizeSample)){
            *ppOutDevice = pDevice;
        }
        else{
            pDevice->Release();
        }
    }
    else if(wcscmp(cszDeviceName, device_Benchmark) == 0){
        KbBenchmarkDevice *pDevice = new KbBenchmarkDevice;
        if (pDevice->Open(m_pConfig, cszDeviceName, cszId, cpFormat, nBufferSizeSample)) {
            *ppOutDevice = pDevice;
        }
        else {
            pDevice->Release();
        }
    }
    return *ppOutDevice != NULL;
}
///////////////////////////////////////////////////////////////////////////////
void WINAPI KbWaveFileDeviceModule::EnumDevices(IKpiDeviceEnumerator *pEnumerator)
{//デバイス名の列挙
    kbwavefile_Settings settings;
    kbwavefile_GetSettings(m_pConfig, &settings);
    pEnumerator->Enumerate(device_WaveFile, L"");
    if(settings.bEnumBenchmark){
        pEnumerator->Enumerate(device_Benchmark, L"");
    }
}
///////////////////////////////////////////////////////////////////////////////
BOOL  WINAPI KbWaveFileDeviceModule::EnumConfig(IKpiConfigEnumerator *pEnumerator)
{
    return kbwavefile_EnumConfig(pEnumerator);
}
///////////////////////////////////////////////////////////////////////////////
DWORD WINAPI KbWaveFileDeviceModule::ApplyConfig(const wchar_t *cszSection, //セクション名
                             const wchar_t *cszKey,     //キー名
                             UINT64 nValue,             //変更後の値(INT)
                             double dValue,             //変更後の値(FLOAT)
                             const wchar_t *cszValue)
{
    return kbwavefile_ApplyConfig(m_pConfig, cszSection, cszKey, nValue, dValue, cszValue);
}
///////////////////////////////////////////////////////////////////////////////
HRESULT WINAPI kpi_CreateInstance(REFIID riid, void **ppvObject, IKpiUnknown *pUnknown)
{
    *ppvObject = NULL;
    if(!IsEqualIID(riid, IID_IKpiOutDeviceModule)){
        return E_NOINTERFACE;
    }
    IKpiConfig *pConfig;
    kpi_CreateConfig(pUnknown, &kbwavefile_GUID, NULL, &pConfig);
    IKpiOutDeviceModule *pModule = new KbWaveFileDeviceModule(pConfig);
    *ppvObject = pModule;
    pConfig->Release();
    return S_OK;
}
///////////////////////////////////////////////////////////////////////////////
BOOL APIENTRY DllMain(HMODULE hModule, DWORD  ul_reason_for_call, LPVOID lpReserved)
{
    switch (ul_reason_for_call){
        case DLL_PROCESS_ATTACH:
            {
                g_hKpi = hModule;
                DisableThreadLibraryCalls(hModule);
            }
            break;
        case DLL_PROCESS_DETACH:
            {
            }
            break;
    }
    return TRUE;
}
