///|
// Node id helpers shared by renderer element conversion and layout adjustments.

///|
fn node_id_is_tag(node_id : String, tag : String) -> Bool {
  node_id == tag ||
  node_id.has_prefix(tag + "#") ||
  node_id.has_prefix(tag + ".")
}

///|
/// Create node ID from element
fn make_node_id(elem : @html.Element) -> String {
  match elem.id {
    Some(id) => elem.tag + "#" + id
    None =>
      if elem.classes.length() > 0 {
        elem.tag + "." + elem.classes[0]
      } else {
        elem.tag
      }
  }
}

///|
/// Internal attribute the dynamic-rendering path stamps onto a render
/// `@html.Element` to carry its originating `@dom.DomTree` node id through to the
/// render `@node.Node` (see `attach_dom_id`). It lives only on the derived render
/// document, never on the DomTree, so it is not serialized into `html_content`;
/// the cascade ignores it (`html_to_selector_element` filters it out).
pub let crater_dom_id_attr : String = "data-crater-domid"

///|
/// Parse a non-negative integer, or `None` on any non-digit. Dependency-free so
/// `core`-adjacent render code keeps a small import surface.
fn parse_dom_id(s : String) -> Int? {
  if s.length() == 0 {
    return None
  }
  let mut acc = 0
  for c in s {
    let d = c.to_int() - '0'.to_int()
    if d < 0 || d > 9 {
      return None
    }
    acc = acc * 10 + d
  }
  Some(acc)
}

///|
/// Copy the originating DomTree node id (if the element carries the internal
/// `data-crater-domid` attribute) onto the freshly-built render node.
fn attach_dom_id(node : @node.Node, elem : @html.Element) -> @node.Node {
  match elem.attributes.get(crater_dom_id_attr) {
    Some(s) => node.set_dom_id(parse_dom_id(s))
    None => ()
  }
  node
}