#ifndef _mpp_dec_h_
#define _mpp_dec_h_

#ifdef WIN32
#define MPC_LITTLE_ENDIAN
#endif

#include <assert.h>
#include "config_types.h"
#include "mpc_math.h"

class MPC_reader {
public:
	virtual mpc_int32_t read ( void *ptr, mpc_int32_t size ) = 0;
	virtual bool seek ( mpc_int32_t offset ) = 0;
	virtual mpc_int32_t tell () = 0;
	virtual mpc_int32_t get_size () = 0;
	virtual bool canseek() = 0;
};

class MPC_decoder {
public:
	MPC_decoder(MPC_reader *r, double scale_factor = 1.0);
	~MPC_decoder();

	bool Initialize(const class StreamInfo *si);
	void ScaleOutput(double factor);
	mpc_uint32_t Decode(MPC_SAMPLE_FORMAT *buffer, mpc_uint32_t * vbr_update_acc = 0, mpc_uint32_t * vbr_update_bits = 0);
	bool SeekSeconds(double seconds);
	bool SeekSample(mpc_int64_t sample);

public:
	enum
	{
		FrameLength = (36 * 32),               // samples per frame
		SynthDelay = 481,
		DecodeBufferLength = 4 * FrameLength,
	};
private:
	enum
	{
		EQ_TAP = 13,                      // length of FIR filter for EQ
		DELAY = ((EQ_TAP + 1) / 2),      // delay of FIR
		FIR_BANDS = 4,                       // number of subbands to be FIR filtered
		MEMSIZE = 16384,                   // overall buffer size
		MEMSIZE2 = (MEMSIZE/2),             // size of one buffer
		MEMMASK = (MEMSIZE-1),
		V_MEM = 2304,
	};
	void SetStreamInfo ( const class StreamInfo *si );
	void UpdateBuffer ( mpc_uint32_t RING );
	void RESET_Synthesis ( void );
	void RESET_Globals ( void );

	mpc_uint32_t BitsRead ( void );
	mpc_uint32_t decode_internal ( MPC_SAMPLE_FORMAT *buffer );
	void RESET_Y ( void );
	void Lese_Bitstrom_SV6 ( void );
	void Lese_Bitstrom_SV7 ( void );

	void Requantisierung ( const mpc_int32_t Last_Band );

	mpc_uint32_t samples_to_skip;

	typedef struct {
	    mpc_int32_t  L [36];
	    mpc_int32_t  R [36];
	} QuantTyp;

	typedef struct {
	    mpc_uint32_t  Code;
		mpc_uint32_t  Length;
		mpc_int32_t           Value;
	} HuffmanTyp;

	static int HuffmanTyp_cmpfn ( const void* p1, const void* p2 );

	MPC_reader *m_reader;

  mpc_uint32_t Speicher [MEMSIZE];         // read-buffer
  mpc_uint32_t dword;                      // actually decoded 32bit-word
  mpc_uint32_t  pos;                        // bit-position within dword
  mpc_uint32_t  Zaehler;                    // actual index within read-buffer

  mpc_uint32_t  FwdJumpInfo;
  mpc_uint32_t  ActDecodePos;
  mpc_uint32_t  FrameWasValid;

  mpc_uint32_t  DecodedFrames;
  mpc_uint32_t  OverallFrames;
  mpc_int32_t           SampleRate;                 // Sample frequency

  mpc_uint32_t  StreamVersion;              // version of bitstream
  mpc_uint32_t  MS_used;                    // MS-coding used ?
  mpc_int32_t           Max_Band;
  mpc_uint32_t  MPCHeaderPos;               // AB: needed to support ID3v2
  //mpc_uint32_t  OverallFrames;
  //mpc_uint32_t  DecodedFrames;
  mpc_uint32_t  LastValidSamples;
  mpc_uint32_t  TrueGaplessPresent;

  mpc_uint32_t  EQ_activated;

  mpc_uint32_t  WordsRead;                  // counts amount of decoded dwords

  /*static*/ mpc_uint32_t  __r1;
  /*static*/ mpc_uint32_t  __r2;


  mpc_int32_t           SCF_Index_L [32] [3];
  mpc_int32_t           SCF_Index_R [32] [3];       // holds scalefactor-indices
  QuantTyp      Q [32];                     // holds quantized samples
  mpc_int32_t           Res_L [32];
  mpc_int32_t           Res_R [32];                 // holds the chosen quantizer for each subband
  mpc_int32_t           DSCF_Flag_L [32];
  mpc_int32_t           DSCF_Flag_R [32];           // differential SCF used?
  mpc_int32_t           SCFI_L [32];
  mpc_int32_t           SCFI_R [32];                // describes order of transmitted SCF
  mpc_int32_t           DSCF_Reference_L [32];
  mpc_int32_t           DSCF_Reference_R [32];      // holds last frames SCF
  mpc_int32_t           MS_Flag[32];                // MS used?


  HuffmanTyp    HuffHdr  [10];
  HuffmanTyp    HuffSCFI [ 4];
  HuffmanTyp    HuffDSCF [16];
  HuffmanTyp*   HuffQ [2] [8];

  HuffmanTyp    HuffQ1 [2] [3*3*3];
  HuffmanTyp    HuffQ2 [2] [5*5];
  HuffmanTyp    HuffQ3 [2] [ 7];
  HuffmanTyp    HuffQ4 [2] [ 9];
  HuffmanTyp    HuffQ5 [2] [15];
  HuffmanTyp    HuffQ6 [2] [31];
  HuffmanTyp    HuffQ7 [2] [63];

  const HuffmanTyp* SampleHuff [18];
  HuffmanTyp    SCFI_Bundle   [ 8];
  HuffmanTyp    DSCF_Entropie [13];
  HuffmanTyp    Region_A [16];
  HuffmanTyp    Region_B [ 8];
  HuffmanTyp    Region_C [ 4];

  HuffmanTyp    Entropie_1 [ 3];
  HuffmanTyp    Entropie_2 [ 5];
  HuffmanTyp    Entropie_3 [ 7];
  HuffmanTyp    Entropie_4 [ 9];
  HuffmanTyp    Entropie_5 [15];
  HuffmanTyp    Entropie_6 [31];
  HuffmanTyp    Entropie_7 [63];

  MPC_SAMPLE_FORMAT V_L [V_MEM + 960];
  MPC_SAMPLE_FORMAT V_R [V_MEM + 960];
  MPC_SAMPLE_FORMAT Y_L [36] [32];
  MPC_SAMPLE_FORMAT Y_R [36] [32];

  MPC_SAMPLE_FORMAT SCF [256];                 // holds adapted scalefactors (for clipping prevention)
#ifdef MPC_FIXED_POINT
  unsigned char SCF_shift[256];
#endif
  mpc_uint32_t  Q_bit [32];                 // holds amount of bits to save chosen quantizer (SV6)
  mpc_uint32_t  Q_res [32] [16];            // holds conversion: index -> quantizer (SV6)

private: // functions
	void Reset_BitstreamDecode ( void );
	mpc_uint32_t Bitstream_read ( const mpc_uint32_t );
	mpc_int32_t Huffman_Decode ( const HuffmanTyp* );         // works with maximum lengths up to 14
	mpc_int32_t Huffman_Decode_fast ( const HuffmanTyp* );    // works with maximum lengths up to 10
	mpc_int32_t Huffman_Decode_faster ( const HuffmanTyp* );  // works with maximum lengths up to  5
	void SCFI_Bundle_read ( const HuffmanTyp*, mpc_int32_t*, mpc_int32_t* );

	void Reset_V ( void );
	void Synthese_Filter_float ( MPC_SAMPLE_FORMAT * dst );
	mpc_uint32_t random_int ( void );
	
	void EQSet ( mpc_int32_t on, char data[10], mpc_int32_t preamp );
	void Helper1 ( mpc_uint32_t bitpos );
	void Helper2 ( mpc_uint32_t bitpos );
	void Helper3 ( mpc_uint32_t bitpos, mpc_uint32_t* buffoffs );
	void Huffman_SV6_Encoder ( void );
	void Huffman_SV6_Decoder ( void );
	void Huffman_SV7_Encoder ( void );
	void Huffman_SV7_Decoder ( void );

	void initialisiere_Quantisierungstabellen ( double );
	void Quantisierungsmodes ( void );        // conversion: index -> quantizer (bitstream reading)
	void Resort_HuffTables ( const mpc_uint32_t elements, HuffmanTyp* Table, const mpc_int32_t offset );
private:
	inline mpc_int32_t f_read ( void *ptr, size_t size) { return m_reader->read (ptr, size); };
	mpc_int32_t f_read_dword( mpc_uint32_t * ptr, mpc_uint32_t count);
	inline bool f_seek ( mpc_int32_t offset) { return m_reader->seek(offset); };
};

#include "streaminfo.h"

#endif
