///////////////////////////////////////////////////////////////////////////////
//
//       セグメントを解析する


#include "jdecoder.h"
#include <stdio.h>
#include <string.h>

//=============================================================================
// StartOfImage セグメント
unsigned int segment_startOfImage( JPEGDecoder *jd, InputStream *is ) {
  // 中身はからっぽ
  return JDEC_NOERROR;
}


//=============================================================================
// Application 0 = application 0 セグメント
unsigned int segment_application0( JPEGDecoder *jd, InputStream *is ) {
  int i;

  // 2 バイト .. セグメント長
  unsigned short len = is->read16(is);

  // 5 バイト .. 識別子がある..はず
  for (i=0; i<5; ++i)
    jd->app0_identifier[i] = (char)is->read8(is);

  // "JFIF" ?
  if ( !strcmp(jd->app0_identifier, "JFIF") ) {

    // 1 バイト .. メジャーバージョン番号
    jd->major_revision = is->read8(is);
    // 1 バイト .. マイナーバージョン番号
    jd->minor_revision = is->read8(is);

    // 1 バイト .. 密度単位
    jd->density_unit = is->read8(is);

    // 2 バイト .. 横密度
    jd->horiz_density = is->read16(is);
    // 2 バイト .. 縦密度
    jd->verti_density = is->read16(is);

    // 1 バイト .. サムネイル横幅
    jd->thumb_width = is->read8(is);
    // 1 バイト .. サムネイル高さ
    jd->thumb_height = is->read8(is);

    // 残り (len - 16) バイトはサムネイル画像
    len -= 16;
    while (len > 0) {
      len--;
      is->read8(is);
    }
  } else if ( !strcmp(jd->app0_identifier, "JFXX") ) {
    // unsupported
  }

  return JDEC_NOERROR;
}



//=============================================================================
//  Define Quantization Table  量子化テーブル定義
unsigned int segment_defineQuantizationTable( JPEGDecoder *jd, InputStream *is ) {

  unsigned int precision, number, i;
  // 2 バイト .. セグメント長
  unsigned int len = is->read16(is);

  // テーブル(65バイト)が記述されている回数
  int count = (len - 2) / 65;

  while (count-- > 0) {
    precision = is->read8(is); // とりあえず 1 バイト取り出し
    number = precision & 15;   //   下位 4 ビット .. 量子化テーブル識別子
    precision >>= 4;           //   上位 4 ビット .. 精度

    for (i=0; i<64; ++i) {
      jd->quant_tables[number][i] = is->read8(is);
    }

  }

  return JDEC_NOERROR;
}

//=============================================================================
//  Start Of Frame 0

static void make_extradata_SOF0( JPEGDecoder * jd );

unsigned int segment_startOfFrame0 ( JPEGDecoder *jd, InputStream *is ) {

  int i;
  unsigned int sampling_factor;

  // 2 バイト .. セグメント長
  unsigned int len = is->read16(is);

  // 1 バイト .. 画素深度 ( '8' 固定 )
  jd->depth = is->read8(is);

  // 2 バイト .. 高さ
  jd->height = is->read16(is);

  // 2 バイト .. 横幅
  jd->width = is->read16(is);

  // 1 バイト .. 画像成分数
  jd->component_count = is->read8(is);

  for (i=0; i<jd->component_count; ++i) {
    // 1 バイト .. 成分識別子
    jd->component_id[i] = is->read8(is);

    // 1 バイト .. サンプリングファクタ
    sampling_factor = is->read8(is);
      // そのうち上位 4 ビット .. 水平サンプリングファクタ
      jd->horizontal_sampling_factor[i] = (int)sampling_factor >> 4;
      // 下位 4 ビット .. 垂直サンプリングファクタ
      jd->vertical_sampling_factor[i] = (int)sampling_factor & 15;

    // 1 バイト.. 量子化テーブルセレクタ
    jd->qt_selector[i] = is->read8(is);
  }

  // 後の利便性のために，あらかじめ色々計算しておくとよい
  make_extradata_SOF0(jd);

  return JDEC_NOERROR;

}

static void make_extradata_SOF0( JPEGDecoder *jd ) {

  int i;
  int hsf_min = 99, hsf_max = 0;
  int vsf_min = 99, vsf_max = 0;
  int horiz_blocks = 0, verti_blocks = 0;

  for (i=0; i<jd->component_count; ++i) {

    // いくつか取得できたサンプリングファクタの中で，最大/最小値を保持
    if ( jd->horizontal_sampling_factor[i] < hsf_min )
      hsf_min = jd->horizontal_sampling_factor[i];
    if ( hsf_max < jd->horizontal_sampling_factor[i])
      hsf_max = jd->horizontal_sampling_factor[i];

    if ( jd->vertical_sampling_factor[i] < vsf_min )
      vsf_min = jd->vertical_sampling_factor[i];
    if ( vsf_max < jd->vertical_sampling_factor[i] )
      vsf_max = jd->vertical_sampling_factor[i];
  }

  jd->total_block_count_a_MCU = 0;
  for (i=0; i<jd->component_count; ++i) {

    jd->inverse_horizontal_sampling_factor[i] =
        hsf_max / jd->horizontal_sampling_factor[i];

    jd->inverse_vertical_sampling_factor[i] =
        vsf_max / jd->vertical_sampling_factor[i];

    jd->horizontal_block_count_a_MCU[i] =
        jd->horizontal_sampling_factor[i] / hsf_min;
    if ( horiz_blocks < jd->horizontal_block_count_a_MCU[i] )
      horiz_blocks = jd->horizontal_block_count_a_MCU[i];

    jd->vertical_block_count_a_MCU[i] =
        jd->vertical_sampling_factor[i] / vsf_min;
    if ( verti_blocks < jd->vertical_block_count_a_MCU[i] )
      verti_blocks = jd->vertical_block_count_a_MCU[i];

    jd->block_count_a_MCU[i] =
        jd->horizontal_block_count_a_MCU[i] *
        jd->vertical_block_count_a_MCU[i];

    jd->total_block_count_a_MCU += jd->block_count_a_MCU[i];
  }

  jd->MCU_width = horiz_blocks * 8;
  jd->MCU_height = verti_blocks * 8;

  return;
}


//=============================================================================
//   Define Huffman Table
static
void print_bits( unsigned int code, unsigned int bits ) {
  if ( 1 < bits )
    print_bits( code >> 1, bits - 1);
  printf("%c", code & 1 ? '1' : '0');
}

static
void print_component( HuffmanTable *table, int comp ) {
  printf(" %3d (zrl %2d, code %2d): ", comp, comp >> 4, comp & 15 );
  print_bits( table[comp].code, table[comp].bits );
  printf("\n");
}

unsigned int segment_defineHuffmanTable( JPEGDecoder *jd, InputStream *is ) {

  unsigned int class_and_id, table_class, table_id, i, k, lengths[16];
  unsigned int component, code = 0;
  HuffmanTable *table;

  // 2 バイト .. セグメント長
  int len = (int)is->read16(is) - 2;

  while (len > 0) {

    // 1 バイト .. テーブルのクラスと識別子
    class_and_id = is->read8(is);
      table_class = class_and_id >> 4;
      table_id    = class_and_id & 15;

    // どのテーブルに値を記憶させるかを選択
    table = jd->huffman_tables[table_class][table_id];
    // とりあえず初期化する
    for (k=0; k<256; ++k) {
      table[k].code = 0;
      table[k].bits = 0;
    }

    // 1 バイト x 16 回 .. 後ろに格納されているそれぞれの要素の個数
    for (i=0; i<16; ++i)
      lengths[i] = is->read8(is);

    len -= 17;

    for (i=0; i<16; ++i) {

      // 1 バイト x lengths[i] 回 .. 要素
      for (k=0; k<lengths[i]; ++k) {
        component = is->read8(is);
        table[component].code = code++;
        table[component].bits = i+1;
        // print_component( table, component );
      }

      code <<= 1;
      len -= lengths[i];
    }
  }

  return JDEC_NOERROR;
}

//=============================================================================
unsigned int segment_startOfScan( JPEGDecoder *jd, InputStream *is ) {

  int i, component_id;
  unsigned int dc_ac_table, unused;

  // 2 バイト .. セグメント長
  int len = (int)is->read16(is) - 2;

  // 1 バイト .. スキャン内の成分数
  int count = (int)is->read8(is);

  for (i=0; i<count; ++i) {
    // 1 バイト .. スキャン成分セレクタ
    component_id = (int)is->read8(is);

    // とりあえず 1 バイト
    dc_ac_table = is->read8(is);
      // 上位 4 ビット .. DC 成分用ハフマンテーブルセレクタ
      jd->huffman_table_for_dc[i] = dc_ac_table >> 4;
      // 下位 4 ビット .. AC 成分用ハフマンテーブルセレクタ
      jd->huffman_table_for_ac[i] = dc_ac_table & 15;
  }

  // 以下 3 バイトはここでは未使用
  unused = is->read8(is);
  unused = is->read8(is);
  unused = is->read8(is);

  return JDEC_NOERROR;
}


