require 'observable'

module FoxTails

# Classes which include this module must define an instance method
# #connect_to_target which establishes the connection between the
# object and the target.
module FTTargeted

  # The target arg is either a Fox object or a Proc or Method returning a Fox
  # object
  def init_target(target = nil)
    @target = target
  end

  def send_target(*args, &block)
    @target.send(*args, &block) if @target
  end

  def create
    super

    if @target.is_a? Proc or @target.is_a? Method
      @target = @target.call
    end

    connect_to_target if @target
  end
end

# FTStateTargeted replaces the standard tgt,sel mechanism with symbolic
# variable access. Argument lists are the same as in Fox, but with the
# tgt, sel arguments replaced with a target object (or proc/method returning
# an object), a state variable in the target, and possibly additional args.
#
# Class which include this module must define an instance method
# #target_arg_range which returns the range of positions in the argument
# list which take the place of tgt,sel.
module FTStateTargeted
  include FTTargeted

  def initialize(*args)
    range = target_arg_range
    target_args = args[range]
    args[range] = [nil, 0]     # Substitute no-op tgt,sel args for FX classes

    super(*args)

    init_target(*target_args)
  end

  # state must be name of observable variable in target
  def init_target(target = nil, state = :none)
    super target
    @state = state
    @state_setter = "#{state}=".intern
    @state_getter = "#{state}".intern
    @state_when   = "when_#{state}".intern
  end

  def set_target_state(value)
    send_target(@state_setter, value)
  end

  def get_target_state
    send_target(@state_getter)
  end

  def when_target_state(pattern, &block)
    send_target(@state_when, pattern, &block)
  end
end

module FTListStateTargeted
  include FTStateTargeted

  def init_target(target = nil, list = :none, state = :none)
    super target, state

    @list = list
    @list_setter = "#{list}=".intern
    @list_getter = "#{list}".intern
    @list_when   = "when_#{list}".intern
  end

  def set_target_list(value)
    send_target(@list_setter, value)
  end

  def get_target_list
    send_target(@list_getter)
  end

  def when_target_list(pattern, &block)
    send_target(@list_when, pattern, &block)
  end
end

end