module MotionKit
  module_function

  def siblings(view)
    case view
    when CALayer
      view.superlayer ? view.superlayer.sublayers : []
    else
      view.superview ? view.superview.subviews : []
    end
  end

  def children(view)
    case view
    when CALayer
      view.sublayers
    else
      view.subviews
    end
  end

  def parent(view)
    case view
    when CALayer
      view.superlayer
    else
      view.superview
    end
  end

  # - check view
  # - check subviews (unless 'skip' is provided)
  # - check siblings (skipping 'view')
  # - go up to parent and repeat, skipping children
  def nearest(view, skip=nil, &test)
    return nil if view.nil?

    if test.call(view)
      return view
    end

    children = MotionKit.children(view)
    siblings = MotionKit.siblings(view)
    parent = MotionKit.parent(view)

    found = nil

    # only check the children starting at the "root", e.g. nearest hasn't been
    # called recursively.
    if !skip || skip == parent
      children.each do |child|
        found = nearest(child, &test)
        break if found
      end
      return found if found
    end

    # siblings are closer than parents
    # passing 'parent' means only check self and children
    unless skip == parent
      siblings.each do |sibling|
        found = (sibling != view && nearest(sibling, parent, &test))
        break if found
      end
    end

    if found
      found
    elsif skip != parent
      nearest(parent, true, &test)
    end
  end

end
