
#ifndef JDECODER_H
#define JDECODER_H

#include "idct.h"
#include "bstream.h"

namespace JPEG {


// マーカからそれぞれ文字列を得る
const char *getMarkerDescription(unsigned int m);


///////////////////////////////////////////////////////////////////////////////
struct HuffmanTree{
  enum { ERROR_VALUE = 9999 };

  HuffmanTree *next_tree[2];
  int value[2];

  HuffmanTree() {
    next_tree[0] = 0;
    next_tree[1] = 0;
    value[0] = ERROR_VALUE;
    value[1] = ERROR_VALUE;
  }

  ~HuffmanTree() {
    delete next_tree[0];
    delete next_tree[1];
  }
};


///////////////////////////////////////////////////////////////////////////////
class Decoder {
  bool image_started_;
  bool image_end_;
  bool start_of_frame_;
  BitwiseInputStreamReader stream_;

  enum {
    JUST_A_0xFF = 0xFF00,
    START_OF_FRAME_MIN = 0xFFC0,
    START_OF_FRAME_0 = 0xFFC0,
    START_OF_FRAME_MAX = 0xFFC3,
    DEFINE_HUFFMAN_TABLE =0xFFC4,
    START_OF_IMAGE = 0xFFD8,
    END_OF_IMAGE = 0xFFD9,
    START_OF_SCAN = 0xFFDA,
    DEFINE_QUANTIZATION_TABLE = 0xFFDB,
    APPLICATION_MIN = 0xFFE0,
    APPLICATION_0 = 0xFFE0,
    APPLICATION_MAX = 0xFFEF,
  };

  // APP0
  char app0_identifier_[5];  // "JFIF\0" 固定のはず
    // app0_identifier == "JFIF\0" の場合
    int  major_revision_;
    int  minor_revision_;
    int  density_unit_;
    int  horiz_density_;
    int  verti_density_;
    int  thumb_width_;
    int  thumb_height_;
    // サムネイル画像は略

  // SOF0
  int depth_per_component_;
  int height_;
  int width_;
  int component_count_;   // 1 or 3
  int component_id_[3];
  int sampling_factor_[3];
  int horizontal_sampling_factor_[3];
  int vertical_sampling_factor_[3];
  int qt_selector_[3];
    // SOF0 取得後，便宜的に計算しておくとよいもの
    int depth_;
    int bytes_per_pixel_;
    int bytes_per_line_;
    int coded_width_;
    int coded_height_;
    int horizontal_sampling_factor_max_; //! サンプリングファクタのの横方向の最大値
    int vertical_sampling_factor_max_;   //! サンプリングファクタのの縦方向の最大値
    int MCU_coded_width_;  // MCU の幅
    int MCU_coded_height_; // MCU の高さ
    unsigned char *decoded_image_;
    short *coeff_workarea_[3];

  // DQT
  short quant_tables_[3][64];

  // DHT
  HuffmanTree huffman_trees_[2][3];

  // SOS
  int huffman_table_for_dc_[4]; // Y, Cr, Cb 別
  int huffman_table_for_ac_[4];


  // その他
  int getting_line_;
  int dc_pred_[3];
  bool skip_next_0x00_;



  unsigned long get_marker();
  void require_segments();

  void segment_startOfImage();
  void segment_application0();
  void segment_defineQuantizationTable();
  void segment_startOfFrame0();
  void segment_defineHuffmanTable();
  void segment_startOfScan();
  void segment_unknown();

  void decode_MCU_line();
  m_ui32 read_bits_scan(unsigned int bits);
  m_ui32 decode_huffman_tree( HuffmanTree *);
  void decode_block(short *, int );
  void dequantize( short *, int);
  void block_to_image(int);

public:
  Decoder( InputStream *stream );

  virtual ~Decoder(){
    delete decoded_image_;
    for (int c=0; c<3; ++c)
      delete coeff_workarea_[c];
  }

  int getWidth();   //! 画像の横幅
  int getHeight();  //! 画像の高さ
  int getDepth();   //! 画像の画素深度 ( ビット単位 )

  int getBPL();     //! 1 ラインのバイト数 
                    // DIB の様式 (4バイトアライン) であるとは限らず，
                    // getLine の引数に必要なバッファサイズを表す

  int getLine(void *);

};

}; // namespace JPEG

#endif JDECODER_H


