#pragma once

#include "kpi_decoder.h"
#include "kpi_impl.h"
#include "kbsnesapu_id666.h"
#include "kbsnesapu_config.h"

class KbSnesApuDecoder : public KbKpiUnknownImpl<IKpiDecoder>
{
public:
    static SAPUFunc  s_Apu;//Pointers to SNESAPU functions
private:
    static HINSTANCE s_hSnesApu;
    static KbSnesApuDecoder* s_pCurrentApu;//直前に SNESAPU の API を呼び出したインスタンス
    static CRITICAL_SECTION s_cs;
    static int       s_nInitializeCount;
    KPI_MEDIAINFO m_MediaInfo;
    KbId666       m_id666;
    IKpiFile     *m_pFile;
    IKpiFolder   *m_pFolder;
    //Context 保持用
    BYTE        *m_pContext;
    DWORD        m_dwContextSize;
    //
    SPCDATA      m_SpcData;
    UINT64       m_qwDecodeSample;//再生位置((UINT64)-1 のとき、まだ LoadApu() していない)
    IKpiConfig  *m_pConfig;
    double       m_dAmp;
    kbsnesapu_Settings m_Settings;
    void __fastcall GetMutex(void);
    void __fastcall ReleaseMutex(void);
    void __fastcall LoadApu(void);
    static u32 __stdcall SNESAPUCallbackProc(u32 effect, u32 addr, u32 value, void *pData);
    u32 SNESAPUCallbackProcInternal(u32 effect, u32 addr, u32 value, void *pData);
    void __fastcall ApplySettings(void);
public:
    KbSnesApuDecoder(IKpiConfig *pConfig);
    ~KbSnesApuDecoder(void);
    DWORD __fastcall Open(const KPI_MEDIAINFO *cpRequest,
                          IKpiFile *pFile,
                          IKpiFolder *pFolder);
    DWORD  WINAPI Select(DWORD dwNumber,
                         const KPI_MEDIAINFO **ppMediaInfo,
                         IKpiTagInfo *pTagInfo,
                         DWORD dwTagGetFlags);
    UINT64 WINAPI Seek(UINT64 qwPosSample, DWORD dwFlag);
    DWORD  WINAPI Render(BYTE *pBuffer, DWORD dwSizeSample);
    DWORD  WINAPI UpdateConfig(void *pvReserved);
    void __fastcall GetTagInfo(IKpiTagInfo *pTagInfo, DWORD dwTagGetFlags);
    static BOOL __fastcall Initialize(const wchar_t *cszDllPath);
    static void __fastcall Uninitialize(void);
};
