///|
/// Explicit presentation style. Omission preserves intrinsic family geometry.
pub(all) enum ConnectorStyle {
  Elbow
  Rounded
  Curved
} derive(Eq, Debug)

///|
pub(all) enum CrossingMode {
  Bridge
  Plain
} derive(Eq, Debug)

///|
/// Per-call connector budgets. Every candidate and generated segment is charged.
pub struct ConnectorLimits {
  candidates : Int32
  subdivisions : Int32
  segments : Int32
  crossings : Int32
  output_units : Int32
} derive(Eq, Debug)

///|
pub fn ConnectorLimits::new(
  candidates~ : Int32 = 2000000,
  subdivisions~ : Int32 = 200000,
  segments~ : Int32 = 100000,
  crossings~ : Int32 = 10000,
  output_units~ : Int32 = 16777216,
) -> ConnectorLimits {
  { candidates, subdivisions, segments, crossings, output_units, }
}

///|
pub struct ConnectorOptions {
  style : ConnectorStyle?
  crossing : CrossingMode
  minimum_approach : Double
  corner_radius : Double
  bridge_radius : Double
  style_supplied_bpmn : Bool
  limits : ConnectorLimits
} derive(Eq, Debug)

///|
pub fn ConnectorOptions::new(
  style? : ConnectorStyle,
  crossing~ : CrossingMode = Bridge,
  minimum_approach~ : Double = 24.0,
  corner_radius~ : Double = 8.0,
  bridge_radius~ : Double = 5.0,
  style_supplied_bpmn~ : Bool = false,
  limits~ : ConnectorLimits = ConnectorLimits::new(),
) -> ConnectorOptions {
  {
    style,
    crossing,
    minimum_approach,
    corner_radius,
    bridge_radius,
    style_supplied_bpmn,
    limits,
  }
}

///|
pub(all) struct ConnectorPoint {
  x : Double
  y : Double
} derive(Eq, Debug)

///|
/// Absolute SVG commands. Source route points remain separate from these values.
pub(all) enum ConnectorCommand {
  Move(ConnectorPoint)
  Line(ConnectorPoint)
  Quadratic(ConnectorPoint, ConnectorPoint)
  Cubic(ConnectorPoint, ConnectorPoint, ConnectorPoint)
} derive(Eq, Debug)

///|
pub struct ConnectorPath {
  commands : ReadOnlyArray[ConnectorCommand]
} derive(Eq, Debug)

///|
fn cn(value : Double) -> String {
  @swimlane_layout.svg_number(value)
}

///|
fn cp(p : ConnectorPoint) -> String {
  "\{cn(p.x)} \{cn(p.y)}"
}

///|
pub fn ConnectorPath::svg(self : ConnectorPath) -> String {
  let out = StringBuilder()
  for i, command in self.commands {
    if i > 0 {
      out.write_string(" ")
    }
    match command {
      Move(p) => out.write_string("M" + cp(p))
      Line(p) => out.write_string("L" + cp(p))
      Quadratic(c, p) => out.write_string("Q" + cp(c) + " " + cp(p))
      Cubic(a, b, p) =>
        out.write_string("C" + cp(a) + " " + cp(b) + " " + cp(p))
    }
  }
  out.to_string()
}

///|
fn clerp(a : ConnectorPoint, b : ConnectorPoint, t : Double) -> ConnectorPoint {
  { x: a.x + (b.x - a.x) * t, y: a.y + (b.y - a.y) * t, }
}

///|
fn cdist(a : ConnectorPoint, b : ConnectorPoint) -> Double {
  ((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y)).sqrt()
}

///|
fn cend(command : ConnectorCommand) -> ConnectorPoint {
  match command {
    Move(p) | Line(p) | Quadratic(_, p) | Cubic(_, _, p) => p
  }
}

///|
fn cpoint(
  start : ConnectorPoint,
  command : ConnectorCommand,
  t : Double,
) -> ConnectorPoint {
  match command {
    Move(p) => p
    Line(p) => clerp(start, p, t)
    Quadratic(c, p) => clerp(clerp(start, c, t), clerp(c, p, t), t)
    Cubic(a, b, p) =>
      clerp(
        clerp(clerp(start, a, t), clerp(a, b, t), t),
        clerp(clerp(a, b, t), clerp(b, p, t), t),
        t,
      )
  }
}

///|
fn csplit(
  start : ConnectorPoint,
  command : ConnectorCommand,
  t : Double,
) -> (ConnectorCommand, ConnectorCommand) {
  match command {
    Move(p) => (Move(p), Move(p))
    Line(p) => (Line(clerp(start, p, t)), Line(p))
    Quadratic(c, p) => {
      let a = clerp(start, c, t)
      let b = clerp(c, p, t)
      let m = clerp(a, b, t)
      (Quadratic(a, m), Quadratic(b, p))
    }
    Cubic(a, b, p) => {
      let x = clerp(start, a, t)
      let y = clerp(a, b, t)
      let z = clerp(b, p, t)
      let u = clerp(x, y, t)
      let v = clerp(y, z, t)
      let m = clerp(u, v, t)
      (Cubic(x, u, m), Cubic(v, z, p))
    }
  }
}

///|
fn cslice(
  start : ConnectorPoint,
  command : ConnectorCommand,
  a : Double,
  b : Double,
) -> ConnectorCommand {
  let (left, _) = csplit(start, command, b)
  if a <= 0.0 {
    left
  } else {
    csplit(start, left, a / b).1
  }
}

///|
/// Read the renderer's absolute path dialect. No author markup is interpreted.
pub fn ConnectorPath::parse(source : String) -> ConnectorPath? {
  let tokens : Array[String] = []
  let token = StringBuilder()
  fn flush() -> Unit {
    let s = token.to_string()
    if s != "" {
      tokens.push(s)
      token.reset()
    }
  }
  for c in source {
    if "MLHVQC".contains(c.to_string()) {
      flush()
      tokens.push(c.to_string())
    } else if c == ' ' || c == ',' || c == '\n' || c == '\t' {
      flush()
    } else if c == '-' &&
      token.to_string() != "" &&
      !token.to_string().has_suffix("e") &&
      !token.to_string().has_suffix("E") {
      flush()
      token.write_char(c)
    } else {
      token.write_char(c)
    }
  }
  flush()
  let commands : Array[ConnectorCommand] = []
  let mut i = 0
  let mut current : ConnectorPoint = { x: 0.0, y: 0.0, }
  while i < tokens.length() {
    let op = tokens[i]
    i += 1
    let count = match op {
      "M" | "L" => 2
      "H" | "V" => 1
      "Q" => 4
      "C" => 6
      _ => return None
    }
    if count > tokens.length() - i {
      return None
    }
    let numbers : Array[Double] = []
    for j in 0.. return None
      }
      if number != number || number.abs() > 1000000000.0 {
        return None
      }
      numbers.push(number)
    }
    i += count
    let p : ConnectorPoint = match op {
      "H" => { x: numbers[0], y: current.y, }
      "V" => { x: current.x, y: numbers[0], }
      _ => { x: numbers[count - 2], y: numbers[count - 1], }
    }
    commands.push(
      match op {
        "M" => Move(p)
        "Q" => Quadratic({ x: numbers[0], y: numbers[1], }, p)
        "C" =>
          Cubic(
            { x: numbers[0], y: numbers[1], },
            { x: numbers[2], y: numbers[3], },
            p,
          )
        _ => Line(p)
      },
    )
    current = p
  }
  if commands.is_empty() || !(commands[0] is Move(_)) {
    None
  } else {
    Some({ commands: ReadOnlyArray::from_array(commands), })
  }
}

///|
fn cterminal(
  path : ConnectorPath,
  minimum : Double,
  end_marker : Bool,
) -> ConnectorPath {
  if !end_marker || path.commands.length() < 2 {
    return path
  }
  let commands = path.commands.iter().to_array()
  let last = commands[commands.length() - 1]
  let terminal = minimum.max(14.0)
  match last {
    Cubic(a, b, end) => {
      let length = cdist(b, end)
      if length < 0.001 {
        return path
      }
      let entry = clerp(end, b, terminal / length)
      let control = clerp(end, b, (terminal + 8.0) / length)
      commands[commands.length() - 1] = Cubic(a, control, entry)
      commands.push(Line(end))
    }
    Quadratic(b, end) => {
      let length = cdist(b, end)
      if length < 0.001 {
        return path
      }
      let entry = clerp(end, b, terminal / length)
      commands[commands.length() - 1] = Quadratic(b, entry)
      commands.push(Line(end))
    }
    _ => return path
  }
  { commands: ReadOnlyArray::from_array(commands), }
}

///|
fn cstyle(
  path : ConnectorPath,
  options : ConnectorOptions,
  start_marker : Bool,
  end_marker : Bool,
  scale~ : Double = 1.0,
) -> ConnectorPath {
  guard options.style is Some(style) else { return path }
  let points : Array[ConnectorPoint] = []
  for command in path.commands {
    match command {
      Move(p) | Line(p) => points.push(p)
      Quadratic(c, p) => {
        points.push(c)
        points.push(p)
      }
      Cubic(a, b, p) => {
        points.push(a)
        points.push(b)
        points.push(p)
      }
    }
  }
  if points.length() < 3 {
    return path
  }
  let out : Array[ConnectorCommand] = [Move(points[0])]
  for i in 1..<(points.length() - 1) {
    let a = points[i - 1]
    let b = points[i]
    let c = points[i + 1]
    let before = cdist(a, b)
    let after = cdist(b, c)
    if before < 0.001 || after < 0.001 {
      continue
    }
    if style == Elbow {
      out.push(Line(b))
      continue
    }
    let reserve_before = if i == 1 && start_marker {
      options.minimum_approach.max(14.0)
    } else {
      0.0
    }
    let reserve_after = if i == points.length() - 2 && end_marker {
      options.minimum_approach.max(14.0)
    } else {
      0.0
    }
    let radius = if style == Rounded {
      options.corner_radius
    } else {
      before.min(after) * 0.5
    }
    let cut = (radius * scale)
      .min(before * 0.5)
      .min(after * 0.5)
      .min((before - reserve_before).max(0.0))
      .min((after - reserve_after).max(0.0))
    let entry = clerp(b, a, cut / before)
    let exit = clerp(b, c, cut / after)
    out.push(Line(entry))
    if cut > 0.001 {
      if style == Rounded {
        out.push(Quadratic(b, exit))
      } else {
        out.push(
          Cubic(clerp(entry, b, 0.666667), clerp(exit, b, 0.666667), exit),
        )
      }
    } else {
      out.push(Line(b))
    }
  }
  out.push(Line(points[points.length() - 1]))
  { commands: ReadOnlyArray::from_array(out), }
}

///|
priv struct ConnectorFlat {
  command : Int32
  a : ConnectorPoint
  b : ConnectorPoint
  lo : Double
  hi : Double
}

///|
priv struct ConnectorWork {
  options : ConnectorOptions
  diagnostics : Array[@diagrams.Diagnostic]
  mut candidates : Int32
  mut subdivisions : Int32
  mut segments : Int32
  mut crossings : Int32
  mut failed : Bool
}

///|
fn ConnectorWork::fail(
  self : ConnectorWork,
  code : String,
  message : String,
) -> Unit {
  if !self.failed {
    self.diagnostics.push(@diagrams.Diagnostic::error(code, message))
  }
  self.failed = true
}

///|
fn ConnectorWork::charge(self : ConnectorWork, kind : Int32) -> Bool {
  if self.failed {
    return false
  }
  let limit = self.options.limits
  let exceeded = match kind {
    0 =>
      if self.candidates >= limit.candidates {
        true
      } else {
        self.candidates += 1
        false
      }
    1 =>
      if self.subdivisions >= limit.subdivisions {
        true
      } else {
        self.subdivisions += 1
        false
      }
    2 =>
      if self.segments >= limit.segments {
        true
      } else {
        self.segments += 1
        false
      }
    _ =>
      if self.crossings >= limit.crossings {
        true
      } else {
        self.crossings += 1
        false
      }
  }
  if exceeded {
    self.fail("connector/limit", "Connector processing budget exhausted")
  }
  !self.failed
}

///|
fn cflatten(path : ConnectorPath, work : ConnectorWork) -> Array[ConnectorFlat] {
  let out : Array[ConnectorFlat] = []
  let mut start : ConnectorPoint = { x: 0.0, y: 0.0, }
  for index, command in path.commands {
    if command is Move(p) {
      start = p
      continue
    }
    fn split(lo : Double, hi : Double, depth : Int32) -> Unit {
      if !work.charge(1) {
        return
      }
      let a = cpoint(start, command, lo)
      let b = cpoint(start, command, hi)
      let middle = cpoint(start, command, (lo + hi) * 0.5)
      let q1 = cpoint(start, command, lo + (hi - lo) * 0.25)
      let q3 = cpoint(start, command, lo + (hi - lo) * 0.75)
      let error = cdist(middle, clerp(a, b, 0.5))
        .max(cdist(q1, clerp(a, b, 0.25)))
        .max(cdist(q3, clerp(a, b, 0.75)))
      if error > 0.05 {
        if depth >= 16 {
          work.fail(
            "connector/limit", "Connector subdivision tolerance exceeded its depth budget",
          )
          return
        }
        split(lo, (lo + hi) * 0.5, depth + 1)
        split((lo + hi) * 0.5, hi, depth + 1)
      } else if work.charge(2) {
        out.push({ command: index, a, b, lo, hi, })
      }
    }
    split(0.0, 1.0, 0)
    start = cend(command)
  }
  out
}

///|
fn ccross(a : ConnectorPoint, b : ConnectorPoint) -> Double {
  a.x * b.y - a.y * b.x
}

///|
fn csub(a : ConnectorPoint, b : ConnectorPoint) -> ConnectorPoint {
  { x: a.x - b.x, y: a.y - b.y, }
}

///|
priv struct ConnectorHop {
  command : Int32
  lo : Double
  hi : Double
  radius : Double
  flip : Bool
}

///|
fn ctangent(
  start : ConnectorPoint,
  command : ConnectorCommand,
  t : Double,
) -> ConnectorPoint {
  match command {
    Move(_) => { x: 0.0, y: 0.0, }
    Line(p) => csub(p, start)
    Quadratic(c, p) => clerp(csub(c, start), csub(p, c), t)
    Cubic(a, b, p) =>
      clerp(
        clerp(csub(a, start), csub(b, a), t),
        clerp(csub(b, a), csub(p, b), t),
        t,
      )
  }
}

///|
fn cbridge(
  start : ConnectorPoint,
  command : ConnectorCommand,
  hop : ConnectorHop,
) -> (ConnectorPoint, ReadOnlyArray[ConnectorCommand]) {
  let a = cpoint(start, command, hop.lo)
  let b = cpoint(start, command, hop.hi)
  fn unit(t : Double) -> ConnectorPoint {
    let direction = ctangent(start, command, t)
    let length = cdist({ x: 0.0, y: 0.0, }, direction)
    if length < 0.000001 {
      let delta = csub(b, a)
      let length = cdist(a, b)
      { x: delta.x / length, y: delta.y / length, }
    } else {
      { x: direction.x / length, y: direction.y / length, }
    }
  }
  let center = (hop.lo + hop.hi) * 0.5
  let middle = cpoint(start, command, center)
  let first = unit(hop.lo)
  let tangent = unit(center)
  let last = unit(hop.hi)
  let sign = if hop.flip { -1.0 } else { 1.0 }
  let peak : ConnectorPoint = {
    x: middle.x + tangent.y * hop.radius * sign,
    y: middle.y - tangent.x * hop.radius * sign,
  }
  let control = hop.radius * 0.5
  (
    a,
    [
      Cubic(
        { x: a.x + first.x * control, y: a.y + first.y * control, },
        { x: peak.x - tangent.x * control, y: peak.y - tangent.y * control, },
        peak,
      ),
      Cubic(
        { x: peak.x + tangent.x * control, y: peak.y + tangent.y * control, },
        { x: b.x - last.x * control, y: b.y - last.y * control, },
        b,
      ),
    ],
  )
}

///|
priv struct ConnectorDrawing {
  identity : String
  original : String
  path : ConnectorPath
  source : String
  target : String
  family : String
  start_marker : Bool
  end_marker : Bool
  hops : Array[ConnectorHop]
  holes : Array[(ConnectorPoint, Double)]
  key : Int32
}

///|
fn capply_hops(
  drawing : ConnectorDrawing,
  work : ConnectorWork,
) -> (ConnectorPath, Array[Int32])? {
  let hops = drawing.hops.copy()
  hops.sort_by((a, b) => {
    let order = a.command.compare(b.command)
    if order == 0 {
      a.lo.compare(b.lo)
    } else {
      order
    }
  })
  let commands : Array[ConnectorCommand] = []
  let bridges : Array[Int32] = []
  for index, command in drawing.path.commands {
    if !work.charge(2) {
      return None
    }
    if command is Move(_) {
      commands.push(command)
      continue
    }
    let start = cend(drawing.path.commands[index - 1])
    let mut previous = 0.0
    for hop in hops {
      if !work.charge(0) {
        return None
      }
      if hop.command != index {
        continue
      }
      commands.push(cslice(start, command, previous, hop.lo))
      for curve in cbridge(start, command, hop).1 {
        bridges.push(commands.length())
        commands.push(curve)
      }
      previous = hop.hi
    }
    if previous < 1.0 {
      commands.push(cslice(start, command, previous, 1.0))
    }
  }
  Some(({ commands: ReadOnlyArray::from_array(commands), }, bridges))
}

///|
priv struct ConnectorProtection {
  box : ConnectorObstacle
  endpoint_attachment : Bool
  masked_connection : String?
}

///|
fn cexempt(
  drawing : ConnectorDrawing,
  protection : ConnectorProtection,
) -> Bool {
  if protection.masked_connection == Some(drawing.identity) {
    return true
  }
  protection.endpoint_attachment &&
  protection.box.owner != "" &&
  (
    protection.box.owner == drawing.source ||
    protection.box.owner == drawing.target
  )
}

///|
fn cattr(attrs : ReadOnlyArray[(String, String)], name : String) -> String? {
  for (key, value) in attrs {
    if key == name {
      return Some(value)
    }
  }
  None
}

///|
fn connector_options_valid(options : ConnectorOptions) -> Bool {
  fn finite(x : Double) -> Bool {
    x == x && x.abs() <= 1000000.0
  }
  finite(options.minimum_approach) &&
  options.minimum_approach >= 0.0 &&
  finite(options.corner_radius) &&
  options.corner_radius > 0.0 &&
  finite(options.bridge_radius) &&
  options.bridge_radius > 0.0 &&
  options.limits.candidates >= 0 &&
  options.limits.subdivisions >= 0 &&
  options.limits.segments >= 0 &&
  options.limits.crossings >= 0 &&
  options.limits.output_units >= 0
}

///|
/// Resolve generated visible connectors once, before ID scoping. Layout data is
/// never mutated. Borders, lifelines, symbols and trace copies are excluded.
fn finalize_connectors(
  root : @writer.Node,
  options : ConnectorOptions,
  diagnostics : Array[@diagrams.Diagnostic],
  obstacles~ : ArrayView[ConnectorObstacle] = [],
  viewport? : (Double, Double, Double, Double),
  resource_prefix~ : String = "",
  supplied~ : Bool = false,
  labels~ : ArrayView[(String, ConnectorObstacle)] = [],
) -> @writer.Node? {
  let work : ConnectorWork = {
    options,
    diagnostics,
    candidates: 0,
    subdivisions: 0,
    segments: 0,
    crossings: 0,
    failed: false,
  }
  if !connector_options_valid(options) {
    work.fail(
      "connector/invalid-option", "Connector distances must be finite and non-negative; radii and budgets must be valid",
    )
    return None
  }
  fn default_viewport() -> (Double, Double, Double, Double)? {
    guard root is Element(_, attrs, _) else { return None }
    guard cattr(attrs, "width") is Some(w) && cattr(attrs, "height") is Some(h) else {
      return None
    }
    let width = @string.parse_double(w) catch { _ => return None }
    let height = @string.parse_double(h) catch { _ => return None }
    Some((0.0, 0.0, width, height))
  }
  let viewport = match viewport {
    Some(value) => Some(value)
    None => default_viewport()
  }
  let protections : Array[ConnectorProtection] = []
  for box in obstacles {
    protections.push({
      box,
      endpoint_attachment: true,
      masked_connection: None,
    })
  }
  for (connection, box) in labels {
    protections.push({
      box,
      endpoint_attachment: false,
      masked_connection: if connection == "" {
        None
      } else {
        Some(connection)
      },
    })
  }
  let drawings : Array[ConnectorDrawing] = []
  fn collect(
    node : @writer.Node,
    parent : String,
    source : String,
    target : String,
    identity : String,
  ) -> Unit {
    guard node is Element(name, attrs, children) else { return }
    let identity = cattr(attrs, "data-connector").unwrap_or(
      cattr(attrs, "data-flowchart-id").unwrap_or(
        cattr(attrs, "data-swimlane-id").unwrap_or(
          cattr(attrs, "data-id").unwrap_or(
            cattr(attrs, "data-member").unwrap_or(
              cattr(attrs, "data-index").unwrap_or(identity),
            ),
          ),
        ),
      ),
    )
    let class = cattr(attrs, "class").unwrap_or("")
    let source = cattr(attrs, "data-from").unwrap_or(
      cattr(attrs, "data-source").unwrap_or(source),
    )
    let target = cattr(attrs, "data-to").unwrap_or(
      cattr(attrs, "data-target").unwrap_or(target),
    )
    let parent = if class != "" { class } else { parent }
    let visible = name == "path" &&
      (
        class == "m-line" ||
        class == "bpmn-connector" ||
        class == "architecture-path" ||
        class.has_prefix("rr-connector ") ||
        class == "data-connector" ||
        class == "swimlane-connector" ||
        class == "flowchart-connector"
      )
    if visible {
      if cattr(attrs, "d") is Some(original) {
        if ConnectorPath::parse(original) is Some(path) {
          let start_marker = cattr(attrs, "marker-start") is Some(_)
          let end_marker = cattr(attrs, "marker-end") is Some(_)
          if supplied &&
            options.style_supplied_bpmn &&
            path.commands.length() > 1 {
            let terminal = options.minimum_approach.max(14.0)
            let first = path.commands[1]
            let last = path.commands[path.commands.length() - 1]
            if (
                start_marker &&
                (
                  !(first is Line(_)) ||
                  cdist(cend(path.commands[0]), cend(first)) < terminal
                )
              ) ||
              (
                end_marker &&
                (
                  !(last is Line(_)) ||
                  cdist(
                    cend(path.commands[path.commands.length() - 2]),
                    cend(last),
                  ) <
                  terminal
                )
              ) {
              work.fail(
                "connector/routing-conflict", "Supplied BPMN path lacks a safe marked approach",
              )
              return
            }
          }
          drawings.push({
            identity: if identity == "" {
              "connector-\{drawings.length()}"
            } else {
              identity
            },
            original,
            path: cstyle(
              cterminal(path, options.minimum_approach, end_marker),
              options,
              start_marker,
              end_marker,
            ),
            source,
            target,
            family: cattr(attrs, "data-owner").unwrap_or(""),
            start_marker,
            end_marker,
            hops: [],
            holes: [],
            key: drawings.length(),
          })
        } else {
          work.fail(
            "connector/routing-conflict", "Unsupported generated connector path",
          )
        }
      }
    }
    if name != "defs" {
      for child in children {
        collect(child, parent, source, target, identity)
      }
    }
  }
  collect(root, "", "", "", "")
  if options.style is Some(style) && style != Elbow {
    for index, drawing in drawings {
      let original = ConnectorPath::parse(drawing.original).unwrap()
      let baseline = cflatten(original, work)
      let mut scale = 1.0
      for attempt in 0..<12 {
        let candidate = cstyle(
          cterminal(original, options.minimum_approach, drawing.end_marker),
          options,
          drawing.start_marker,
          drawing.end_marker,
          scale~,
        )
        let flat = cflatten(candidate, work)
        let mut blocked = false
        for protection in protections {
          let box = protection.box
          if cexempt(drawing, protection) {
            continue
          }
          let mut existing = false
          for segment in baseline {
            if !work.charge(0) {
              return None
            }
            if cintersects(segment.a, segment.b, box) {
              existing = true
              break
            }
          }
          if existing && !(supplied && options.style_supplied_bpmn) {
            continue
          }
          for segment in flat {
            if !work.charge(0) {
              return None
            }
            if cintersects(segment.a, segment.b, box) {
              blocked = true
              break
            }
          }
          if blocked {
            break
          }
        }
        if !blocked {
          drawings[index] = { ..drawing, path: candidate, }
          break
        }
        if attempt == 11 {
          work.fail(
            "connector/routing-conflict",
            "Requested connector curve has no safe corridor: " +
            drawing.identity,
          )
          return None
        }
        scale *= 0.5
      }
    }
  }
  let flats = drawings.map(d => cflatten(d.path, work))
  let preview_flats = flats.copy()
  let extents : Array[(Double, Double, Double, Double)] = []
  for flat in flats {
    let mut left = 1000000000.0
    let mut top = 1000000000.0
    let mut right = -1000000000.0
    let mut bottom = -1000000000.0
    for segment in flat {
      if !work.charge(0) {
        return None
      }
      for p in [segment.a, segment.b] {
        left = left.min(p.x)
        top = top.min(p.y)
        right = right.max(p.x)
        bottom = bottom.max(p.y)
      }
    }
    extents.push((left, top, right, bottom))
  }
  if options.crossing == Bridge {
    for i in 0.. r.y.abs() {
                  a.a.x.min(a.b.x).max(b.a.x.min(b.b.x)) <
                  a.a.x.max(a.b.x).min(b.a.x.max(b.b.x)) - 0.01
                } else {
                  a.a.y.min(a.b.y).max(b.a.y.min(b.b.y)) <
                  a.a.y.max(a.b.y).min(b.a.y.max(b.b.y)) - 0.01
                }
                if overlap {
                  work.fail(
                    "connector/routing-conflict",
                    "Unrelated connector segments overlap: \{over.original} / \{under.original}",
                  )
                  return None
                }
              }
              continue
            }
            let delta = csub(b.a, a.a)
            let t = ccross(delta, s) / denominator
            let u = ccross(delta, r) / denominator
            if t < -0.000001 || t > 1.000001 || u < -0.000001 || u > 1.000001 {
              continue
            }
            let point = clerp(a.a, a.b, t)
            let ends = [
              cend(over.path.commands[0]),
              cend(over.path.commands[over.path.commands.length() - 1]),
              cend(under.path.commands[0]),
              cend(under.path.commands[under.path.commands.length() - 1]),
            ]
            if ends.iter().any(p => cdist(p, point) < 0.5) {
              continue
            }
            let shared = (
                over.source != "" &&
                (over.source == under.source || over.source == under.target)
              ) ||
              (
                over.target != "" &&
                (over.target == under.source || over.target == under.target)
              )
            if shared &&
              ends
              .iter()
              .any(p => {
                cdist(p, point) <=
                options.minimum_approach.max(14.0) +
                8.0 +
                15.0 +
                options.bridge_radius * 2.0 +
                4.0
              }) {
              continue
            }
            if seen.iter().any(p => cdist(p, point) < 0.5) {
              continue
            }
            seen.push(point)
            fn candidate(
              drawing : ConnectorDrawing,
              segment : ConnectorFlat,
              fraction : Double,
            ) -> (ConnectorHop, Array[(Int32, ConnectorHop)])? {
              let command = drawing.path.commands[segment.command]
              let start = cend(drawing.path.commands[segment.command - 1])
              let at = segment.lo + (segment.hi - segment.lo) * fraction
              let chord = cdist(segment.a, segment.b) /
                (segment.hi - segment.lo)
              if chord < 0.0001 {
                return None
              }
              let mut radius = options.bridge_radius
                .min(at * chord * 0.45)
                .min((1.0 - at) * chord * 0.45)
              for prior in drawing.hops {
                if !work.charge(0) {
                  return None
                }
                if prior.command != segment.command {
                  continue
                }
                let center = (prior.lo + prior.hi) * 0.5
                radius = radius.min((at - center).abs() * chord * 0.45)
              }
              if radius < 2.0 {
                return None
              }
              let lo = (at - radius / chord).max(0.0)
              let hi = (at + radius / chord).min(1.0)
              let adjustments : Array[(Int32, ConnectorHop)] = []
              for index, prior in drawing.hops {
                if !work.charge(0) {
                  return None
                }
                if prior.command != segment.command {
                  continue
                }
                let center = (prior.lo + prior.hi) * 0.5
                let allowed = (at - center).abs() * chord * 0.45
                if allowed < 2.0 {
                  return None
                }
                if prior.radius > allowed {
                  let half = (prior.hi - prior.lo) *
                    0.5 *
                    allowed /
                    prior.radius
                  adjustments.push(
                    (
                      index,
                      {
                        ..prior,
                        lo: center - half,
                        hi: center + half,
                        radius: allowed,
                      },
                    ),
                  )
                }
              }
              let before = cpoint(start, command, lo)
              let after = cpoint(start, command, hi)
              if (
                  segment.command == 1 &&
                  drawing.start_marker &&
                  cdist(start, before) < options.minimum_approach
                ) ||
                (
                  segment.command == drawing.path.commands.length() - 1 &&
                  drawing.end_marker &&
                  cdist(after, cend(command)) < options.minimum_approach
                ) {
                return None
              }
              Some(
                (
                  { command: segment.command, lo, hi, radius, flip: false, },
                  adjustments,
                ),
              )
            }
            fn fit_underpass(
              drawing : ConnectorDrawing,
              pair : (ConnectorHop, Array[(Int32, ConnectorHop)]),
            ) -> (ConnectorHop, Array[(Int32, ConnectorHop)])? {
              let (hop, adjustments) = pair
              let start = cend(drawing.path.commands[0])
              let end = cend(
                drawing.path.commands[drawing.path.commands.length() - 1],
              )
              let first = if drawing.start_marker {
                options.minimum_approach.max(14.0)
              } else {
                2.0
              }
              let last = if drawing.end_marker {
                options.minimum_approach.max(14.0)
              } else {
                2.0
              }
              let available = (cdist(start, point) - first).min(
                cdist(end, point) - last,
              )
              let radius = hop.radius.min((available - 2.5) / 1.5)
              if radius < 2.0 {
                return None
              }
              let center = (hop.lo + hop.hi) * 0.5
              let half = (hop.hi - hop.lo) * 0.5 * radius / hop.radius
              Some(
                (
                  { ..hop, lo: center - half, hi: center + half, radius, },
                  adjustments,
                ),
              )
            }
            let preferred = candidate(over, a, t).bind(pair => {
              fit_underpass(under, pair)
            })
            let (owner, beneath, hop, adjustments) = match preferred {
              Some((hop, adjustments)) => (over, under, hop, adjustments)
              None =>
                match
                  candidate(under, b, u).bind(pair => fit_underpass(over, pair)) {
                  Some((hop, adjustments)) => (under, over, hop, adjustments)
                  None => {
                    work.fail(
                      "connector/routing-conflict",
                      "No safe bridge at \{cp(point)} on \{over.original} crossing \{under.original}",
                    )
                    return None
                  }
                }
            }
            let mut hop = hop
            // Bound the hop against every third routed connector before it is
            // committed. Reducing a radius retains a real arch, never an elbow.
            for attempt in 0..<24 {
              let start = cend(owner.path.commands[hop.command - 1])
              let command = owner.path.commands[hop.command]
              let (entry, curves) = cbridge(start, command, hop)
              let bridge_path : ConnectorPath = {
                commands: ReadOnlyArray::from_array([Move(entry), ..curves]),
              }
              let pieces = cflatten(bridge_path, work)
              let mut conflict = false
              for piece in pieces {
                if viewport is Some((x, y, width, height)) &&
                  [piece.a, piece.b]
                  .iter()
                  .any(p => {
                    p.x < x - 0.05 ||
                    p.y < y - 0.05 ||
                    p.x > x + width + 0.05 ||
                    p.y > y + height + 0.05
                  }) {
                  conflict = true
                  break
                }
                for protection in protections {
                  if !work.charge(0) {
                    return None
                  }
                  if cexempt(owner, protection) {
                    continue
                  }
                  if cintersects(piece.a, piece.b, protection.box) {
                    conflict = true
                    break
                  }
                }
                if conflict {
                  break
                }
              }
              for k in 0.. bounds.2 ||
                  point.y + hop.radius * 2.0 < bounds.1 ||
                  point.y - hop.radius * 2.0 > bounds.3 {
                  continue
                }
                for a in pieces {
                  for b in preview_flats[k] {
                    if !work.charge(0) {
                      return None
                    }
                    let r = csub(a.b, a.a)
                    let u = csub(b.b, b.a)
                    let denominator = ccross(r, u)
                    if denominator.abs() < 0.000001 {
                      continue
                    }
                    let delta = csub(b.a, a.a)
                    let t = ccross(delta, u) / denominator
                    let v = ccross(delta, r) / denominator
                    if t < -0.000001 ||
                      t > 1.000001 ||
                      v < -0.000001 ||
                      v > 1.000001 {
                      continue
                    }
                    let crossing = clerp(a.a, a.b, t)
                    let intended = k == beneath.key &&
                      cdist(point, crossing) <= hop.radius * 1.5 + 1.0
                    if !intended &&
                      !drawings[k].holes
                      .iter()
                      .any(h => cdist(h.0, crossing) <= h.1 - 1.5) {
                      conflict = true
                      break
                    }
                  }
                  if conflict {
                    break
                  }
                }
                if conflict {
                  break
                }
              }
              if !conflict {
                break
              }
              if !hop.flip {
                hop = { ..hop, flip: true, }
                continue
              }
              let radius = (hop.radius * 0.65).max(2.0)
              if radius >= hop.radius {
                work.fail(
                  "connector/routing-conflict", "Bridge has no safe corridor past a third connector",
                )
                return None
              }
              if attempt == 23 {
                work.fail(
                  "connector/limit", "Bridge corridor refinement budget exhausted",
                )
                return None
              }
              let center = (hop.lo + hop.hi) * 0.5
              let half = (hop.hi - hop.lo) * 0.5 * radius / hop.radius
              hop = {
                ..hop,
                lo: center - half,
                hi: center + half,
                radius,
                flip: false,
              }
            }
            if !work.charge(3) {
              return None
            }
            for (index, adjusted) in adjustments {
              owner.hops[index] = adjusted
            }
            owner.hops.push(hop)
            beneath.holes.push((point, hop.radius * 1.5 + 2.5))
            guard capply_hops(owner, work) is Some((preview, _)) else {
              return None
            }
            preview_flats[owner.key] = cflatten(preview, work)
            let mut left = 1000000000.0
            let mut top = 1000000000.0
            let mut right = -1000000000.0
            let mut bottom = -1000000000.0
            for segment in preview_flats[owner.key] {
              if !work.charge(0) {
                return None
              }
              for p in [segment.a, segment.b] {
                left = left.min(p.x)
                top = top.min(p.y)
                right = right.max(p.x)
                bottom = bottom.max(p.y)
              }
            }
            extents[owner.key] = (left, top, right, bottom)
          }
        }
      }
    }
  }
  if work.failed {
    return None
  }
  let defs : Array[@writer.Node] = []
  let resolved = Map([])
  let final_segments : Array[Array[ConnectorFlat]] = []
  let bridge_commands : Array[Array[Int32]] = []
  for drawing in drawings {
    guard capply_hops(drawing, work) is Some((resolved_path, bridges)) else {
      return None
    }
    let commands = resolved_path.commands
    let original = ConnectorPath::parse(drawing.original).unwrap()
    let original_flat = cflatten(original, work)
    let final_flat = cflatten(resolved_path, work)
    final_segments.push(final_flat)
    bridge_commands.push(bridges)
    for segment in final_flat {
      if viewport is Some((x, y, width, height)) &&
        [segment.a, segment.b]
        .iter()
        .any(p => {
          p.x < x - 0.05 ||
          p.y < y - 0.05 ||
          p.x > x + width + 0.05 ||
          p.y > y + height + 0.05
        }) {
        work.fail(
          "connector/routing-conflict",
          "Connector outside viewport: " +
          drawing.identity +
          " " +
          @debug.to_string((segment.a, segment.b, viewport)),
        )
        return None
      }
      let command = resolved_path.commands[segment.command]
      if original.commands.contains(command) &&
        !(supplied && options.style_supplied_bpmn) {
        continue
      }
      for protection in protections {
        let obstacle = protection.box
        if !work.charge(0) {
          return None
        }
        if cexempt(drawing, protection) {
          continue
        }
        if !cintersects(segment.a, segment.b, obstacle) {
          continue
        }
        // Existing masked labels may sit on their original path. They do not
        // grant an exemption to a newly inserted bridge.
        let bridge = command is Cubic(_, _, _) && !drawing.hops.is_empty()
        let mut existing = false
        if !bridge && !(supplied && options.style_supplied_bpmn) {
          for segment in original_flat {
            if !work.charge(0) {
              return None
            }
            if cintersects(segment.a, segment.b, obstacle) {
              existing = true
              break
            }
          }
        }
        if bridge || !existing {
          work.fail(
            "connector/routing-conflict",
            "Styled connector intersects protected content: " +
            drawing.identity +
            " / " +
            obstacle.owner,
          )
          return None
        }
      }
    }
    for _ in commands {
      if !work.charge(2) {
        return None
      }
    }
    let final_path = if drawing.hops.is_empty() &&
      drawing.path == ConnectorPath::parse(drawing.original).unwrap() {
      drawing.original
    } else {
      resolved_path.svg()
    }
    let mask = if drawing.holes.is_empty() {
      None
    } else {
      let id = resource_prefix + "connector-underpass-\{drawing.key}"
      let (x, y, width, height) = viewport.unwrap_or(
        (-1000000.0, -1000000.0, 2000000.0, 2000000.0),
      )
      let bounds = [
        ("x", cn(x)),
        ("y", cn(y)),
        ("width", cn(width)),
        ("height", cn(height)),
      ]
      let children = [
        @writer.element("rect", attrs=[..bounds, ("fill", "white")]),
      ]
      for (point, radius) in drawing.holes {
        children.push(
          @writer.element("circle", attrs=[
            ("cx", cn(point.x)),
            ("cy", cn(point.y)),
            ("r", cn(radius)),
            ("fill", "black"),
          ]),
        )
      }
      defs.push(
        @writer.element(
          "mask",
          attrs=[("id", id), ("maskUnits", "userSpaceOnUse"), ..bounds],
          children~,
        ),
      )
      Some("url(#\{id})")
    }
    resolved[drawing.key] = (final_path, mask)
  }
  // A bridge is new geometry. It may not introduce an unmasked crossing with
  // a third connection that did not intersect the original routed line.
  for i in 0.. 1.000001 || v < -0.000001 || v > 1.000001 {
            continue
          }
          let point = clerp(a.a, a.b, t)
          let hidden = drawings[i].holes
            .iter()
            .concat(drawings[j].holes.iter())
            .any(h => cdist(h.0, point) <= h.1 - 1.5)
          if hidden {
            continue
          }
          let over = drawings[i]
          let under = drawings[j]
          let shared = (
              over.source != "" &&
              (over.source == under.source || over.source == under.target)
            ) ||
            (
              over.target != "" &&
              (over.target == under.source || over.target == under.target)
            )
          let ends = [
            cend(over.path.commands[0]),
            cend(over.path.commands[over.path.commands.length() - 1]),
            cend(under.path.commands[0]),
            cend(under.path.commands[under.path.commands.length() - 1]),
          ]
          if shared && ends.iter().any(p => cdist(p, point) < 0.5) {
            continue
          }
          work.fail(
            "connector/routing-conflict",
            "Bridge intersects another connector without an underpass: " +
            over.identity +
            " / " +
            under.identity,
          )
          return None
        }
      }
    }
  }
  let mut ordinal = 0
  fn rewrite(node : @writer.Node, parent : String) -> @writer.Node {
    guard node is Element(name, attrs, children) else { return node }
    let class = cattr(attrs, "class").unwrap_or("")
    let parent = if class != "" { class } else { parent }
    let visible = name == "path" &&
      (
        class == "m-line" ||
        class == "bpmn-connector" ||
        class == "architecture-path" ||
        class.has_prefix("rr-connector ") ||
        class == "data-connector" ||
        class == "swimlane-connector" ||
        class == "flowchart-connector"
      )
    let new_attrs = attrs.iter().to_array()
    if visible {
      let key = ordinal
      ordinal += 1
      if resolved.get(key) is Some((final_path, mask)) {
        for i in 0.. rewrite(c, parent)).iter().to_array()
    }
    if name == "svg" {
      new_attrs.push(("data-connector-options", @debug.to_string(options)))
    }
    if name == "svg" && !defs.is_empty() {
      new_children.push(@writer.element("defs", children=defs))
    }
    @writer.element(name, attrs=new_attrs, children=new_children)
  }
  let result = rewrite(root, "")
  if @writer.to_string(result).length() > options.limits.output_units {
    work.fail("connector/limit", "Connector SVG output budget exhausted")
    None
  } else {
    Some(result)
  }
}

///|
pub extend ConnectorStyle with Eq::{equal, not_equal}

///|
pub extend ConnectorStyle with @debug.Debug::{to_repr}

///|
pub extend CrossingMode with Eq::{equal, not_equal}

///|
pub extend CrossingMode with @debug.Debug::{to_repr}

///|
pub extend ConnectorLimits with Eq::{equal, not_equal}

///|
pub extend ConnectorLimits with @debug.Debug::{to_repr}

///|
pub extend ConnectorOptions with Eq::{equal, not_equal}

///|
pub extend ConnectorOptions with @debug.Debug::{to_repr}

///|
pub extend ConnectorPoint with Eq::{equal, not_equal}

///|
pub extend ConnectorPoint with @debug.Debug::{to_repr}

///|
pub extend ConnectorCommand with Eq::{equal, not_equal}

///|
pub extend ConnectorCommand with @debug.Debug::{to_repr}

///|
pub extend ConnectorPath with Eq::{equal, not_equal}

///|
pub extend ConnectorPath with @debug.Debug::{to_repr}