///|
pub fn order_sort_subgraph(
  g : Graph,
  v : String,
  cg : Graph,
  bias_right? : Bool = false,
) -> OrderResult {
  let mut movable = g.children(v~)
  let node = if g.node_opt(v) is Some(node) { node } else { empty_attrs() }
  let bl = node.get_string("borderLeft")
  let br = node.get_string("borderRight")
  if bl is Some(bl) && br is Some(br) {
    movable = movable.filter(w => w != bl && w != br)
  }
  let barycenters = order_barycenter(g, movable~)
  let subgraphs : Map[String, OrderResult] = Map::new()
  for entry in barycenters {
    if !g.children(v=entry.v).is_empty() {
      let subgraph_result = order_sort_subgraph(g, entry.v, cg, bias_right~)
      subgraphs.set(entry.v, subgraph_result)
      if subgraph_result.barycenter is Some(other_bary) &&
        subgraph_result.weight is Some(other_weight) {
        if entry.barycenter is Some(target_bary) &&
          entry.weight is Some(target_weight) {
          entry.barycenter = Some(
            (target_bary * target_weight + other_bary * other_weight) /
            (target_weight + other_weight),
          )
          entry.weight = Some(target_weight + other_weight)
        } else {
          entry.barycenter = Some(other_bary)
          entry.weight = Some(other_weight)
        }
      }
    }
  }
  let entries = order_resolve_conflicts(barycenters, cg)
  order_expand_subgraphs(entries, subgraphs)
  let result = order_sort(entries, bias_right~)
  if bl is Some(bl) && br is Some(br) {
    result.vs = [bl] + result.vs + [br]
    let bl_preds = g.predecessors(bl)
    let br_preds = g.predecessors(br)
    if !bl_preds.is_empty() && !br_preds.is_empty() {
      let bl_pred = g.node(bl_preds[0])
      let br_pred = g.node(br_preds[0])
      let mut bary = 0.0
      let mut weight = 0.0
      if result.barycenter is Some(result_bary) &&
        result.weight is Some(result_weight) {
        bary = result_bary
        weight = result_weight
      }
      result.barycenter = Some(
        (
          bary * weight +
          bl_pred.get_int_or("order", 0).to_double() +
          br_pred.get_int_or("order", 0).to_double()
        ) /
        (weight + 2.0),
      )
      result.weight = Some(weight + 2.0)
    }
  }
  result
}

///|
fn order_expand_subgraphs(
  entries : Array[OrderEntry],
  subgraphs : Map[String, OrderResult],
) -> Unit {
  for entry in entries {
    let expanded : Array[String] = []
    for v in entry.vs {
      if subgraphs.get(v) is Some(subgraph) {
        for sub_v in subgraph.vs {
          expanded.push(sub_v)
        }
      } else {
        expanded.push(v)
      }
    }
    entry.vs = expanded
  }
}