# Observable mixin                                                            
#
# Adapted from various sources by Brian Amberg
#
# FIXME: Name sources

# Mixin that allows closures to be registered with certain events
#
# Usage:
#  class Observed
#    include Observable
#
#    def foo
#      signal_event(:foo, 'Foo happened')
#    end
#  end
#
#  class Observer
#    def initialize(observed)
#      observed.register(:foo) do | o, *args | 
#        puts "Observed object #{o} signalled foo with arguments #{args.inspect}"
#      end
#    end
#  end
#
#  observed = Observed.new
#  observer = Observer.new(observed)
#  observed.foo
#--
# FIXME: Include optional ID for better deregistration.
module Observable

  # Register an event with the observed class
  #  register(:foo) do | observed, *args | [do something] end
  def register(event=nil, id=nil, &callback)
    @observers ||= Hash.new
    @observers[event] ||= []
    @observers[event] << [id, callback]
    self
  end

  # Deregister an event with the observed class
  #  
  #  deregister(:foo, &callback)
  def deregister(event=nil, id=nil, &callback)
    @observers ||= Hash.new
    @observers[event] ||= []
    @observers.delete_if { | (a_id, a_callback) | (id && (a_id == id)) || (a_callback == callback) }
    self
  end

  protected
  # Signal an event to all observers
  #  signal_event(:foo)
  def signal_event(event = nil, *args)
    @observers ||= Hash.new
    @observers[event] ||= []
    @observers[event].each do | (id, callback) | callback.call(self, *args)  end
  end
end