///|
// Fonts bundled in the program, so converting needs no font files: the
// files Ruby asciidoctor-pdf ships in its gem's `data/fonts` (the
// directory its themes call `GEM_FONTS_DIR`), and prawn-icon's icon fonts.
// The default theme's fonts are here; the fonts of the other bundled
// themes and the icon fonts live in packages of their own
// (`fonts/sans`, `fonts/fallback`, `fonts/icons`), so a program links only
// the ones it registers. Generated by scripts/pdf_bundle_fonts.mbtx; see
// pdf/NOTICE for the fonts' licenses.

///|
/// A set of bundled files, by the name they have in their directory
/// (`notoserif-regular-subset.ttf`, `fas/fa-solid.ttf`). Each is decoded
/// when it is first asked for, then kept.
pub struct Bundle {
  priv files : Map[String, () -> Bytes]
  priv decoded : Map[String, Bytes]
}

///|
/// A bundle of files: name → a function producing the contents (called
/// once, on the first `get`).
pub fn Bundle::new(files : Array[(String, () -> Bytes)]) -> Bundle {
  { files: Map::from_array(files), decoded: Map([]), }
}

///|
/// The contents of file `name`, when the bundle has it.
pub fn Bundle::get(self : Bundle, name : String) -> Bytes? {
  match self.decoded.get(name) {
    Some(data) => Some(data)
    None =>
      match self.files.get(name) {
        Some(load) => {
          let data = load()
          self.decoded[name] = data
          Some(data)
        }
        None => None
      }
  }
}

///|
/// Whether the bundle has file `name` (without decoding it).
pub fn Bundle::contains(self : Bundle, name : String) -> Bool {
  self.files.contains(name)
}

///|
/// The names of the bundle's files.
pub fn Bundle::names(self : Bundle) -> Array[String] {
  self.files.keys().collect()
}

///|
/// The bytes of generated data: the chunks of zlib-compressed,
/// ASCII85-armoured text that scripts/pdf_bundle_fonts.mbtx writes,
/// restored.
pub fn inflate_armoured(chunks : Array[Bytes]) -> Bytes {
  let joined = Buffer()
  for chunk in chunks {
    joined.write_bytes(chunk)
  }
  // the generator wrote valid data: failing to decode it is a bug
  @flate.pdf_flate_decode(@codec.pdf_ascii85_decode(joined.contents())) catch {
    _ => abort("bundled font data does not decode")
  }
}

///|
/// A bundle of generated data (see `inflate_armoured`).
pub fn Bundle::from_armoured(
  files : Array[(String, () -> Array[Bytes])],
) -> Bundle {
  Bundle::new(
    files.map(file => {
      let (name, chunks) = file
      (name, () => inflate_armoured(chunks()))
    }),
  )
}

///|
let default_bundle : Bundle = Bundle::from_armoured(bundled_files())

///|
/// asciidoctor-pdf 2.3.27's default fonts, by their names in its
/// `data/fonts`: the default theme's Noto Serif
/// (`notoserif-regular-subset.ttf`, `-bold-`, `-italic-`, `-bold_italic-`)
/// and M+ 1mn (`mplus1mn-*-subset.ttf`), and its mapping of Font Awesome 4
/// icon names (`fa-legacy-mapping.yml`).
pub fn default_fonts() -> Bundle {
  default_bundle
}