// clay_input.cm - Input handling for clay UI
// Separates input concerns from layout/rendering

var geometry = use('geometry')
var clay = use('clay')

var clay_input = {}

function rect_contains(node, pos) {
  var bb = geometry.rect_move(node.boundingbox, node.config.offset || {x: 0, y: 0})
  return geometry.rect_point_inside(bb, pos)
}

function pointer_enabled(node) {
  var p = node.config.pointer_events
  if (!p || p == 'auto') return true
  if (p == 'none') return false
  return true
}

function should_skip_children(node) {
  var p = node.config.pointer_events
  if (p == 'box-only') return true
  return false
}

function should_skip_self(node) {
  var p = node.config.pointer_events
  if (p == 'box-none') return true
  return false
}

function find_path(node, path, pos) {
  if (!pointer_enabled(node)) return null
  if (!rect_contains(node, pos)) return null

  var next_path = array(path, node)

  if (node[clay.CHILDREN] && !should_skip_children(node)) {
    // Children drawn later should be tested first; reverse if your render order differs
    for (var i = length(node[clay.CHILDREN]) - 1; i >= 0; i--) {
      var child = node[clay.CHILDREN][i]
      var child_path = find_path(child, next_path, pos)
      if (child_path) return child_path
    }
  }

  if (should_skip_self(node)) return null
  return next_path
}

clay_input.deepest = function deepest(tree_root, pos) {
  var path = find_path(tree_root, [], pos) || []
  var deepest = length(path) ? path[length(path) - 1] : null
  return deepest
}

clay_input.bubble = function bubble(deepest, prop) {
  var current = deepest
  while (current) {
    if (current.config && current.config[prop])
      return current
    current = current[clay.PARENT]
  }
  return null
}

clay_input.click = function click(tree_root, mousepos, button = 'left') {
  var deepest = clay_input.deepest(tree_root, mousepos)
  var action_target = clay_input.bubble(deepest, 'action')
  if (action_target && action_target.config.action) action_target.config.action()
}

clay_input.get_actionable = function get_actionable(tree_root) {
  var actionable = []
  function walk(node) {
    if (node.config.action) push(actionable, node)
    if (node[clay.CHILDREN])
      arrfor(node[clay.CHILDREN], walk)
  }
  walk(tree_root)
  return actionable
}

clay_input.filter = function filter(tree_root, predicate) {
  var results = []
  function rec(node) {
    if (predicate(node)) push(results, node)
    if (node[clay.CHILDREN])
      arrfor(node[clay.CHILDREN], rec)
  }
  rec(tree_root)
  return results
}

clay_input.find_by_id = function find_by_id(tree_root, id) {
  function rec(node) {
    if (node.id == id) return node
    if (node[clay.CHILDREN])
      arrfor(node[clay.CHILDREN], function(child) {
        var f = rec(child)
        if (f) return f
      })
    return null
  }
  return rec(tree_root)
}

return clay_input
