#pragma once

#include "AudioHardwareSA.h"

class CAEFLACDecoder final : public CAEStreamingDecoder
{
private:
	FLAC__StreamDecoder*		m_FLACdecoder = nullptr;
	FLAC__StreamMetadata*		m_streamMeta = nullptr;
	FLAC__uint64				m_currentSample;
	FLAC__int32*				m_buffer = nullptr;
	size_t						m_curBlockSize, m_maxBlockSize = 0;
	size_t						m_bufferCursor;
	bool						m_eof;

private:
	static FLAC__StreamDecoderReadStatus	read_cb(const FLAC__StreamDecoder* decoder, FLAC__byte buffer[], size_t* bytes, void* client_data);
	static FLAC__StreamDecoderWriteStatus	write_cb(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 *const buffer[], void *client_data);
	static void								meta_cb(const FLAC__StreamDecoder* decoder, const FLAC__StreamMetadata *metadata, void *client_data);
	static void								error_cb(const FLAC__StreamDecoder* decoder, FLAC__StreamDecoderErrorStatus status, void* client_data);
	static FLAC__StreamDecoderSeekStatus	seek_cb(const FLAC__StreamDecoder *decoder, FLAC__uint64 absolute_byte_offset, void *client_data);
	static FLAC__StreamDecoderTellStatus	tell_cb(const FLAC__StreamDecoder *decoder, FLAC__uint64 *absolute_byte_offset, void *client_data);
	static FLAC__StreamDecoderLengthStatus	length_cb(const FLAC__StreamDecoder *decoder, FLAC__uint64 *stream_length, void *client_data);
	static FLAC__bool						eof_cb(const FLAC__StreamDecoder *decoder, void *client_data);

public:
	CAEFLACDecoder(CAEDataStream* stream)
		: CAEStreamingDecoder(stream)
	{}

	virtual					~CAEFLACDecoder() override;
	virtual bool			Initialise() override;
	virtual uint32_t		FillBuffer(void* pBuf, uint32_t nLen) override;
	virtual uint32_t		GetStreamLengthMs() const override
	{ return uint32_t((m_streamMeta->data.stream_info.total_samples * 1000) / m_streamMeta->data.stream_info.sample_rate); }
	virtual uint32_t		GetStreamPlayTimeMs() const override
	{ return uint32_t((m_currentSample * 1000) / m_streamMeta->data.stream_info.sample_rate); }
	virtual void			SetCursor(uint32_t nTime) override
	{ FLAC__stream_decoder_seek_absolute(m_FLACdecoder, (uint64_t(nTime) * m_streamMeta->data.stream_info.sample_rate) / 1000); }
	virtual uint32_t		GetSampleRate() const override
	{ return m_streamMeta->data.stream_info.sample_rate; }
	virtual uint32_t		GetStreamID() const override
	{ return GetStream()->GetID(); }
};