///|
pub struct ToolpathMetrics {
  segment_count_value : Int
  rapid_distance_value : Double
  cutting_distance_value : Double
  estimated_seconds_value : Double
  feedless_cutting_count_value : Int
  endpoint_revisit_count_value : Int
} derive(Eq, Debug)

///|
pub fn ToolpathMetrics::segment_count(self : ToolpathMetrics) -> Int {
  self.segment_count_value
}

///|
pub fn ToolpathMetrics::rapid_distance(self : ToolpathMetrics) -> Double {
  self.rapid_distance_value
}

///|
pub fn ToolpathMetrics::cutting_distance(self : ToolpathMetrics) -> Double {
  self.cutting_distance_value
}

///|
pub fn ToolpathMetrics::estimated_seconds(self : ToolpathMetrics) -> Double {
  self.estimated_seconds_value
}

///|
pub fn ToolpathMetrics::feedless_cutting_count(self : ToolpathMetrics) -> Int {
  self.feedless_cutting_count_value
}

///|
pub fn ToolpathMetrics::endpoint_revisit_count(self : ToolpathMetrics) -> Int {
  self.endpoint_revisit_count_value
}

///|
/// Estimate duration from feed rates; units are minutes per distance unit.
pub fn measure(program : GCodeProgram) -> ToolpathMetrics {
  let mut rapid_distance = 0.0
  let mut cutting_distance = 0.0
  let mut seconds = 0.0
  let mut feedless = 0
  let mut revisits = 0
  let motions = program.motions()
  for index, motion in motions {
    let length = motion_path_length(motion)
    match motion.kind() {
      Rapid => {
        rapid_distance += length
        seconds += length / 100.0 * 60.0
      }
      Linear | ClockwiseArc | CounterclockwiseArc => {
        cutting_distance += length
        match motion.feed() {
          None => feedless += 1
          Some(feed) =>
            if feed > 0.0 {
              seconds += length / feed * 60.0
            } else {
              feedless += 1
            }
        }
      }
    }
    if index > 0 && motion.end() == motions[index - 1].end() {
      revisits += 1
    }
  }
  {
    segment_count_value: motions.length(),
    rapid_distance_value: rapid_distance,
    cutting_distance_value: cutting_distance,
    estimated_seconds_value: seconds,
    feedless_cutting_count_value: feedless,
    endpoint_revisit_count_value: revisits,
  }
}

///|
pub fn render_metrics(metrics : ToolpathMetrics) -> String {
  "segments=" +
  metrics.segment_count().to_string() +
  ", rapid_distance=" +
  metrics.rapid_distance().to_string() +
  ", cutting_distance=" +
  metrics.cutting_distance().to_string() +
  ", estimated_seconds=" +
  metrics.estimated_seconds().to_string() +
  ", feedless=" +
  metrics.feedless_cutting_count().to_string()
}