///|
fn max_spatial_depth(roots : Array[SpatialNode]) -> Int {
  roots.fold(init=0, (maximum, root) => {
    let depth = spatial_depth(root)
    if depth > maximum {
      depth
    } else {
      maximum
    }
  })
}

///|
pub fn analyze_model(source : String, model : Model) -> ModelMetrics {
  let index = model.index()
  let graph = graph_stats(index)
  let relationships = model.entities.filter(is_relationship).length()
  let properties = model.entities.filter(is_property_entity).length()
  {
    source_length: source.length(),
    entity_count: model.entity_count(),
    product_count: model.products().length(),
    relationship_count: relationships,
    geometry_count: geometry_entities(index).length(),
    property_count: properties,
    spatial_depth: max_spatial_depth(spatial_roots(index)),
    reference_count: graph.reference_count,
  }
}

///|
pub fn metrics_from_step(source : String) -> ModelMetrics raise ParseError {
  let model = parse(source)
  analyze_model(source, model)
}

///|
pub fn ModelMetrics::headline(self : ModelMetrics) -> String {
  "entities=" +
  self.entity_count.to_string() +
  ", products=" +
  self.product_count.to_string() +
  ", geometry=" +
  self.geometry_count.to_string() +
  ", relationships=" +
  self.relationship_count.to_string()
}