class KVOTestSimple
  
  attr_reader :first_name
  
  attr_accessor :second_name
    
  def initialize
    @some_ivar_we_can_set = nil
  end
  
  def first_name=(first_name)
    @first_name = "setting_#{first_name}"
  end

end


class KVOMultipartClass
  attr_accessor :teacher, :students
end

class KVOMultipartPerson
  attr_accessor :name, :car
end

class KVOMultipartCar
  attr_accessor :model
end


class KVOTestRepeaterA
  attr_accessor :b
end

class KVOTestRepeaterB
  attr_accessor :c
end

class KVOTestRepeaterC
  attr_accessor :d
end

class KVOTestRepeaterD
  attr_accessor :e
end

class KVOTestRepeaterE
  attr_accessor :f
end

class KVOTestRepeaterF
  attr_accessor :g
end

describe "Observable#observe" do
  
  it "should allow a simple observer to be added" do
    a = KVOTestSimple.new
    
    old_value = nil
    new_value = nil
    did_see_notification = false
    
    a.observe :first_name do |changes|
      did_see_notification = true
      old_value = changes[:old]
      new_value = changes[:new]
    end
    
    a.first_name = 'adam'
    a.first_name.should == 'setting_adam'
    
    did_see_notification.should == true
    
    old_value.should == nil
    new_value.should == 'setting_adam'
  end
  
  
  
  it "should only observe and post notifications for observed keys" do
    b = KVOTestSimple.new
    
    did_see_notification = false
    
    b.observe :first_name do |changes|
      did_see_notification = true
    end
    
    b.second_name = "adam"
    b.second_name.should == "adam"
    did_see_notification.should == false
    
  end
  
  
  
  it "should allow multiple observers for a single key" do
    c = KVOTestSimple.new
    d = KVOTestSimple.new
    
    first_saw = false
    second_saw = false
    
    c.observe :first_name do |changes|
      first_saw = true
    end
    
    c.observe :first_name do |changes|
      second_saw = true
    end
    
    c.first_name = "some_name"
    c.first_name.should == "setting_some_name"
    
    first_saw.should == true
    second_saw.should == true

  end

  
  
  it "should be possible to observe instance variables" do
    e = KVOTestSimple.new
    
    old_value = nil
    new_value = nil
    did_see_notification = false
    
    e.observe :some_ivar_we_can_set do |changes|
      did_see_notification = true
      old_value = changes[:old]
      new_value = changes[:new]
    end
    
    e.set_attribute :some_ivar_we_can_set, 200
    
    did_see_notification.should == true
    e.get_attribute(:some_ivar_we_can_set).should == 200
    
    old_value.should == nil
    new_value.should == 200
    
  end
  
  
  
  it "should allow observers for multipart keys" do
    the_class = KVOMultipartClass.new
    fred = KVOMultipartPerson.new
    
    the_class.teacher = fred
    did_see_observation = false
    
    the_class.observe 'teacher.name' do |change|
      did_see_observation = true
    end
    
    fred.name = "Fred"
    
    the_class.get_path('teacher.name').should == "Fred"
    did_see_observation.should == true
  end
  
  
  
  it "should allow a three part key" do
    cls = KVOMultipartClass.new
    fred = KVOMultipartPerson.new
    car = KVOMultipartCar.new
    
    did_see_observation = false
    
    cls.teacher = fred
    fred.car = car
    
    cls.observe('teacher.car.model') do |info|
      info[:path].should == "teacher.car.model"
      did_see_observation = true
    end
    
    car.model = "Jaguar"
    
    did_see_observation.should == true
    cls.teacher.car.model.should == "Jaguar"
  end
  
  
  
  it "should allow long observer paths" do
    a = KVOTestRepeaterA.new
    a.set_path 'b', KVOTestRepeaterB.new
    a.set_path 'b.c', KVOTestRepeaterC.new
    a.set_path 'b.c.d', KVOTestRepeaterD.new
    a.set_path 'b.c.d.e', KVOTestRepeaterE.new
    a.set_path 'b.c.d.e.f', KVOTestRepeaterF.new
    a.set_path 'b.c.d.e.f.g', "Hey G"
    
    a.b.c.d.e.f.g.should == "Hey G"
    did_see_observation = false

    a.observe('b.c.d.e.f.g') do |info|
      did_see_observation = true
      
      info[:path].should == 'b.c'
      info[:object].class.should == KVOTestRepeaterA
    end
    
    a.b.c = nil
    did_see_observation.should == true
    
  end
  
  
  
  it "should allow long observer paths, part2" do
    a = KVOTestRepeaterA.new
    a.set_path 'b', KVOTestRepeaterB.new
    a.set_path 'b.c', KVOTestRepeaterC.new
    a.set_path 'b.c.d', KVOTestRepeaterD.new
    a.set_path 'b.c.d.e', KVOTestRepeaterE.new
    a.set_path 'b.c.d.e.f', KVOTestRepeaterF.new
    a.set_path 'b.c.d.e.f.g', "Hey G"
    
    did_see_observation = false

    a.observe('b.c.d.e.f.g') do |info|
      did_see_observation = true
      
      info[:path].should == 'b.c.d'
      info[:object].class.should == KVOTestRepeaterA
      info[:new].should == nil
    end
    
    a.b.c.d = nil
    did_see_observation.should == true
    
  end
  
  
  
  it "should allow long observer paths, part3" do
    a = KVOTestRepeaterA.new
    a.set_path 'b', KVOTestRepeaterB.new
    a.set_path 'b.c', KVOTestRepeaterC.new
    a.set_path 'b.c.d', KVOTestRepeaterD.new
    a.set_path 'b.c.d.e', KVOTestRepeaterE.new
    a.set_path 'b.c.d.e.f', KVOTestRepeaterF.new
    a.set_path 'b.c.d.e.f.g', "Hey G"
    
    did_see_observation = false

    a.observe('b.c.d.e.f.g') do |info|
      did_see_observation = true
      
      info[:path].should == 'b.c.d.e.f.g'
      info[:object].class.should == KVOTestRepeaterA
      info[:new].should == 100
    end
    
    a.b.c.d.e.f.g = 100
    did_see_observation.should == true
    
  end
  
  
  
  it "should allow long observer paths, part3" do
    a = KVOTestRepeaterA.new
    a.set_path 'b', KVOTestRepeaterB.new
    a.set_path 'b.c', KVOTestRepeaterC.new
    a.set_path 'b.c.d', KVOTestRepeaterD.new
    a.set_path 'b.c.d.e', KVOTestRepeaterE.new
    a.set_path 'b.c.d.e.f', KVOTestRepeaterF.new
    a.set_path 'b.c.d.e.f.g', "Hey G"
    
    did_see_observation = false

    a.observe('b.c.d.e.f.g') do |info|
      did_see_observation = true
      
      info[:path].should == 'b'
      info[:object].class.should == KVOTestRepeaterA
      info[:new].should == 200
    end
    
    a.b = 200
    did_see_observation.should == true
    
  end
  
end