///|
/// エンティティリストの開始位置を探索する
fn find_entity_list_offset(data~ : Bytes, version~ : UInt) -> Int? {
  let schema_low = (version & 0xFFU).reinterpret_as_int()
  let schema_high = ((version >> 8) & 0xFFU).reinterpret_as_int()
  let search_start = 100
  let search_end = data.length() - 20
  let mut i = search_start
  while i < search_end {
    // 0xFF 0xFF (新しいクラス定義マーカー) を検索
    let b0 = data[i].to_int()
    let b1 = data[i + 1].to_int()
    if b0 == 0xFF && b1 == 0xFF {
      // スキーマバージョンが一致するか確認
      let s0 = data[i + 2].to_int()
      let s1 = data[i + 3].to_int()
      if s0 == schema_low && s1 == schema_high {
        // クラス名長さを取得
        let name_len = data[i + 4].to_int() | (data[i + 5].to_int() << 8)
        if name_len >= 8 && name_len <= 20 && i + 6 + name_len <= data.length() {
          // "CData"で始まるかチェック
          let c0 = data[i + 6].to_int()
          let c1 = data[i + 7].to_int()
          let c2 = data[i + 8].to_int()
          let c3 = data[i + 9].to_int()
          let c4 = data[i + 10].to_int()
          if c0 == 'C'.to_int() &&
            c1 == 'D'.to_int() &&
            c2 == 'a'.to_int() &&
            c3 == 't'.to_int() &&
            c4 == 'a'.to_int() {
            // 最初のエンティティクラス定義が見つかった
            // カウントWORDは2バイト前
            return Some(i - 2)
          }
        }
      }
    }
    i += 1
  }
  None
}

///|
/// エンティティリストパース結果
priv struct EntityListResult {
  entities : Array[Entity]
  bytes_consumed : Int
}

///|
/// エンティティリストをパースする
fn parse_entity_list(
  data~ : Bytes,
  offset~ : Int,
  version~ : UInt,
) -> EntityListResult {
  let entity_data = Bytes::from_array(data.to_array()[offset:data.length()])
  let reader = Reader::new(data=entity_data)
  let start_pos = reader.position()
  let count = reader.read_word().to_int()
  let entities = Array::new()

  // MFC CArchive PIDトラッキング
  // PIDはUInt16で最大65536まで可能なため、十分なサイズの配列を確保
  let mut pid_to_class = Array::new()
  for _ in 0..<65536 {
    pid_to_class.push("")
  }
  let mut next_pid : UInt = 1U
  for _ in 0.. {
        entities.push(ent)
        pid_to_class = p2c
        next_pid = npid
      }
      { entity: None, pid_to_class: p2c, next_pid: npid } => {
        pid_to_class = p2c
        next_pid = npid
      }
    }
  }
  let end_pos = reader.position()
  { entities, bytes_consumed: end_pos - start_pos }
}

///|
/// PIDトラッキング結果
priv struct PidTrackingResult {
  entity : Entity?
  pid_to_class : Array[String]
  next_pid : UInt
}

///|
/// PIDトラッキング付きでエンティティをパースする
fn parse_entity_with_pid_tracking(
  reader~ : Reader,
  version~ : UInt,
  pid_to_class~ : Array[String],
  next_pid~ : UInt,
) -> PidTrackingResult {
  let class_id = reader.read_word().to_int()
  let mut class_name = ""
  let updated_p2c = pid_to_class
  let mut updated_next_pid = next_pid
  if class_id == 0xFFFF {
    // 新しいクラス定義 - クラス情報を読み取ってエンティティパースに進む
    let _schema = reader.read_word()
    let name_len = reader.read_word().to_int()
    let name_bytes = reader.read_bytes(n=name_len)

    // バイト列をASCII文字列として解釈
    let mut name_chars = ""
    for i in 0.. Entity? {
  if class_name == "CDataSen" {
    let base = parse_entity_base(reader~, version~)
    let start_x = reader.read_double()
    let start_y = reader.read_double()
    let end_x = reader.read_double()
    let end_y = reader.read_double()
    Some(Entity::Line({ base, start_x, start_y, end_x, end_y }))
  } else if class_name == "CDataEnko" {
    let base = parse_entity_base(reader~, version~)
    let center_x = reader.read_double()
    let center_y = reader.read_double()
    let radius = reader.read_double()
    let start_angle = reader.read_double()
    let arc_angle = reader.read_double()
    let tilt_angle = reader.read_double()
    let flatness = reader.read_double()
    let full_circle = reader.read_dword()
    Some(
      Entity::Arc({
        base,
        center_x,
        center_y,
        radius,
        start_angle,
        arc_angle,
        tilt_angle,
        flatness,
        is_full_circle: full_circle != 0,
      }),
    )
  } else if class_name == "CDataTen" {
    let base = parse_entity_base(reader~, version~)
    let x = reader.read_double()
    let y = reader.read_double()
    let tmp = reader.read_dword()
    let is_temporary = tmp != 0
    let mut code = 0U
    let mut angle = 0.0
    let mut scale = 1.0
    if base.pen_style == 100 {
      code = reader.read_dword()
      angle = reader.read_double()
      scale = reader.read_double()
    }
    Some(Entity::Point({ base, x, y, is_temporary, code, angle, scale }))
  } else if class_name == "CDataMoji" {
    let base = parse_entity_base(reader~, version~)
    let start_x = reader.read_double()
    let start_y = reader.read_double()
    let end_x = reader.read_double()
    let end_y = reader.read_double()
    let text_type = reader.read_dword()
    let size_x = reader.read_double()
    let size_y = reader.read_double()
    let spacing = reader.read_double()
    let angle = reader.read_double()
    let font_name = read_cstring(reader~)
    let content = read_cstring(reader~)
    // メタデータ設定はエンティティとして追加しない
    if is_metadata_text(content~) {
      None
      // ^@BMを含む場合は画像エンティティとして処理
    } else if find_bm_marker(content~) is Some(_) {
      match
        parse_image_from_bm_string(
          content~,
          base~,
          start_x~,
          start_y~,
          angle~,
          size_x~,
          size_y~,
        ) {
        Some(image) => Some(Entity::Image(image))
        None =>
          Some(
            Entity::Text({
              base,
              start_x,
              start_y,
              end_x,
              end_y,
              text_type,
              size_x,
              size_y,
              spacing,
              angle,
              font_name,
              content,
            }),
          )
      }
    } else {
      Some(
        Entity::Text({
          base,
          start_x,
          start_y,
          end_x,
          end_y,
          text_type,
          size_x,
          size_y,
          spacing,
          angle,
          font_name,
          content,
        }),
      )
    }
  } else if class_name == "CDataSolid" {
    let base = parse_entity_base(reader~, version~)
    let point1_x = reader.read_double()
    let point1_y = reader.read_double()
    let point4_x = reader.read_double()
    let point4_y = reader.read_double()
    let point2_x = reader.read_double()
    let point2_y = reader.read_double()
    let point3_x = reader.read_double()
    let point3_y = reader.read_double()
    let mut color = 0U
    if base.pen_color == 10 {
      color = reader.read_dword()
    }
    if base.pen_style.to_int() >= 101 {
      Some(
        Entity::ArcSolid({
          base,
          center_x: point1_x,
          center_y: point1_y,
          radius: point4_x,
          flatness: point4_y,
          tilt_angle: point2_x,
          start_angle: point2_y,
          arc_angle: point3_x,
          solid_param: point3_y,
          color,
        }),
      )
    } else {
      Some(
        Entity::Solid({
          base,
          point1_x,
          point1_y,
          point2_x,
          point2_y,
          point3_x,
          point3_y,
          point4_x,
          point4_y,
          color,
        }),
      )
    }
  } else if class_name == "CDataBlock" {
    let base = parse_entity_base(reader~, version~)
    let ref_x = reader.read_double()
    let ref_y = reader.read_double()
    let scale_x = reader.read_double()
    let scale_y = reader.read_double()
    let rotation = reader.read_double()
    let def_number = reader.read_dword()
    Some(
      Entity::Block({
        base,
        ref_x,
        ref_y,
        scale_x,
        scale_y,
        rotation,
        def_number,
      }),
    )
  } else if class_name == "CDataSunpou" {
    // 寸法エンティティ - 線メンバーを返す
    let _base = parse_entity_base(reader~, version~)
    // 線メンバーをパースして返す(Go版の実装に倣う)
    let line_base = parse_entity_base(reader~, version~)
    let start_x = reader.read_double()
    let start_y = reader.read_double()
    let end_x = reader.read_double()
    let end_y = reader.read_double()
    // 文字メンバーをパース(スキップ)
    let _text_base = parse_entity_base(reader~, version~)
    let _text_start_x = reader.read_double()
    let _text_start_y = reader.read_double()
    let _text_end_x = reader.read_double()
    let _text_end_y = reader.read_double()
    let _text_type = reader.read_dword()
    let _text_size_x = reader.read_double()
    let _text_size_y = reader.read_double()
    let _text_spacing = reader.read_double()
    let _text_angle = reader.read_double()
    let _text_font_name = read_cstring(reader~)
    let _text_content = read_cstring(reader~)

    // Ver 4.20+ の追加データ
    if version >= 420 {
      let _sxf_mode = reader.read_word()
      for _ in 0..<2 {
        let _ = parse_entity_base(reader~, version~)
        let _ = reader.read_double()
        let _ = reader.read_double()
        let _ = reader.read_double()
        let _ = reader.read_double()

      }
      for _ in 0..<4 {
        let _ = parse_entity_base(reader~, version~)
        let _ = reader.read_double()
        let _ = reader.read_double()
        let _ = reader.read_dword()

      }
    }
    // 寸法エンティティは線として返す(Go版の実装に倣う)
    Some(Entity::Line({ base: line_base, start_x, start_y, end_x, end_y }))
  } else {
    // 不明なクラス
    None
  }
}

///|
/// エンティティ基本属性をパースする
fn parse_entity_base(reader~ : Reader, version~ : UInt) -> EntityBase {
  let group = reader.read_dword()
  let pen_style = reader.read_byte()
  let pen_color = reader.read_word()
  let pen_width = if version >= 351 { reader.read_word() } else { 0 }
  let layer = reader.read_word()
  let layer_group = reader.read_word()
  let flag = reader.read_word()
  { group, pen_style, pen_color, pen_width, layer, layer_group, flag }
}