///|
/// A graph of motif nodes used to coordinate repeated and connected decorations.
pub(all) struct MotifGraph {
  nodes : Array[Motif]
  edges : Array[(Int, Int)]
} derive(Debug)

///|
pub fn MotifGraph::new() -> MotifGraph {
  { nodes: [], edges: [] }
}

///|
pub fn MotifGraph::add_node(self : MotifGraph, motif : Motif) -> Int {
  self.nodes.push(motif)
  self.nodes.length() - 1
}

///|
pub fn MotifGraph::connect(self : MotifGraph, left : Int, right : Int) -> Bool {
  if left < 0 ||
    right < 0 ||
    left >= self.nodes.length() ||
    right >= self.nodes.length() {
    false
  } else {
    self.edges.push((left, right))
    true
  }
}

///|
pub fn MotifGraph::neighbors(self : MotifGraph, node : Int) -> Array[Int] {
  let result = []
  for edge in self.edges {
    if edge.0 == node {
      result.push(edge.1)
    } else if edge.1 == node {
      result.push(edge.0)
    }
  }
  result
}

///|
pub fn MotifGraph::connected_components(self : MotifGraph) -> Array[Array[Int]] {
  let visited = []
  for _ in 0.. 0 {
        let node = queue.remove(0)
        component.push(node)
        for neighbor in self.neighbors(node) {
          if !visited[neighbor] {
            visited[neighbor] = true
            queue.push(neighbor)
          }
        }
      }
      components.push(component)
    }
  }
  components
}

///|
pub fn MotifGraph::bounds(self : MotifGraph) -> Rect {
  let points = []
  for node in self.nodes {
    points.push(node.anchor)
  }
  bounds_of_points(points)
}

///|
pub fn MotifGraph::translate(self : MotifGraph, offset : Vec2) -> MotifGraph {
  let nodes = []
  for node in self.nodes {
    nodes.push(
      node.placed(
        node.anchor.x + offset.x,
        node.anchor.y + offset.y,
        node.scale,
        node.rotation,
      ),
    )
  }
  { nodes, edges: self.edges }
}

///|
pub fn MotifGraph::to_document(
  self : MotifGraph,
  width : Double,
  height : Double,
  background : Color,
) -> SvgDocument {
  let document = SvgDocument::new(width, height)
  document.add(
    SvgElement::SvgPath(
      Path::rect(width, height),
      SvgStyle::new(fill=background.to_hex(), stroke="none"),
    ),
  )
  for edge in self.edges {
    let left = self.nodes[edge.0].anchor
    let right = self.nodes[edge.1].anchor
    document.add_line(
      left,
      right,
      SvgStyle::new(fill="none", stroke="#999999", stroke_width=0.5),
    )
  }
  for node in self.nodes {
    document.add(SvgElement::SvgPath(node.transformed_path(), node.style))
  }
  document
}