/// ****************************************************************************
/// @file   
/// @author Dr.Neeton
/// @date   2008/X/X - 2014/01/24
/// 
/// @brief  CSC(Core Sound Codec)関連。
/// 
/// ****************************************************************************

#pragma once

#include "CPL_Core_CSC_Encoder.h"
#include "CPL_Core_CSC_Decoder.h"

namespace CPL {
namespace Core {



// _____________________________________________________________________________
/// @brief CSC基底クラス
///
// *****************************************************************************
class baseCscData {
  friend class CscMemoryStream;
  friend class CscFileStream;
public:
  enum COMPRESS_TYPE {
    CT_SIMPLE,
    CT_SUB1,
  };

#if (CPL_CSC_VERSION == 1)
protected:

  void zzf_setWaveInfo(
         const BaseWaveData&  in_wave_buf,
         int                  in_max_bit );
  void zzf_setValue(
         MemoryStreamCell& out_csc_buf,
         int               in_index,
         int               in_channel,
         int               in_value );
  int  zzf_getValue(
         const MemoryStreamCell& in_csc_buf,
         int                     in_index,
         int                     in_channel );
  void zzf_getKeyList(
         Array::Dynamic<short>&  in_buf,
         Array::Dynamic<int>*    out_ptr_key_list,
         int                     in_index0,
         int                     in_index1,
         float                   in_allowed_value,
         bool                    in_align_check );
  void zzf_minCut( Array::Dynamic<short>& io_org_buf, float in_zero_limit );
  int  zzf_enc_getCompressBlockBuffer(
         short_cptr    in_org_buf,
         U8            out_ptr_buf[ CSC_BLOCK_SIZE*2 ],
         int           in_sample_num,
         COMPRESS_TYPE in_type );


  CscHeaderInfo m_csc_info;
public:
  CscHeaderInfo const&  GetHeader() const { return m_csc_info; }

  virtual bool  Encode( const BaseWaveData& in_wave_data, int in_max_bit, float in_zero_limit );
  virtual bool  Decode( BaseWaveData& out_wave_data ) const;
  virtual int   Decode( CscBlockInfo const* in_ptr_block_table,
                        void* out_ptr_buf,
                        int   in_sample_idx,
                        int   in_sample_num,
                        int   in_flag_loop,
                        int*  out_ptr_next_idx ) const;


#elif (CPL_CSC_VERSION == 2)
protected:
  void        zzf_setWaveInfo2( BaseWaveData const& in_wave_buf );
  int         zzf_encode2_Block(
                CscEncodeInfo&  io_enc_info,
                CscBlockInfo2&  io_block_info,
                short_cptr      in_org_buf,
                int             in_block_idx,
                U8              out_ptr_buf[ CSC_BLOCK_SIZE*4 ] );

  CscHeaderInfo2  m_csc_info2;

public:
  CscHeaderInfo2 const& GetHeader2() const { return m_csc_info2; }

  virtual bool  Encode2( CscEncodeInfo& io_enc_info );
  virtual int   Decode2( BaseWaveData& out_wave_data ) const;
  size_t        Decode2_Range(
                  CscBlockInfo2 const*  in_block_offs_table,
                  void*                 out_ptr_buf,
                  int                   in_sample_idx,
                  int                   in_sample_num,
                  int                   in_flag_loop,
                  int*                  out_ptr_next_idx ) const;

#endif


protected:
  using Stream_i_sptr = Core::Stream_i_::shared_ptr;

  Core::StringA m_mask;

  baseCscData( Core::StringA const& mask ) : m_mask(mask) {}
  baseCscData( baseCscData const& dd ) {}

public:
  Core::StringA         GetMask()   const { return m_mask; }

  virtual Stream_i_sptr GetDataStream() const = 0;
  virtual void          SetupDataBuffer() = 0;
  virtual ~baseCscData(){}
};


// _____________________________________________________________________________
/// @brief CSCメモリストリーム
///
// *****************************************************************************
class CscMemoryStream
  : public baseCscData
  , public Core::MemoryStream
{
  friend class CscMemoryStream;
protected:
  Core::MemoryStreamCell::shared_ptr m_sp_data_stm;
  
public:
  Stream_i_sptr GetDataStream() const { return m_sp_data_stm; }
  void          SetupDataBuffer();

  void operator = ( CscMemoryStream const& db )
  {
    m_csc_info2 = db.m_csc_info2;
    static_cast<Core::MemoryStream&>(*this) = db;
  }

  CscMemoryStream( Core::StringA const& in_mask ) : baseCscData( in_mask ) {}
  CscMemoryStream( str_cptr in_path, Core::StringA const& in_mask );
  CscMemoryStream( const CscMemoryStream& db );
  ~CscMemoryStream(){}
};


// _____________________________________________________________________________
/// @brief CSCファイルストリーム
///
// *****************************************************************************
class CscFileStream
  : public baseCscData
  , public Core::FileStream
{
  friend class CscFileStream;
protected:
  sdptr<Core::FileStreamCell> m_ptr_data_stream;
  
public:
  Stream_i_sptr GetDataStream() const { return m_ptr_data_stream; }
  void          SetupDataBuffer();

  void operator = ( const CscFileStream& in_csc_stream )
  {
    m_csc_info2 = in_csc_stream.m_csc_info2;
    static_cast<Core::FileStream&>(*this) = in_csc_stream;
  }

  CscFileStream( _in<Core::StringA> in_mask ) : baseCscData( in_mask ) {}
  CscFileStream( str_cptr in_path, bool in_flag_read, _in<Core::StringA> in_mask );
  CscFileStream( cref<CscFileStream> in_csc_stream );
  ~CscFileStream() {}
};



} // namespace Core
} // namespace CPL
