#include <windows.h>
#include <stdio.h>

#include "kbdsound_module.h"
#include "kbdsound_device.h"
#include "kbdsound_enum.h"
#include "kbdsound_config.h"

// {0D726D92-3998-4D03-9809-3CC91E2E1EB7}
static const GUID kbdsound_GUID =
{ 0xd726d92, 0x3998, 0x4d03, { 0x98, 0x9, 0x3c, 0xc9, 0x1e, 0x2e, 0x1e, 0xb7 } };

#define KBDSOUND_VERSION 6
#define KBDSOUND_VERSION_STR "0.06"

static const DWORD   kbdsound_PluginVersion = KBDSOUND_VERSION;
static const wchar_t kbdsound_Description[] = L"DirectSound Device v" KBDSOUND_VERSION_STR ;
static const wchar_t kbdsound_Copyright[] = L"Copyright (C) 2016-2019 Kobarin";
static const wchar_t kbdsound_TypeName[] = L"DirectSound";
static const DWORD   kbdsound_SupportConfig = 1;
static const DWORD   kbdsound_SupportFlags = KPI_DEVICE_MODULEINFO::SUPPORT_FLAG_VOLUME |
                                             KPI_DEVICE_MODULEINFO::SUPPORT_FLAG_RATE |
                                             //KPI_DEVICE_MODULEINFO::SUPPORT_FLAG_BITPERFECT |
                                             0;
static const DWORD   kbdsound_MultipleInstance = KPI_MULTINST_INFINITE |
                                                 //KPI_MULTINST_ZERO |
                                                  //KPI_MULTINST_ONE |
                                                  //KPI_MULTINST_UNIQUE |
                                                  0;

///////////////////////////////////////////////////////////////////////////////
//KbDSoundDeviceModule
///////////////////////////////////////////////////////////////////////////////
KbDSoundDeviceModule::KbDSoundDeviceModule(IKpiConfig *pConfig)
    :m_ModuleInfo{
        sizeof(KPI_DEVICE_MODULEINFO),
        KPI_OUTDEVICE_MODULE_VERSION,
        kbdsound_PluginVersion,
        kbdsound_MultipleInstance,
        kbdsound_GUID,
        kbdsound_Description,
        kbdsound_Copyright,
        kbdsound_TypeName,
        kbdsound_SupportConfig,
        kbdsound_SupportFlags,
        0, 0, 0, 0 //reservved
    }
{
    //KbDSoundDevice::LoadDSoundDll();//必要になるまで呼ばない
    m_pConfig = pConfig;
    pConfig->AddRef();
}
///////////////////////////////////////////////////////////////////////////////
KbDSoundDeviceModule::~KbDSoundDeviceModule(void)
{
    KbDSoundDevice::Uninitialize();
    m_pConfig->Release();
}
///////////////////////////////////////////////////////////////////////////////
void  WINAPI KbDSoundDeviceModule::GetModuleInfo(const KPI_DEVICE_MODULEINFO **ppInfo)
{
    *ppInfo = &m_ModuleInfo;
}
///////////////////////////////////////////////////////////////////////////////
void  WINAPI KbDSoundDeviceModule::EnumDevices(IKpiDeviceEnumerator *pEnumerator)
{
    KbDSoundEnumerator dsEnumerator;
    dsEnumerator.EnumerateDevices(pEnumerator);
}
///////////////////////////////////////////////////////////////////////////////
BOOL  WINAPI KbDSoundDeviceModule::EnumConfig(IKpiConfigEnumerator *pEnumerator)
{
    return kbdsound_EnumConfig(pEnumerator);
}
///////////////////////////////////////////////////////////////////////////////
DWORD WINAPI KbDSoundDeviceModule::ApplyConfig(const wchar_t *cszSection, //セクション名
                                               const wchar_t *cszKey,     //キー名
                                               UINT64 nValue,             //変更後の値(INT)
                                               double dValue,             //変更後の値(FLOAT)
                                               const wchar_t *cszValue)   //変更後の値(STR)
{
    return kbdsound_ApplyConfig(m_pConfig, cszSection, cszKey, nValue, dValue, cszValue);
}
///////////////////////////////////////////////////////////////////////////////
BOOL WINAPI KbDSoundDeviceModule::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;
    }
    KbDSoundDevice *pDevice = new KbDSoundDevice;
    if(pDevice->Open(cszDeviceName, cszId, cpFormat, nBufferSizeSample, m_pConfig)){
        *ppOutDevice = pDevice;
    }
    else{
        pDevice->Release();
    }
    return *ppOutDevice != NULL;
}
///////////////////////////////////////////////////////////////////////////////
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, &kbdsound_GUID, NULL, &pConfig);
    KbDSoundDeviceModule *pModule = new KbDSoundDeviceModule(pConfig);
    *ppvObject = (IKpiOutDeviceModule*)pModule;
    pConfig->Release();
    return S_OK;
}
///////////////////////////////////////////////////////////////////////////////
BOOL WINAPI DllMain(HMODULE hModule, DWORD  ul_reason_for_call, LPVOID lpReserved)
{
    switch (ul_reason_for_call){
        case DLL_PROCESS_ATTACH:
            {
                DisableThreadLibraryCalls(hModule);
            }
            break;
        case DLL_PROCESS_DETACH:
            {
            }
            break;
    }
    return TRUE;
}
///////////////////////////////////////////////////////////////////////////////
