#pragma once

extern "C" {
#include "flac/include/FLAC/all.h"
}
#include "kpi_decoder.h"
#include "kpi_impl.h"

class KbFlacDecoder : public KbKpiUnknownImpl<IKpiDecoder>
{
private:
    IKpiFile            *m_pFile;
    FLAC__StreamDecoder *m_decoder;
    FLAC__StreamMetadata_StreamInfo m_stream_info;
    int    m_block_align;//=(bitspersample/8) * channels
    BYTE  *m_direct_buf;
    DWORD  m_direct_buf_size;
    DWORD  m_direct_buf_copied;
    BYTE   m_temp_buf[FLAC__MAX_BLOCK_SIZE * 2 * 4];//2=maxchannel, 4=32/8
    DWORD  m_temp_buf_size;
    DWORD  m_temp_buf_remain;
    KPI_MEDIAINFO m_MediaInfo;
    //
    static FLAC__StreamDecoderReadStatus read_callback(const FLAC__StreamDecoder *decoder, 
                                                           FLAC__byte buffer[], 
                                                           size_t *bytes, 
                                                           void *client_data);
    static FLAC__StreamDecoderSeekStatus seek_callback(const FLAC__StreamDecoder *decoder, 
                                                           FLAC__uint64 absolute_byte_offset, 
                                                           void *client_data);
    static FLAC__StreamDecoderTellStatus tell_callback(const FLAC__StreamDecoder *decoder, 
                                                           FLAC__uint64 *absolute_byte_offset, 
                                                           void *client_data);
    static FLAC__StreamDecoderLengthStatus length_callback(const FLAC__StreamDecoder *decoder, 
                                                           FLAC__uint64 *stream_length, 
                                                           void *client_data);
    static FLAC__bool eof_callback(const FLAC__StreamDecoder *decoder, void *client_data);
    //
    static void metadata_callback(const FLAC__StreamDecoder *decoder, 
                                       const FLAC__StreamMetadata *metadata, 
                                       void *client_data);
    static FLAC__StreamDecoderWriteStatus write_callback(const FLAC__StreamDecoder *decoder, 
                                                         const FLAC__Frame *frame, 
                                                         const FLAC__int32 * const buffer[], 
                                                         void *client_data);
    static void error_callback(const FLAC__StreamDecoder *decoder, 
                               FLAC__StreamDecoderErrorStatus status, 
                               void *client_data);
    void metadata_callback(const FLAC__StreamDecoder *decoder, 
                           const FLAC__StreamMetadata *metadata);
    FLAC__StreamDecoderWriteStatus write_callback(const FLAC__StreamDecoder *decoder, 
                                                  const FLAC__Frame *frame, 
                                                  const FLAC__int32 * const buffer[]);
    void error_callback(const FLAC__StreamDecoder *decoder, 
                                    FLAC__StreamDecoderErrorStatus status);
public:
    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;}

    KbFlacDecoder(IKpiFile *pFile, IKpiFolder *pFolder);
    ~KbFlacDecoder(void);
};
