// GPX 1.1 导入:wpt / rte / trk → KML 文档。
//
// 映射:wpt → Point;rte → LineString;trk 的单段 → LineString,
// 多段 → MultiGeometry(LineString...)。

///|
/// 从 wpt/rtept/trkpt 元素读一个点(lat/lon 属性 + 可选 ele)。
fn point_from_gpx(elem : XmlElement) -> KmlPoint raise KmlError {
  let lat = match elem.attr("lat") {
    Some(v) => parse_double(trim_text(v))
    None => raise BadGpx("missing lat")
  }
  let lon = match elem.attr("lon") {
    Some(v) => parse_double(trim_text(v))
    None => raise BadGpx("missing lon")
  }
  let alt = match first_element(elem, "ele") {
    Some(e) => parse_double(trim_text(e.text()))
    None => None
  }
  match (lon, lat) {
    (Some(lon), Some(lat)) => { lon, lat, alt, }
    _ => raise BadGpx("lat/lon not numeric")
  }
}

///|
/// 读一组子点(rtept / trkpt)。
fn points_from_gpx(
  elem : XmlElement,
  child_name : String,
) -> Array[KmlPoint] raise KmlError {
  let out : Array[KmlPoint] = []
  let mut i = 0
  while i < elem.children.length() {
    match elem.children[i] {
      Element(child) =>
        if child.name == child_name {
          out.push(point_from_gpx(child))
        }
      Text(_) => ()
    }
    i = i + 1
  }
  out
}

///|
/// 读一个 GPX 名称子元素。
fn name_from_gpx(elem : XmlElement) -> String {
  match first_element(elem, "name") {
    Some(n) => trim_text(n.text())
    None => ""
  }
}

///|
/// 从 GPX 文本导入 KML 文档。
pub fn from_gpx(text : String) -> KmlDocument raise KmlError {
  let root = parse_xml(text)
  let placemarks : Array[Placemark] = []
  if root.name != "gpx" {
    raise BadGpx("root element is not gpx")
  }
  let mut i = 0
  while i < root.children.length() {
    match root.children[i] {
      Element(child) =>
        if child.name == "wpt" {
          placemarks.push({
            name: name_from_gpx(child),
            description: "",
            geometry: Some(Geometry::Point(point_from_gpx(child))),
            style_url: "",
            extended_data: [],
            folder: "",
            timestamp: None,
          })
        } else if child.name == "rte" {
          let pts = points_from_gpx(child, "rtept")
          if pts.length() > 0 {
            placemarks.push({
              name: name_from_gpx(child),
              description: "",
              geometry: Some(Geometry::LineString({ points: pts, })),
              style_url: "",
              extended_data: [],
              folder: "",
              timestamp: None,
            })
          }
        } else if child.name == "trk" {
          let segs : Array[Array[KmlPoint]] = []
          let mut k = 0
          while k < child.children.length() {
            match child.children[k] {
              Element(seg) =>
                if seg.name == "trkseg" {
                  let pts = points_from_gpx(seg, "trkpt")
                  if pts.length() > 0 {
                    segs.push(pts)
                  }
                }
              Text(_) => ()
            }
            k = k + 1
          }
          if segs.length() == 1 {
            placemarks.push({
              name: name_from_gpx(child),
              description: "",
              geometry: Some(Geometry::LineString({ points: segs[0], })),
              style_url: "",
              extended_data: [],
              folder: "",
              timestamp: None,
            })
          } else if segs.length() > 1 {
            let parts : Array[Geometry] = []
            let mut s = 0
            while s < segs.length() {
              parts.push(Geometry::LineString({ points: segs[s], }))
              s = s + 1
            }
            placemarks.push({
              name: name_from_gpx(child),
              description: "",
              geometry: Some(Geometry::MultiGeometry(parts)),
              style_url: "",
              extended_data: [],
              folder: "",
              timestamp: None,
            })
          }
        }
      Text(_) => ()
    }
    i = i + 1
  }
  { name: "", placemarks, styles: [], style_maps: [], }
}