// Copyright 2026 International Digital Economy Academy
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

///|
/// Parsed OS/2 table (subset).
pub struct Os2Table {
  version : Int
  weight_class : Int
  width_class : Int
  fs_type : Int
  typo_ascender : Int
  typo_descender : Int
  typo_line_gap : Int
  win_ascent : Int
  win_descent : Int
  code_page_range_1 : UInt?
  code_page_range_2 : UInt?
  x_height : Int?
  cap_height : Int?
  default_char : Int?
  break_char : Int?
  max_context : Int?
  lower_optical_point_size : Int?
  upper_optical_point_size : Int?
} derive(Show, ToJson)

///|
fn os2_required_len(version : Int) -> Int {
  if version < 0 {
    return 0
  }
  if version >= 5 {
    100
  } else if version >= 2 {
    96
  } else if version >= 1 {
    86
  } else {
    78
  }
}

///|
/// Parse OS/2 table bytes (version 0-5, subset of fields).
pub fn Os2Table::parse(data : BytesView) -> Result[Os2Table, SfntError] {
  let version = read_u16_int(data, 0)
  match version {
    Err(err) => Err(err)
    Ok(version) => {
      let required = os2_required_len(version)
      if data.length() < required {
        return Err(UnexpectedEof)
      }
      let weight_class = read_u16_int(data, 4)
      let width_class = read_u16_int(data, 6)
      let fs_type = read_u16_int(data, 8)
      let typo_ascender = read_i16(data, 68)
      let typo_descender = read_i16(data, 70)
      let typo_line_gap = read_i16(data, 72)
      let win_ascent = read_u16_int(data, 74)
      let win_descent = read_u16_int(data, 76)
      match (
        weight_class,
        width_class,
        fs_type,
        typo_ascender,
        typo_descender,
        typo_line_gap,
        win_ascent,
        win_descent,
      ) {
        (Err(err), _, _, _, _, _, _, _) => Err(err)
        (_, Err(err), _, _, _, _, _, _) => Err(err)
        (_, _, Err(err), _, _, _, _, _) => Err(err)
        (_, _, _, Err(err), _, _, _, _) => Err(err)
        (_, _, _, _, Err(err), _, _, _) => Err(err)
        (_, _, _, _, _, Err(err), _, _) => Err(err)
        (_, _, _, _, _, _, Err(err), _) => Err(err)
        (_, _, _, _, _, _, _, Err(err)) => Err(err)
        (
          Ok(weight_class),
          Ok(width_class),
          Ok(fs_type),
          Ok(typo_ascender),
          Ok(typo_descender),
          Ok(typo_line_gap),
          Ok(win_ascent),
          Ok(win_descent),
        ) => {
          let mut code_page_range_1 : UInt? = None
          let mut code_page_range_2 : UInt? = None
          if version >= 1 {
            let range1 = read_u32(data, 78)
            let range2 = read_u32(data, 82)
            match (range1, range2) {
              (Err(err), _) => return Err(err)
              (_, Err(err)) => return Err(err)
              (Ok(range1), Ok(range2)) => {
                code_page_range_1 = Some(range1)
                code_page_range_2 = Some(range2)
              }
            }
          }
          let mut x_height : Int? = None
          let mut cap_height : Int? = None
          let mut default_char : Int? = None
          let mut break_char : Int? = None
          let mut max_context : Int? = None
          if version >= 2 {
            let x_height_val = read_i16(data, 86)
            let cap_height_val = read_i16(data, 88)
            let default_char_val = read_u16_int(data, 90)
            let break_char_val = read_u16_int(data, 92)
            let max_context_val = read_u16_int(data, 94)
            match (
              x_height_val,
              cap_height_val,
              default_char_val,
              break_char_val,
              max_context_val,
            ) {
              (Err(err), _, _, _, _) => return Err(err)
              (_, Err(err), _, _, _) => return Err(err)
              (_, _, Err(err), _, _) => return Err(err)
              (_, _, _, Err(err), _) => return Err(err)
              (_, _, _, _, Err(err)) => return Err(err)
              (
                Ok(x_height_val),
                Ok(cap_height_val),
                Ok(default_char_val),
                Ok(break_char_val),
                Ok(max_context_val),
              ) => {
                x_height = Some(x_height_val)
                cap_height = Some(cap_height_val)
                default_char = Some(default_char_val)
                break_char = Some(break_char_val)
                max_context = Some(max_context_val)
              }
            }
          }
          let mut lower_optical_point_size : Int? = None
          let mut upper_optical_point_size : Int? = None
          if version >= 5 {
            let lower = read_u16_int(data, 96)
            let upper = read_u16_int(data, 98)
            match (lower, upper) {
              (Err(err), _) => return Err(err)
              (_, Err(err)) => return Err(err)
              (Ok(lower), Ok(upper)) => {
                lower_optical_point_size = Some(lower)
                upper_optical_point_size = Some(upper)
              }
            }
          }
          Ok(Os2Table::{
            version,
            weight_class,
            width_class,
            fs_type,
            typo_ascender,
            typo_descender,
            typo_line_gap,
            win_ascent,
            win_descent,
            code_page_range_1,
            code_page_range_2,
            x_height,
            cap_height,
            default_char,
            break_char,
            max_context,
            lower_optical_point_size,
            upper_optical_point_size,
          })
        }
      }
    }
  }
}