#include <windows.h>
#include <stdio.h>
#include "kbncsf_decoder.h"
#include "kbncsf_config.h"
#include "in_ncsf/XSFPlayer_NCSF.h"
#include "XSFConfig.h"

extern HINSTANCE g_hKpi;
XSFFile   *xSFFileInInfo;
/*
class XSFConfigIO_kbncsf : public XSFConfigIO
{
public:
    XSFConfigIO_kbncsf() { }
    // This is not defined in XSFConfig.cpp, it should be defined in your own config's source and return a pointer to your config's I/O class.
    //static XSFConfigIO *Create();
    ~XSFConfigIO_kbncsf(){ }
    void SetValueString(const std::string &name, const std::string &value);
    std::string GetValueString(const std::string &name, const std::string &defaultValue)const;
    void SetHInstance(HINSTANCE) { }
    HINSTANCE GetHInstance() const { return nullptr; }
};
XSFConfigIO *XSFConfigIO::Create()
{
    return new XSFConfigIO_kbncsf;
}
void XSFConfigIO_kbncsf::SetValueString(const std::string &name, const std::string &value)
{
}
std::string XSFConfigIO_kbncsf::GetValueString(const std::string &name, const std::string &defaultValue)const 
{ 
    return defaultValue; 
}
*/
///////////////////////////////////////////////////////////////////////////
//KbNcsfDecoder
///////////////////////////////////////////////////////////////////////////
void __fastcall KbNcsfDecoder::Init(IKpiConfig *pConfig)
{
//    xSFConfig = XSFConfig::Create();
    xSFFileInInfo = new XSFFile;
}
///////////////////////////////////////////////////////////////////////////
void __fastcall KbNcsfDecoder::Deinit(void)
{
//    delete xSFConfig;
//    xSFConfig = NULL;
    delete xSFFileInInfo;
    xSFFileInInfo = NULL;
}
///////////////////////////////////////////////////////////////////////////
KbNcsfDecoder::KbNcsfDecoder(IKpiConfig *pConfig)
{
    kpi_InitMediaInfo(&m_MediaInfo);
    m_pFile = NULL;
    m_ncsf = NULL;
    m_qwCurSample = -1;
    m_qwEndSample = -1;
    m_volume = 1.0;
    kbncsf_GetSettings(pConfig, &m_Settings);
}
///////////////////////////////////////////////////////////////////////////
KbNcsfDecoder::~KbNcsfDecoder(void)
{
    if(m_pFile){
        m_pFile->Release();
    }
    delete m_ncsf;
}
///////////////////////////////////////////////////////////////////////////
DWORD __fastcall KbNcsfDecoder::Open(const KPI_MEDIAINFO *cpRequest, 
                                    IKpiFile *pFile, 
                                    IKpiFolder *pFolder)
{
    int nSampleRate = m_Settings.nSampleRate;
    if(nSampleRate < 0){
        nSampleRate *= -1;
    }
    else if(cpRequest){
        if(cpRequest->dwSampleRate != 0){
            nSampleRate = cpRequest->dwSampleRate;
        }
    }
    switch(nSampleRate) {
    case 44100:case 48000: case 88200: case 96000: case 176400: case 192000:break;
    default: nSampleRate = 44100;break;
    }
    m_ncsf = new XSFPlayer_NCSF(pFile, pFolder);
    m_ncsf->SetSampleRate(nSampleRate);
    if(!m_ncsf->Load()){
        delete m_ncsf;
        m_ncsf = NULL;
        return 0;
    }
    m_ncsf->SetInterpolation(m_Settings.nInterpolation);
    m_MediaInfo.dwSampleRate = nSampleRate;
    m_MediaInfo.dwChannels = 2;
    m_MediaInfo.nBitsPerSample = -64;
    pFile->AddRef();
    m_pFile = pFile;
    const XSFFile *file = m_ncsf->GetXSFFile();
    int length_ms = file->GetLengthMS(-1);
    int fade_ms = file->GetFadeMS(-1);
    if(!m_Settings.bIgnoreVolumeTag){
        m_volume = file->GetVolume(VOLUMETYPE_VOLUME, PEAKTYPE_NONE);
    }
    m_volume *= m_Settings.dVolume;
    if(length_ms <= 0){
        m_MediaInfo.qwLength = -1;
    }
    else{
        m_MediaInfo.qwLength = kpi_MsTo100ns(length_ms);
    }
    if(fade_ms < 0){
        m_MediaInfo.qwFadeOut = -1;
    }
    else{
        m_MediaInfo.qwFadeOut = kpi_MsTo100ns(fade_ms);
    }
    if(m_MediaInfo.qwFadeOut == 0 && m_MediaInfo.qwLength != (UINT64)-1){
        m_MediaInfo.qwLoop = 0;
        m_qwEndSample = kpi_100nsToSample(m_MediaInfo.qwLength, m_MediaInfo.dwSampleRate);
    }
    else{
        m_MediaInfo.qwLoop = -1;
        m_qwEndSample = (UINT64)-1;
    }
    m_MediaInfo.dwNumber = 1;
    m_MediaInfo.dwCount = 1;
    m_qwCurSample = 0;
	return m_MediaInfo.dwCount;
}
///////////////////////////////////////////////////////////////////////////
DWORD WINAPI KbNcsfDecoder::Select(DWORD dwNumber,
                                  const KPI_MEDIAINFO **ppMediaInfo,
                                  IKpiTagInfo *pTagInfo,
                                  DWORD dwTagGetFlags)
{
    if(ppMediaInfo){
        *ppMediaInfo = NULL;
    }
    if (dwNumber > m_MediaInfo.dwCount) {
        return 0;
    }
    if (!ppMediaInfo) {//タグ取得のみ(タイトル/アーティストのみ)
        return 1;
    }
    *ppMediaInfo = &m_MediaInfo;
    return 1;
}
///////////////////////////////////////////////////////////////////////////
UINT64 WINAPI KbNcsfDecoder::Seek(UINT64 qwPosSample, DWORD dwFlag)
{
    if(m_qwCurSample > qwPosSample){
        m_ncsf->Terminate();
        m_ncsf->Load();
        m_ncsf->SeekTop();
        m_qwCurSample = 0;
        return 0;
    }
	return qwPosSample;
}
///////////////////////////////////////////////////////////////////////////
DWORD WINAPI KbNcsfDecoder::Render(BYTE *pBuffer, DWORD dwSizeSample)
{
    if(m_qwCurSample == (UINT64)-1){
        return 0;
    }
    if (m_qwCurSample + dwSizeSample > m_qwEndSample) {
        dwSizeSample = m_qwEndSample - m_qwCurSample;
    }
    const double k = m_volume / 0x8000;
    const int unit_sample = 2048;
    int tmp[unit_sample *2];
    double *dst = (double*)pBuffer;
    DWORD ret = 0;
    while(ret < dwSizeSample){
        DWORD copy_sample = dwSizeSample - ret;
        if(copy_sample > unit_sample){
            copy_sample = unit_sample;
        }
        m_ncsf->GenerateSamples((BYTE*)tmp, 0, copy_sample);
        for(int i = 0; i < copy_sample*2; i++){
            dst[i] = tmp[i]*k;
        }
        dst += copy_sample*2;
        ret += copy_sample;
    }
    m_qwCurSample += ret;
    return ret;
}
///////////////////////////////////////////////////////////////////////////
