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

#include "kmp_pi.h"
#include "kpi.h"
#include "kpi_impl.h"
#include "kbflac_decoder.h"
#include "kbflac_tag.h"

/////////////////////////////////////////////////////////////////////////////
KbFlacDecoder::KbFlacDecoder(IKpiFile *pFile, IKpiFolder *pFolder)
{
    m_decoder = NULL;
    m_pFile = pFile;
    ZeroMemory(&m_stream_info, sizeof(m_stream_info));
    m_block_align = 0;
    m_direct_buf = NULL;
    m_direct_buf_size = 0;
    m_direct_buf_copied = 0;
    m_temp_buf_size = 0;
    m_temp_buf_remain = 0;
    kpi_InitMediaInfo(&m_MediaInfo);
    pFile->AddRef();
}
/////////////////////////////////////////////////////////////////////////////
KbFlacDecoder::~KbFlacDecoder(void)
{
    if(m_decoder){
        FLAC__stream_decoder_finish(m_decoder);
        FLAC__stream_decoder_delete(m_decoder);
    }
    if(m_pFile){
        m_pFile->Release();
    }
}
/////////////////////////////////////////////////////////////////////////////
DWORD WINAPI KbFlacDecoder::Render(BYTE *Buffer, DWORD dwSizeSample)
{
    DWORD dwRet = 0;
    DWORD dwSize = dwSizeSample * m_block_align;
    while (1) {
        if (m_temp_buf_remain) {
            DWORD copy_bytes = m_temp_buf_remain;
            if (copy_bytes + dwRet > dwSize) {
                copy_bytes = dwSize - dwRet;
            }
            memcpy(Buffer + dwRet, m_temp_buf + m_temp_buf_size - m_temp_buf_remain, copy_bytes);
            m_temp_buf_remain -= copy_bytes;
            dwRet += copy_bytes;
            if (dwRet == dwSize) {
                break;
            }
        }
        if (FLAC__stream_decoder_get_state(m_decoder) == FLAC__STREAM_DECODER_END_OF_STREAM) {
            break;
        }
        m_direct_buf = Buffer + dwRet;
        m_direct_buf_size = dwSize - dwRet;
        m_direct_buf_copied = 0;
        if (!FLAC__stream_decoder_process_single(m_decoder)) {
            break;
        }
        dwRet += m_direct_buf_copied;
        if (dwRet == dwSize) {
            break;
        }
    }
    return dwRet / m_block_align;
}
/////////////////////////////////////////////////////////////////////////////
UINT64 WINAPI KbFlacDecoder::Seek(UINT64 qwPosSample, DWORD dwFlags)
{
    m_direct_buf = NULL;
    m_direct_buf_size = m_direct_buf_copied = 0;//write_callback が呼ばれるので必ず必要
    m_temp_buf_size = m_temp_buf_remain = 0;    //write_callback が呼ばれるので必ず必要
    if (FLAC__stream_decoder_seek_absolute(m_decoder, qwPosSample)) {
        return qwPosSample;
    }
    return 0;
}
/////////////////////////////////////////////////////////////////////////////
DWORD WINAPI KbFlacDecoder::Select(DWORD dwNumber,
                                   const KPI_MEDIAINFO **ppMediaInfo, 
                                   IKpiTagInfo *pTagInfo,
                                   DWORD dwTagGetFlags)
{
    if(ppMediaInfo){
        *ppMediaInfo = NULL;
    }
    if(dwNumber > 1){//番号がおかしい
        return 0;
    }
    if(pTagInfo){
        kbflac_GetTagInfoFromStream(m_pFile, pTagInfo, dwTagGetFlags);
    }
    if(!ppMediaInfo){
        return 1;
    }
    FLAC__StreamDecoder *decoder = FLAC__stream_decoder_new();
    m_pFile->Seek(0, FILE_BEGIN);
    m_decoder = decoder;
    if (FLAC__stream_decoder_init_stream(decoder,
                                         read_callback,
                                         seek_callback,
                                         tell_callback,
                                         length_callback,
                                         eof_callback,
                                         write_callback,
                                         metadata_callback,
                                         error_callback,
                                         this) != FLAC__STREAM_DECODER_INIT_STATUS_OK) {
        return 0;
    }
    if (!FLAC__stream_decoder_process_until_end_of_metadata(decoder)) {
        //OGG Flac?
        FLAC__stream_decoder_finish(decoder);
        FLAC__stream_decoder_delete(decoder);
        m_decoder = decoder = FLAC__stream_decoder_new();
        m_pFile->Seek(0, FILE_BEGIN);
        if (FLAC__stream_decoder_init_ogg_stream(decoder,
                                                 read_callback,
                                                 seek_callback,
                                                 tell_callback,
                                                 length_callback,
                                                 eof_callback,
                                                 write_callback,
                                                 metadata_callback,
                                                 error_callback,
                                                 this) != FLAC__STREAM_DECODER_INIT_STATUS_OK) {
            return 0;
        }
        if (!FLAC__stream_decoder_process_until_end_of_metadata(decoder)) {
            return 0;
        }
    }
    if (m_stream_info.bits_per_sample != 32 &&
        m_stream_info.bits_per_sample != 24 &&
        m_stream_info.bits_per_sample != 16 &&
        m_stream_info.bits_per_sample != 8) {
        return 0;
    }
    m_block_align = (m_stream_info.bits_per_sample / 8) * m_stream_info.channels;
    kpi_InitMediaInfo(&m_MediaInfo);
    m_MediaInfo.cb = sizeof(KPI_MEDIAINFO);
    m_MediaInfo.dwNumber = 1;
    m_MediaInfo.dwCount = 1;
    m_MediaInfo.dwFormatType = KPI_MEDIAINFO::FORMAT_PCM;
    m_MediaInfo.dwSampleRate = m_stream_info.sample_rate;
    m_MediaInfo.nBitsPerSample = m_stream_info.bits_per_sample;
    m_MediaInfo.dwChannels = m_stream_info.channels;
    m_MediaInfo.dwSpeakerConfig = 0;
    m_MediaInfo.dwSeekableFlags = KPI_MEDIAINFO::SEEK_FLAGS_SAMPLE;
    m_MediaInfo.dwUnitSample = 0;
    m_MediaInfo.qwLength = kpi_SampleTo100ns(m_stream_info.total_samples, m_stream_info.sample_rate);
    m_MediaInfo.qwLoop = 0;
    m_MediaInfo.qwFadeOut = 0;
    m_MediaInfo.dwLoopCount = 0;
    *ppMediaInfo = &m_MediaInfo;
    return 1;
}
/////////////////////////////////////////////////////////////////////////////
FLAC__StreamDecoderWriteStatus KbFlacDecoder::write_callback(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data)
{
    KbFlacDecoder *flacDecoder = (KbFlacDecoder*)client_data;
    return flacDecoder->write_callback(decoder, frame, buffer);
}
/////////////////////////////////////////////////////////////////////////////
void KbFlacDecoder::metadata_callback(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data)
{
    KbFlacDecoder *flacDecoder = (KbFlacDecoder*)client_data;
    flacDecoder->metadata_callback(decoder, metadata);
}
/////////////////////////////////////////////////////////////////////////////
void KbFlacDecoder::error_callback(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data)
{
}
/////////////////////////////////////////////////////////////////////////////
void KbFlacDecoder::metadata_callback(const FLAC__StreamDecoder  *decoder, 
                                      const FLAC__StreamMetadata *metadata)
{
	if(metadata->type == FLAC__METADATA_TYPE_STREAMINFO) {
		memcpy(&m_stream_info, &metadata->data.stream_info, sizeof(m_stream_info));
	}
}
/////////////////////////////////////////////////////////////////////////////
FLAC__StreamDecoderWriteStatus KbFlacDecoder::write_callback(const FLAC__StreamDecoder *decoder, 
                                                             const FLAC__Frame *frame, 
                                                             const FLAC__int32 *const buffer[])
{
	int wide_sample, sample, channel;
    int channels = m_stream_info.channels;
    int wide_samples = frame->header.blocksize;
    int direct_copy_samples = m_direct_buf_size / m_block_align;
    if(direct_copy_samples > wide_samples){
        direct_copy_samples = wide_samples;
    }
    if(m_stream_info.bits_per_sample == 16){
        for(sample = 0, wide_sample = 0; wide_sample < direct_copy_samples; wide_sample++){
            for(channel = 0; channel < channels; channel++, sample++){
		    	((FLAC__int16*)m_direct_buf)[sample] = (FLAC__int16)buffer[channel][wide_sample];
            }
        }
        for(sample = 0; wide_sample < wide_samples; wide_sample++){
            for(channel = 0; channel < channels; channel++, sample++){
		    	((FLAC__int16*)m_temp_buf)[sample] = (FLAC__int16)buffer[channel][wide_sample];
            }
        }
    }
    else if (m_stream_info.bits_per_sample == 32) {
        for (sample = 0, wide_sample = 0; wide_sample < direct_copy_samples; wide_sample++) {
            for (channel = 0; channel < channels; channel++, sample++) {
                ((FLAC__int32*)m_direct_buf)[sample] = (FLAC__int32)buffer[channel][wide_sample];
            }
        }
        for (sample = 0; wide_sample < wide_samples; wide_sample++) {
            for (channel = 0; channel < channels; channel++, sample++) {
                ((FLAC__int32*)m_temp_buf)[sample] = (FLAC__int32)buffer[channel][wide_sample];
            }
        }

    }
    else if(m_stream_info.bits_per_sample == 24){
        for(sample = 0, wide_sample = 0; wide_sample < direct_copy_samples; wide_sample++){
            for(channel = 0; channel < channels; channel++, sample++){
		        BYTE *dst = &m_direct_buf[sample*3];
                const BYTE *src = (const BYTE*)&buffer[channel][wide_sample];
                dst[0] = src[0];
                dst[1] = src[1];
                dst[2] = src[2];
            }
        }
        for(sample = 0; wide_sample < wide_samples; wide_sample++){
            for(channel = 0; channel < channels; channel++, sample++){
		        BYTE *dst = &m_temp_buf[sample*3];
                const BYTE *src = (const BYTE*)&buffer[channel][wide_sample];
                dst[0] = src[0];
                dst[1] = src[1];
                dst[2] = src[2];
            }
        }
    }
    else if(m_stream_info.bits_per_sample == 8){
        for(sample = 0, wide_sample = 0; wide_sample < direct_copy_samples; wide_sample++){
            for(channel = 0; channel < channels; channel++, sample++){
		    	m_direct_buf[sample] = (FLAC__int8)buffer[channel][wide_sample] + 128;
            }
        }
        for(sample = 0; wide_sample < wide_samples; wide_sample++){
            for(channel = 0; channel < channels; channel++, sample++){
		    	m_temp_buf[sample] = (FLAC__int8)buffer[channel][wide_sample] + 128;
            }
        }
    }
    m_direct_buf_copied = direct_copy_samples * m_block_align;
    m_temp_buf_remain = m_temp_buf_size = sample * m_block_align / channels;
    return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
}
/////////////////////////////////////////////////////////////////////////////
void KbFlacDecoder::error_callback(const FLAC__StreamDecoder *decoder, 
                                    FLAC__StreamDecoderErrorStatus status)
{

}
/////////////////////////////////////////////////////////////////////////////
FLAC__StreamDecoderReadStatus KbFlacDecoder::read_callback(const FLAC__StreamDecoder *decoder, 
                                                           FLAC__byte buffer[], 
                                                           size_t *bytes, 
                                                           void *client_data)
{
	IKpiFile *pFile = ((KbFlacDecoder*)client_data)->m_pFile;
    if(*bytes > 0) {
        DWORD dwRead = pFile->Read(buffer, *bytes);
        if(dwRead != *bytes){
		  	*bytes = dwRead;
            return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM;
    	}
	    else {
		 	*bytes = dwRead;
            return dwRead ? FLAC__STREAM_DECODER_READ_STATUS_CONTINUE : FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM;
	    }
	}
    else{
        return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM;
    }
}
/////////////////////////////////////////////////////////////////////////////
FLAC__StreamDecoderSeekStatus KbFlacDecoder::seek_callback(const FLAC__StreamDecoder *decoder, 
                                                           FLAC__uint64 absolute_byte_offset, 
                                                           void *client_data)
{
	IKpiFile *pFile = ((KbFlacDecoder*)client_data)->m_pFile;
    if(pFile->Seek(absolute_byte_offset, FILE_BEGIN) == KPI_FILE_EOF){
        return FLAC__STREAM_DECODER_SEEK_STATUS_ERROR;
    }
    return FLAC__STREAM_DECODER_SEEK_STATUS_OK;
}
/////////////////////////////////////////////////////////////////////////////
FLAC__StreamDecoderTellStatus KbFlacDecoder::tell_callback(const FLAC__StreamDecoder *decoder, 
                                                     FLAC__uint64 *absolute_byte_offset, 
                                                     void *client_data)
{
	IKpiFile *pFile = ((KbFlacDecoder*)client_data)->m_pFile;
    if((*absolute_byte_offset = pFile->Seek(0, FILE_CURRENT)) == KPI_FILE_EOF){
        return FLAC__STREAM_DECODER_TELL_STATUS_ERROR;
    }
    return FLAC__STREAM_DECODER_TELL_STATUS_OK;
}
/////////////////////////////////////////////////////////////////////////////
FLAC__StreamDecoderLengthStatus KbFlacDecoder::length_callback(const FLAC__StreamDecoder *decoder, 
                                                         FLAC__uint64 *stream_length, 
                                                         void *client_data)
{
	IKpiFile *pFile = ((KbFlacDecoder*)client_data)->m_pFile;
    if((*stream_length = pFile->GetSize()) == KPI_FILE_EOF){
        return FLAC__STREAM_DECODER_LENGTH_STATUS_ERROR;
    }
    return FLAC__STREAM_DECODER_LENGTH_STATUS_OK;
}
/////////////////////////////////////////////////////////////////////////////
FLAC__bool KbFlacDecoder::eof_callback(const FLAC__StreamDecoder *decoder, void *client_data)
{
	IKpiFile *pFile = ((KbFlacDecoder*)client_data)->m_pFile;
    UINT64 qwPos = pFile->Seek(0, FILE_CURRENT);
    if(qwPos == KPI_FILE_EOF){
        return TRUE;
    }
    if(pFile->GetSize() == qwPos){
        return TRUE;
    }
    return FALSE;
}
/////////////////////////////////////////////////////////////////////////////
