# -*- ruby -*-
#encoding: utf-8

require 'schedulability'
require 'schedulability/schedule'
require 'loggability'

require 'arborist/observer' unless defined?( Arborist::Observer )


# An summarization action taken by an Observer.
class Arborist::Observer::Summarize
	extend Loggability


	# Loggability API -- log to the Arborist logger
	log_to :arborist


	### Create a new Summary that will call the specified +block+ +during+ the given schedule,
	### +every+ specified number of seconds or +count+ events, whichever is sooner.
	def initialize( every: 0, count: 0, during: nil, &block )
		raise ArgumentError, "Summarize requires a block" unless block
		raise ArgumentError, "Summarize requires a value for `every` or `count`." if
			every.zero? && count.zero?

		@time_threshold  = every
		@count_threshold = count
		@schedule        = Schedulability::Schedule.parse( during ) if during
		@block           = block

		@event_history = {}
	end


	######
	public
	######

	##
	# The object to #call when the action is triggered.
	attr_reader :block

	##
	# The number of seconds between calls to the action
	attr_reader :time_threshold

	##
	# The number of events that cause the action to be called.
	attr_reader :count_threshold

	##
	# The schedule that applies to this action.
	attr_reader	:schedule

	##
	# The Hash of recent events, keyed by their arrival time.
	attr_reader :event_history


	### Call the action for the specified +event+.
	def handle_event( event )
		self.record_event( event )
		self.call_block if self.should_run?
	end


	### Handle a timing event by calling the block with any events in the history.
	def on_timer( * )
		self.log.debug "Timer event: %d pending event/s" % [ self.event_history.size ]
		self.call_block unless self.event_history.empty?
	end


	### Execute the action block.
	def call_block
		self.block.call( self.event_history.dup )
	ensure
		self.event_history.clear
	end


	### Record the specified +event+ in the event history if within the scheduled period(s).
	def record_event( event )
		return if self.schedule && !self.schedule.now?
		self.event_history[ Time.now ] = event
	end


	### Returns +true+ if the count threshold is exceeded and the current time is within the
	### action's schedule.
	def should_run?
		return self.count_threshold_exceeded?
	end


	### Returns +true+ if the number of events in the event history meet or exceed the
	### #count_threshold.
	def count_threshold_exceeded?
		return false if self.count_threshold.zero?
		self.log.debug "Event history has %d events" % [ self.event_history.size ]
		return self.event_history.size >= self.count_threshold
	end

end # class Arborist::Observer::Summarize