// 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 justification header (shallow).
pub struct JustificationHeader {
  class_table_offset : Int
  wdc_table_offset : Int
  pc_table_offset : Int
  lookup : LookupTable?
} derive(Show, ToJson)

///|
/// Parsed just table (shallow).
pub struct JustTable {
  version : Int
  format : Int
  horiz : JustificationHeader?
  vert : JustificationHeader?
} derive(Show, ToJson)

///|
pub fn JustTable::has_data(self : JustTable) -> Bool {
  self.version != 0
}

fn parse_justification_header(
  data : BytesView,
  offset : Int,
  num_glyphs : Int,
) -> Result[JustificationHeader, AatError] {
  if offset < 0 || offset + 8 > data.length() {
    return Err(UnexpectedEof)
  }
  let class_offset = read_u16_int(data, offset)
  let wdc_offset = read_u16_int(data, offset + 2)
  let pc_offset = read_u16_int(data, offset + 4)
  let lookup_offset = read_u16_int(data, offset + 6)
  match (class_offset, wdc_offset, pc_offset, lookup_offset) {
    (Err(err), _, _, _) => Err(err)
    (_, Err(err), _, _) => Err(err)
    (_, _, Err(err), _) => Err(err)
    (_, _, _, Err(err)) => Err(err)
    (Ok(class_offset), Ok(wdc_offset), Ok(pc_offset), Ok(lookup_offset)) => {
      if class_offset < 0 || wdc_offset < 0 || pc_offset < 0 || lookup_offset < 0 {
        return Err(InvalidFormat)
      }
      if class_offset != 0 && class_offset > data.length() {
        return Err(UnexpectedEof)
      }
      if wdc_offset != 0 && wdc_offset > data.length() {
        return Err(UnexpectedEof)
      }
      if pc_offset != 0 && pc_offset > data.length() {
        return Err(UnexpectedEof)
      }
      let lookup = if lookup_offset == 0 {
        None
      } else {
        if lookup_offset > data.length() {
          return Err(UnexpectedEof)
        }
        match parse_lookup(data, lookup_offset, num_glyphs) {
          Err(err) => return Err(err)
          Ok(value) => Some(value)
        }
      }
      Ok(
        JustificationHeader::{
          class_table_offset: class_offset,
          wdc_table_offset: wdc_offset,
          pc_table_offset: pc_offset,
          lookup,
        },
      )
    }
  }
}

///|
/// Parse a just table (shallow).
pub fn JustTable::parse(
  data : BytesView,
  num_glyphs : Int,
) -> Result[JustTable, AatError] {
  if num_glyphs < 0 {
    return Err(InvalidFormat)
  }
  let version = read_i32(data, 0)
  let format = read_u16_int(data, 4)
  let horiz_offset = read_u16_int(data, 6)
  let vert_offset = read_u16_int(data, 8)
  match (version, format, horiz_offset, vert_offset) {
    (Err(err), _, _, _) => Err(err)
    (_, Err(err), _, _) => Err(err)
    (_, _, Err(err), _) => Err(err)
    (_, _, _, Err(err)) => Err(err)
    (Ok(version), Ok(format), Ok(horiz_offset), Ok(vert_offset)) => {
      if format != 0 {
        return Err(InvalidFormat)
      }
      let horiz = if horiz_offset == 0 {
        None
      } else {
        Some(match parse_justification_header(data, horiz_offset, num_glyphs) {
          Err(err) => return Err(err)
          Ok(value) => value
        })
      }
      let vert = if vert_offset == 0 {
        None
      } else {
        Some(match parse_justification_header(data, vert_offset, num_glyphs) {
          Err(err) => return Err(err)
          Ok(value) => value
        })
      }
      Ok(JustTable::{ version, format, horiz, vert })
    }
  }
}