class ReactiveCount
  include ReactiveTags

  def reactive?
    true
  end

  def initialize(source, block)
    @source = ReactiveValue.new(source)
    @block = block
  end

  def cur
    direct_count
  end

  # After events are bound, we keep a cache of each cell's count
  # value, and base the results
  def cached_count

  end

  # Before events are bound, when .cur is called, we simply
  # run the count on the source object.
  def direct_count
    count = 0
    @source.size.cur.times do |index|
      val = @source[index]
      result = @block.call(val).cur
      if result == true
        count += 1
      end
    end

    count
  end

  def setup_listeners
    @cell_trackers = []
    @added_tracker = @source.on('added') do |_, index|
      change_cell_count(@source.size.cur)
      trigger!('changed')
    end

    @removed_tracker = @source.on('removed') do |_, index|
      change_cell_count(@source.size.cur)
      trigger!('changed')
    end

    # Initial cell tracking
    change_cell_count(@source.size.cur)
  end

  # We need to make sure we're listening on the result from each cell,
  # that way we can trigger when the value changes.
  def change_cell_count(size)
    current_size = @cell_trackers.size

    if current_size < size
      # Add trackers

      current_size.upto(size-1) do |index|
        # Get the reactive value for the index
        val = @source[index]

        result = @block.call(val)

        @cell_trackers << result.on('changed') do
          trigger!('changed')
        end
      end
    elsif current_size > size
      (current_size-1).downto(size) do |index|
        @cell_trackers[index].remove
        @cell_trackers.delete_at(index)
      end
    end
  end


  def teardown_listeners
    @added_tracker.remove
    @added_tracker = nil

    @removed_tracker.remove
    @removed_tracker = nil

    change_cell_count(0)

    @cell_trackers = nil
  end

  def event_added(event, scope_provider, first, first_for_event)
    setup_listeners if first
  end

  def event_removed(event, last, last_for_event)
    teardown_listeners if last
  end

  def inspect
    "@#{cur}"
  end
end