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

///|
/// Cache for shaped runs (ported from `cosmic-text/src/shape_run_cache.rs`).

///|
/// Key for caching shape runs.
pub struct ShapeRunKey {
  text : String
  default_attrs : Attrs
  attrs_spans : Array[(Int, Int, Attrs)]
}

///|
pub fn ShapeRunKey::new(text : String, attrs_list : AttrsList) -> ShapeRunKey {
  let default_attrs = attrs_list.defaults()
  let spans : Array[(Int, Int, Attrs)] = []
  for s in attrs_list.spans_iter() {
    if s.attrs != default_attrs {
      spans.push((s.start, s.end, s.attrs))
    }
  }
  ShapeRunKey::{ text, default_attrs, attrs_spans: spans }
}

///|
pub impl Eq for ShapeRunKey with fn equal(self, other) {
  if self.text != other.text ||
    self.default_attrs != other.default_attrs ||
    self.attrs_spans.length() != other.attrs_spans.length() {
    return false
  }
  for i in 0.. ShapeRunCache {
  ShapeRunCache::{ age: 0UL, cache: @hashmap.HashMap::default() }
}

///|
/// Get a cache item, updating age if found.
pub fn ShapeRunCache::get(
  self : ShapeRunCache,
  key : ShapeRunKey,
) -> Array[ShapeGlyph]? {
  match self.cache.get(key) {
    None => None
    Some((_, glyphs)) => {
      self.cache.set(key, (self.age, glyphs))
      Some(glyphs)
    }
  }
}

///|
/// Peek a cache item without updating its age.
pub fn ShapeRunCache::peek(
  self : ShapeRunCache,
  key : ShapeRunKey,
) -> Array[ShapeGlyph]? {
  match self.cache.get(key) {
    None => None
    Some((_, glyphs)) => Some(glyphs)
  }
}

///|
/// Insert a cache item with current age.
pub fn ShapeRunCache::insert(
  self : ShapeRunCache,
  key : ShapeRunKey,
  glyphs : Array[ShapeGlyph],
) -> Unit {
  self.cache.set(key, (self.age, glyphs))
}

///|
/// Clear all cached runs.
pub fn ShapeRunCache::clear(self : ShapeRunCache) -> Unit {
  self.cache.clear()
}

///|
/// Remove anything in the cache with an age older than `keep_ages`.
pub fn ShapeRunCache::trim(self : ShapeRunCache, keep_ages : UInt64) -> Unit {
  let entries = self.cache.to_array()
  for e in entries {
    let (k, v) = e
    let age = v.0
    if age + keep_ages < self.age {
      self.cache.remove(k)
    }
  }
  self.age = self.age + 1UL
}

///|
pub impl Show for ShapeRunCache with fn output(_self, logger) {
  logger.write_string("ShapeRunCache { .. }")
}