// Ported from topojson-client v3.1.0 src/feature.js, ISC.

///|
fn Topology::line(
  self : Topology,
  refs : Json,
  minimum : Int,
) -> Array[Array[Double]] raise TopoError {
  let points : Array[Array[Double]] = []
  for arc_ref in array(refs) {
    if !points.is_empty() {
      ignore(points.pop())
    }
    for p in self.arc(number(arc_ref).to_int()) {
      points.push(p)
    }
  }
  if !points.is_empty() {
    while points.length() < minimum {
      points.push(points[0].copy())
    }
  }
  points
}

///|
fn Topology::geometry(self : Topology, g : Json) -> Json raise TopoError {
  let type_ = kind(g)
  let refs = field(g, "arcs")
  let coords : Json = match type_ {
    "Point" => self.point(field(g, "coordinates")).to_json()
    "MultiPoint" =>
      array(field(g, "coordinates")).map(p => self.point(p)).to_json()
    "LineString" => self.line(refs, 2).to_json()
    "MultiLineString" => array(refs).map(r => self.line(r, 2)).to_json()
    "Polygon" => array(refs).map(r => self.line(r, 4)).to_json()
    "MultiPolygon" =>
      array(refs).map(poly => array(poly).map(r => self.line(r, 4))).to_json()
    "GeometryCollection" =>
      return {
        "type": "GeometryCollection",
        "geometries": array(field(g, "geometries"))
        .map(c => self.geometry(c))
        .to_json(),
      }
    _ => return Json::null()
  }
  { "type": type_.to_json(), "coordinates": coords }
}

///|
fn Topology::single_feature(self : Topology, g : Json) -> Json raise TopoError {
  let properties = field(g, "properties")
  let out : Map[String, Json] = Map([
    ("type", "Feature".to_json()),
    ("geometry", self.geometry(g)),
    (
      "properties",
      if properties == Json::null() {
        Json::empty_object()
      } else {
        properties
      },
    ),
  ])
  for k in ["id", "bbox"] {
    let v = field(g, k)
    if v != Json::null() {
      out[k] = v
    }
  }
  Json::object(out)
}

///|
/// Convert a named object into a GeoJSON Feature or FeatureCollection.
pub fn Topology::feature(
  self : Topology,
  name : String,
) -> Json raise TopoError {
  let g = self.object(name)
  if kind(g) == "GeometryCollection" {
    {
      "type": "FeatureCollection",
      "features": array(field(g, "geometries"))
      .map(c => self.single_feature(c))
      .to_json(),
    }
  } else {
    self.single_feature(g)
  }
}