// ============================================================
// Advanced Nodes: Delay, WaitUntil, LimitedSequence
// ============================================================

///|
pub fn delay_node(child : Node, delay_ticks : Int) -> Node {
  let current_delay : Ref[Int] = Ref::new(0)
  let tick = fn(bb) {
    if current_delay.get() < delay_ticks {
      current_delay.set(current_delay.get() + 1)
      return Status::BTRunning
    }
    let status = child.tick(bb)
    if status != Status::BTRunning {
      current_delay.set(0)
    }
    status
  }
  let reset = fn() {
    current_delay.set(0)
    child.reset()
  }
  Node::new(tick, reset)
}

///|
pub fn wait_until_node(condition : (Blackboard) -> Bool) -> Node {
  let tick = fn(bb) {
    if condition(bb) {
      Status::BTSuccess
    } else {
      Status::BTRunning
    }
  }
  let reset = fn() { () }
  Node::new(tick, reset)
}

///|
pub fn limited_sequence(children : Array[Node], limit : Int) -> Node {
  let count : Ref[Int] = Ref::new(0)
  let running_child : Ref[Int] = Ref::new(0)

  let tick = fn(bb) {
    if count.get() >= limit {
      return Status::BTFailure
    }

    let mut i = running_child.get()
    while i < children.length() {
      let child = children[i]
      let status = child.tick(bb)
      match status {
        Status::BTRunning => {
          running_child.set(i)
          return Status::BTRunning
        }
        Status::BTFailure => {
          for c in children {
            c.reset()
          }
          running_child.set(0)
          return Status::BTFailure
        }
        Status::BTSuccess => i = i + 1
      }
    }
    running_child.set(0)
    count.set(count.get() + 1)
    Status::BTSuccess
  }

  let reset = fn() {
    count.set(0)
    running_child.set(0)
    for c in children {
      c.reset()
    }
  }
  Node::new(tick, reset)
}