///|
pub struct AtlasProfile {
  name : String
  max_width : Int
  padding : Int
  strategy : AtlasStrategy
  objective : AtlasObjective
  mobile : Bool
} derive(Debug, Eq, ToJson, FromJson)

///|
pub fn AtlasProfile::options(self : AtlasProfile) -> AtlasOptions {
  { max_width: self.max_width, padding: self.padding }
}

///|
pub fn AtlasProfile::recommend(
  self : AtlasProfile,
  sheet : SpriteSheet,
) -> AtlasCandidate {
  let recommendation = recommend_atlas(
    sheet,
    max_width=self.max_width,
    padding=self.padding,
    objective=self.objective,
  )
  match recommendation.candidate_named(self.strategy) {
    Some(candidate) => candidate
    None => recommendation.best
  }
}

///|
pub fn AtlasProfile::fits(self : AtlasProfile, sheet : SpriteSheet) -> Bool {
  self.recommend(sheet).valid
}

///|
pub fn AtlasProfile::to_json_string(
  self : AtlasProfile,
  indent? : Int = 2,
) -> String {
  ToJson::to_json(self).stringify(indent~)
}

///|
pub fn atlas_profiles() -> Array[AtlasProfile] {
  [
    {
      name: "mobile-compact",
      max_width: 1024,
      padding: 1,
      strategy: CompactRows,
      objective: MinimizeArea,
      mobile: true,
    },
    {
      name: "mobile-power-of-two",
      max_width: 2048,
      padding: 2,
      strategy: PowerOfTwo,
      objective: MaximizeOccupancy,
      mobile: true,
    },
    {
      name: "desktop-balanced",
      max_width: 2048,
      padding: 2,
      strategy: Rows,
      objective: Balanced,
      mobile: false,
    },
    {
      name: "desktop-wide",
      max_width: 4096,
      padding: 2,
      strategy: CompactRows,
      objective: MinimizeWidth,
      mobile: false,
    },
    {
      name: "high-density",
      max_width: 4096,
      padding: 4,
      strategy: PowerOfTwo,
      objective: MaximizeOccupancy,
      mobile: false,
    },
  ]
}

///|
pub fn atlas_profile_named(name : String) -> AtlasProfile? {
  match atlas_profiles().search_by(fn(profile) { profile.name == name }) {
    Some(index) => Some(atlas_profiles()[index])
    None => None
  }
}

///|
pub fn mobile_atlas_profiles() -> Array[AtlasProfile] {
  atlas_profiles().filter(fn(profile) { profile.mobile })
}

///|
pub fn atlas_profile_count() -> Int {
  atlas_profiles().length()
}

///|
pub fn atlas_profile_names() -> Array[String] {
  atlas_profiles().map(fn(profile) { profile.name })
}

///|
pub fn best_atlas_profile(sheet : SpriteSheet, mobile : Bool) -> AtlasProfile? {
  let profiles = atlas_profiles().filter(fn(profile) {
    profile.mobile == mobile && profile.fits(sheet)
  })
  profiles.get(0)
}