#pragma once

#include "kpi_decoder.h"
#include "kpi_impl.h"
#include "kbmsxplug_config.h"

#include "in_msx.h"
#include "kssplay.h"
#include "optdlg/optdlg.h"

class KbMsxplugDecoder : public KbKpiUnknownImpl<IKpiDecoder>
{
private:
    struct KMP_STATUS{//本体の再生位置を取得するための構造体(非公式)
        DWORD dwStructSize;//=sizeof(KMP_STATUS) //プラグイン側で設定
        DWORD dwAccepted;  //本体が受け入れてば 1//本体側で設定(作成直後にプラグイン側で 0 にする)
        DWORD dwPosition;  //再生位置(ms)        //本体側で設定
        DWORD dwStatus;    //KPI_STATUS_STOP/KPI_STATUS_PLAYING/KPI_STATIS_PAUSE(kpi_player.h)//本体側で設定
    };
    static KbMsxplugDecoder *s_pActive;
    static LONG              s_lInitDone;
    KPI_MEDIAINFO  m_MediaInfo;
    KSS           *m_kss;
    KSSPLAY       *m_kssPlay;
    kbmsxplug_Settings m_Settings;
    IKpiConfig    *m_pConfig;
    BOOL           m_bUseILL;
    unsigned char  m_ILLdata[16*19];
    UINT64         m_qwCurSample;
    //MGS 歌詞用
    OPTDLG        *m_MgsDlg;    //歌詞ダイアログ
    DWORD          m_dwMgsThreadId;
    volatile LONG  m_lMgsInitialized;//歌詞ダイアログ未初期化時-1、初期化後 0 
    HANDLE         m_hMgsThread;//歌詞ダイアログを作成するスレッドのハンドル
    HANDLE         m_hFileMap;  //KMP_STATUS を得るためのファイルマップハンドル
    KMP_STATUS    *m_pStatus;
    BOOL           m_bHasMgsLyr;//TRUE のとき、MGS 歌詞を含む
    CRITICAL_SECTION m_cs;      //MGS のときだけ InitializeCriticalSection する
    static unsigned __stdcall MgsThreadProc(void *instance){
        return ((KbMsxplugDecoder*)instance)->MgsThreadProcInternal();
    }
    unsigned __fastcall MgsThreadProcInternal(void);
    void __fastcall CreateStatusFileMap(void);
    void __fastcall CreateMgsDlg(void);
    void __fastcall DeleteMgsDlg(void);
    static wchar_t* getLyrics(void *instance, wchar_t *text, int size, DWORD *decode_pos_ms, DWORD *play_pos_ms){
        return ((KbMsxplugDecoder*)instance)->getLyricsInternal(text, size, decode_pos_ms, play_pos_ms);
    }
    wchar_t* __fastcall getLyricsInternal(wchar_t *text, int size, DWORD *decode_pos_ms, DWORD *play_pos_ms);
    void __fastcall Lock(void){if(m_bHasMgsLyr)EnterCriticalSection(&m_cs);}  //歌詞を含むときだけクリティカルセクションに入る
    void __fastcall Unlock(void){if(m_bHasMgsLyr)LeaveCriticalSection(&m_cs);}//歌詞を含むときだけクリティカルセクションに入る
    //ここまで
public:
    DWORD  __fastcall Open(const KPI_MEDIAINFO *cpRequest, 
                           IKpiFile   *pFile, 
                           IKpiFolder *pFolder,
                           IKpiConfig *pConfig);
    DWORD  WINAPI Select(DWORD dwNumber,
                         const KPI_MEDIAINFO **ppMediaInfo,
                         IKpiTagInfo *pTagInfo,
                         DWORD dwTagGetFlags);
    DWORD  WINAPI Render(BYTE *pBuffer, DWORD dwSizeSample);
    UINT64 WINAPI Seek(UINT64 qwPosSample, DWORD dwFlag);
    DWORD  WINAPI UpdateConfig(void *pvReserved){return 0;}
    void __fastcall GetTagInfo(IKpiTagInfo *pTagInfo, DWORD dwTagGetFlags);
    KbMsxplugDecoder(IKpiConfig *pConfig);
    ~KbMsxplugDecoder(void);
};
