require 'spec/spec_helper'

describe "Recurring Events" do

  FEB       = DateTime.new(2009, 2)
  MARCH     = DateTime.new(2009, 3)
  APRIL     = DateTime.new(2009, 4)
  MARCH_29  = DateTime.new(2009, 3, 29, 19, 30)
  APRIL_19  = DateTime.new(2009, 4, 19)
  APRIL_13  = DateTime.new(2009, 4, 13)
  SEPTEMBER = DateTime.new(2009, 9, 30)
  OCTOBER   = DateTime.new(2009, 10)

  before(:each) do
    Event.destroy_all
  end

  describe "monthly event on the 3rd Monday until september" do
    before(:each) do
      @event = Event.create! :start_at => APRIL_13, :end_at => APRIL_13 + 1.hour, :repeat_monthly => true, :events_end_at => SEPTEMBER
    end

    it "should have one event per month on the 3rd Monday" do
      month = APRIL
      while month <= SEPTEMBER
        occurrences = EventOccurrence.for_month(month)
        occurrences.size.should == 1
        month = month >> 1
      end

      @event.occurrences[0].start_at.should == DateTime.new(2009, 4, 20)
      @event.occurrences[1].start_at.should == DateTime.new(2009, 5, 18)
      @event.occurrences[2].start_at.should == DateTime.new(2009, 6, 15)

      EventOccurrence.for_month(OCTOBER).should be_blank
    end
  end

  describe "weekly event starting in march without end" do
    before(:each) do
      @event = Event.create! :start_at => MARCH_29, :end_at => MARCH_29 + 1.hour, :repeat_weekly => true
      @april = EventOccurrence.for_month(APRIL)
    end

    it "should have four events in april" do
      EventOccurrence.for_month(APRIL).size.should == 4
    end

    it "should have one event if ranged for one day" do
      EventOccurrence.for_range(MARCH_29, MARCH_29 + 1.day).size.should == 1
    end

    it "should have 52 events if ranged for a year" do
      EventOccurrence.for_range(MARCH_29, MARCH_29 + 52.weeks - 1.day).size.should == 52
    end

    it "the created occurrences should be attached to the event, and have the same times for starting and ending" do
      april_events = EventOccurrence.for_month(APRIL)
      april_events[0].start_at.should == DateTime.new(2009, 4,  5, 19, 30)
      april_events[0].end_at.  should == DateTime.new(2009, 4,  5, 20, 30)

      april_events[1].start_at.should == DateTime.new(2009, 4, 12, 19, 30)
      april_events[1].end_at.  should == DateTime.new(2009, 4, 12, 20, 30)

      april_events[2].start_at.should == DateTime.new(2009, 4, 19, 19, 30)
      april_events[2].end_at.  should == DateTime.new(2009, 4, 19, 20, 30)

      april_events[3].start_at.should == DateTime.new(2009, 4, 26, 19, 30)
      april_events[3].end_at.  should == DateTime.new(2009, 4, 26, 20, 30)
    end

    it "shouldn't create new events on subsequent calls" do
      assert_difference "EventOccurrence.count", 0 do 
        @april.should == EventOccurrence.for_month(APRIL)
      end
    end

    it "should be able to find events in far future" do
      assert_difference "EventOccurrence.count", 4 do 
        EventOccurrence.for_month(APRIL + 1.year).size.should == 4
      end
    end

    it "should be one event in march" do
      EventOccurrence.for_month(MARCH).size.should == 1
    end

    it "should be no events in feb" do
      EventOccurrence.for_month(FEB).should be_blank
    end

    it "deleting the event should delete the occurrences" do
      @event.destroy
      @april.each { |o| lambda { o.reload }.should raise_error }
    end

    it "making the end date earlier should remove the occurrences after the new end date" do
      @event.events_end_at = APRIL_19
      @event.save!

      # The last event should have been removed
      lambda { @april.last.reload }.should raise_error
    end

    it "shouldn't delete occurrences for other events when changing the end date" do
      other_event = Event.create! :start_at => MARCH_29, :end_at => MARCH_29 + 1.hour, :repeat_weekly => true
      EventOccurrence.for_month(APRIL)
      other_occurrences = other_event.reload.occurrences
      other_occurrences.should_not be_blank

      @event.events_end_at = APRIL_19
      @event.save!
     
      # Ensure that no other event had their occurrences deleted
      other_occurrences.each { |e| e.reload }
    end

    it "should delete previous occurences if start date moved forward" do
      @event.occurrences.find(:all, :conditions => ["start_at < ?", APRIL_19]).should_not be_blank
      @event.update_attribute :start_at, APRIL_19
      # There shouldn't be any events after April 19th
      @event.occurrences.find(:all, :conditions => ["start_at < ?", APRIL_19]).should be_blank
    end
  end

  describe "weekly event starting in march ending midway through april" do
    it "should have three events in april (not 4)" do
      event = Event.create! :start_at => MARCH_29, :repeat_weekly => true, :end_at => MARCH_29 + 1.hour, :events_end_at => APRIL_19
      april = EventOccurrence.for_month(APRIL)
      april.size.should == 3
    end
  end

end

describe "Non-recurring event" do
  it "should have a single occurrence" do
    event = Event.create! :start_at => MARCH_29, :end_at => MARCH_29 + 1.hour
    occurrences = EventOccurrence.for_month(MARCH)
    occurrences.size.should == 1
    occurrences.first.start_at.should == event.start_at
    occurrences.first.end_at.  should == event.end_at
  end
end
