///|
/// Multi-file ROS package bundle export.

///|
pub(all) struct MeshAsset {
  rel_path : String
  bytes : Bytes
}

///|
pub(all) struct UrdfBundle {
  package_name : String
  robot : Robot
  meshes : Array[MeshAsset]
}

///|
pub fn UrdfBundle::new(package_name : String, robot : Robot) -> UrdfBundle {
  { package_name, robot, meshes: [], }
}

///|
pub fn UrdfBundle::add_mesh_bytes(
  self : UrdfBundle,
  rel_path : String,
  bytes : Bytes,
) -> UrdfBundle {
  let meshes = self.meshes.copy()
  meshes.push({ rel_path, bytes, })
  { ..self, meshes, }
}

///|
pub fn UrdfBundle::add_mesh_text(
  self : UrdfBundle,
  rel_path : String,
  text : String,
) -> UrdfBundle {
  self.add_mesh_bytes(rel_path, @encoding/utf8.encode(text))
}

///|
/// Generates a standard ROS 2 `package.xml`.
pub fn UrdfBundle::package_xml(
  self : UrdfBundle,
  version~ : String = "0.1.0",
  description~ : String = "",
  maintainer~ : String = "gmlewis",
  email~ : String = "gmlewis@users.noreply.github.com",
  license~ : String = "Apache-2.0",
) -> String {
  let sb = StringBuilder()
  sb.write_string("\n")
  sb.write_string("\n")
  sb.write_string("  " + xml_escape(self.package_name) + "\n")
  sb.write_string("  " + xml_escape(version) + "\n")
  sb.write_string(
    "  " + xml_escape(description) + "\n",
  )
  sb.write_string(
    "  " +
    xml_escape(maintainer) +
    "\n",
  )
  sb.write_string("  " + xml_escape(license) + "\n")
  sb.write_string("  ament_cmake\n")
  sb.write_string("  \n")
  sb.write_string("    ament_cmake\n")
  sb.write_string("  \n")
  sb.write_string("\n")
  sb.to_string()
}

///|
fn dir_of(path : String) -> String {
  match path.rev_find("/") {
    Some(idx) if idx > 0 => String::unsafe_substring(path, start=0, end=idx)
    _ => ""
  }
}

///|
/// Writes `package.xml`, `urdf/.urdf`, and every mesh asset to
/// `out_dir`, creating parent directories as needed.
pub async fn UrdfBundle::write_to_dir(
  self : UrdfBundle,
  out_dir : String,
  checked~ : Bool = true,
) -> Unit {
  @fs.mkdir(out_dir, recursive=true, allow_exist=true)
  let urdf_dir = out_dir + "/urdf"
  @fs.mkdir(urdf_dir, recursive=true, allow_exist=true)
  let urdf_path = urdf_dir + "/" + self.robot.name + ".urdf"
  self.robot.write_urdf_file(Some(urdf_path), checked~)
  let package_path = out_dir + "/package.xml"
  write_text_file(self.package_xml(), Some(package_path))
  for mesh in self.meshes {
    let parent = dir_of(mesh.rel_path)
    if parent != "" {
      @fs.mkdir(out_dir + "/" + parent, recursive=true, allow_exist=true)
    }
    @fs.write_file(
      out_dir + "/" + mesh.rel_path,
      mesh.bytes,
      permission=0o644,
      create_mode=@fs.CreateMode::CreateOrTruncate,
    )
  }
}