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

///|
/// Rounding state for the TrueType interpreter.
///
/// Ported from `fontations/skrifa/src/outline/glyf/hint/round.rs` (Apache-2.0 OR MIT).
priv enum TtRoundMode {
  Grid
  HalfGrid
  DoubleGrid
  DownToGrid
  UpToGrid
  Off
  Super
  Super45
}

///|
priv struct TtRoundState {
  mut mode : TtRoundMode
  mut threshold : Int
  mut phase : Int
  mut period : Int
}

///|
fn TtRoundState::default() -> TtRoundState {
  { mode: Grid, threshold: 0, phase: 0, period: 64 }
}

///|
fn TtRoundState::round(self : TtRoundState, distance_bits : Int) -> Int {
  match self.mode {
    HalfGrid =>
      if distance_bits >= 0 {
        (tt_hint_floor_26(distance_bits) + 32).max(0)
      } else {
        (-(tt_hint_floor_26(-distance_bits) + 32)).min(0)
      }
    Grid =>
      if distance_bits >= 0 {
        tt_hint_round_26(distance_bits).max(0)
      } else {
        (-tt_hint_round_26(-distance_bits)).min(0)
      }
    DoubleGrid =>
      if distance_bits >= 0 {
        tt_hint_round_pad(distance_bits, 32).max(0)
      } else {
        (-tt_hint_round_pad(-distance_bits, 32)).min(0)
      }
    DownToGrid =>
      if distance_bits >= 0 {
        tt_hint_floor_26(distance_bits).max(0)
      } else {
        (-tt_hint_floor_26(-distance_bits)).min(0)
      }
    UpToGrid =>
      if distance_bits >= 0 {
        tt_hint_ceil_26(distance_bits).max(0)
      } else {
        (-tt_hint_ceil_26(-distance_bits)).min(0)
      }
    Super =>
      if distance_bits >= 0 {
        let val = (
            (distance_bits + (self.threshold - self.phase)) & -self.period
          ) +
          self.phase
        if val < 0 {
          self.phase
        } else {
          val
        }
      } else {
        let val = -((self.threshold - self.phase - distance_bits) & -self.period) -
          self.phase
        if val > 0 {
          -self.phase
        } else {
          val
        }
      }
    Super45 =>
      if distance_bits >= 0 {
        let val = (distance_bits + (self.threshold - self.phase)) /
          self.period *
          self.period +
          self.phase
        if val < 0 {
          self.phase
        } else {
          val
        }
      } else {
        let val = -((self.threshold - self.phase - distance_bits) /
          self.period *
          self.period) -
          self.phase
        if val > 0 {
          -self.phase
        } else {
          val
        }
      }
    Off => distance_bits
  }
}