// 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.

///|
let myanmar_feature_tags : Array[@common.Tag] = [
  @common.Tag::from_chars('l', 'o', 'c', 'l'),
  @common.Tag::from_chars('c', 'c', 'm', 'p'),
  @common.Tag::from_chars('r', 'p', 'h', 'f'),
  @common.Tag::from_chars('p', 'r', 'e', 'f'),
  @common.Tag::from_chars('b', 'l', 'w', 'f'),
  @common.Tag::from_chars('p', 's', 't', 'f'),
  @common.Tag::from_chars('p', 'r', 'e', 's'),
  @common.Tag::from_chars('a', 'b', 'v', 's'),
  @common.Tag::from_chars('b', 'l', 'w', 's'),
  @common.Tag::from_chars('p', 's', 't', 's'),
]

///|
let myanmar_cat_c : Int = 1

///|
let myanmar_cat_cs : Int = 18

///|
let myanmar_cat_ra : Int = 15

///|
let myanmar_cat_iv : Int = 2

///|
let myanmar_cat_gb : Int = 10

///|
let myanmar_cat_dotted_circle : Int = 11

///|
let myanmar_cat_as : Int = 32

///|
let myanmar_cat_h : Int = 4

///|
let myanmar_cat_mr : Int = 36

///|
let myanmar_cat_vpre : Int = 22

///|
let myanmar_cat_vs : Int = 40

///|
let myanmar_cat_vblw : Int = 21

///|
let myanmar_cat_a : Int = 9

///|
let myanmar_pos_start : Int = 0

///|
let myanmar_pos_pre_m : Int = 2

///|
let myanmar_pos_pre_c : Int = 3

///|
let myanmar_pos_base_c : Int = 4

///|
let myanmar_pos_after_main : Int = 5

///|
let myanmar_pos_before_sub : Int = 7

///|
let myanmar_pos_below_c : Int = 8

///|
let myanmar_pos_after_sub : Int = 9

///|
let myanmar_pos_end : Int = 14

fn myanmar_category(codepoint : UInt) -> Int {
  indic_category(indic_get_categories(codepoint)).reinterpret_as_int()
}

fn is_consonant_myanmar(category : Int) -> Bool {
  category == myanmar_cat_c ||
  category == myanmar_cat_cs ||
  category == myanmar_cat_ra ||
  category == myanmar_cat_iv ||
  category == myanmar_cat_gb ||
  category == myanmar_cat_dotted_circle
}

fn reverse_range(buffer : Buffer, start : Int, end : Int) -> Unit {
  if start < 0 || end > buffer.infos.length() || start >= end {
    return ()
  }
  let mut i = start
  let mut j = end - 1
  while i < j {
    let tmp = buffer.infos[i]
    buffer.infos[i] = buffer.infos[j]
    buffer.infos[j] = tmp
    let tmp_pos = buffer.positions[i]
    buffer.positions[i] = buffer.positions[j]
    buffer.positions[j] = tmp_pos
    i = i + 1
    j = j - 1
  }
}

fn reorder_by_positions(
  buffer : Buffer,
  positions : Array[Int],
  start : Int,
  end : Int,
) -> Array[Int] {
  if start < 0 || end > buffer.infos.length() || start >= end {
    return positions
  }
  let range_len = end - start
  let order : Array[Int] = []
  for pos in myanmar_pos_start..=myanmar_pos_end {
    for rel in 0.. Unit {
  if start < 0 || end > buffer.infos.length() || start >= end {
    return ()
  }
  buffer.merge_clusters(start, end)
  let mut base = end
  let mut has_reph = false
  let mut limit = start
  if start + 3 <= end &&
    categories[start] == myanmar_cat_ra &&
    categories[start + 1] == myanmar_cat_as &&
    categories[start + 2] == myanmar_cat_h {
    limit = limit + 3
    base = start
    has_reph = true
  }
  if !has_reph {
    base = limit
  }
  for i in limit.. Unit {
  if categories.length() != buffer.infos.length() || syllables.length() != buffer.infos.length() {
    return ()
  }
  let mut i = 0
  while i < syllables.length() {
    let syllable = syllables[i]
    let mut j = i + 1
    while j < syllables.length() && syllables[j] == syllable {
      j = j + 1
    }
    let syllable_type = syllable & 0x0f
    if syllable_type == myanmar_syllable_type_consonant ||
      syllable_type == myanmar_syllable_type_broken {
      reorder_consonant_syllable_myanmar(buffer, categories, i, j)
    }
    i = j
  }
}

///|
pub fn Buffer::shape_myanmar(
  self : Buffer,
  font : @font.Font,
) -> Result[Unit, ShapeError] {
  let gsub = match font.gsub() {
    Err(err) => return Err(Font(err))
    Ok(value) => value
  }
  let script_tag = self.script.to_tag()
  let mym2_tag = @common.Tag::from_chars('m', 'y', 'm', '2')
  let mut selected_script_tag = script_tag
  if gsub is Some(gsub) && buffer_layout_has_script(gsub.layout(), mym2_tag) {
    selected_script_tag = mym2_tag
  }
  if gsub is Some(gsub) {
    let dflt_tag = @common.Tag::from_chars('D', 'F', 'L', 'T')
    let latn_tag = @common.Tag::from_chars('l', 'a', 't', 'n')
    if !buffer_layout_has_script(gsub.layout(), mym2_tag) {
      if buffer_layout_has_script(gsub.layout(), script_tag) ||
        buffer_layout_has_script(gsub.layout(), dflt_tag) ||
        buffer_layout_has_script(gsub.layout(), latn_tag) {
        return self.shape_ot_with_options(
          font,
          fallback_position=false,
          zero_width_marks=ZeroWidthMarks::ByGdefEarly,
        )
      }
    }
  }
  let categories : Array[UInt] = []
  for info in self.infos {
    categories.push(indic_category(indic_get_categories(info.codepoint)))
  }
  let syllables = find_syllables_myanmar(categories)
  match insert_dotted_circle_for_syllables(
    font,
    self,
    syllables,
    myanmar_syllable_type_broken,
  ) {
    Err(err) => return Err(err)
    Ok(_) => ()
  }
  let categories_after_u : Array[UInt] = []
  let categories_after_i : Array[Int] = []
  for info in self.infos {
    let category = myanmar_category(info.codepoint)
    categories_after_i.push(category)
    categories_after_u.push(category.reinterpret_as_uint())
  }
  let syllables_after = find_syllables_myanmar(categories_after_u)
  reorder_myanmar_syllables(self, categories_after_i, syllables_after)
  let (unicode_mark_flags, combining_classes) = collect_mark_fallback_data(self.infos)
  match self.shape_basic(font) {
    Err(err) => return Err(err)
    Ok(_) => ()
  }
  if gsub is Some(gsub) {
    match apply_gsub_features_for_syllables(
      font,
      self,
      gsub,
      myanmar_feature_tags,
      syllables_after,
      script_tag=selected_script_tag,
    ) {
      Err(err) => return Err(err)
      Ok(_) => ()
    }
  }
  apply_gpos(
    font,
    self,
    zero_width_marks=ZeroWidthMarks::ByGdefEarly,
    fallback_position=false,
    unicode_mark_flags=unicode_mark_flags,
    combining_classes=combining_classes,
  )
}