<commit_before># An XapDevice model of an xAP Basic Status and Control device.
# (C)2012 <NAME>

path = File.expand_path(File.dirname(__FILE__))
require File.join(path, '..', 'xap.rb')
require File.join(path, 'xap_bsc.rb')

# Represents an xAP BSC Device.  See the xAP Basic Status and Control Schema.
# http://www.xapautomation.org/index.php?title=Basic_Status_and_Control_Schema
class XapBscDevice < XapDevice
	# Initializes an XapBscDevice with the given address, uid.  Endpoints
	# is an array of hashes containing :State, :Level, :Text, and/or
	# optionally :DisplayText.  :State should be a boolean value or nil,
	# :Level should be an array of [numerator, denominator], and :Text and
	# :DisplayText should be Strings.  Each input and output block must
	# also have an :endpoint key that contains the endpoint name for the
	# given block and may include a :uid key that contains an integer from
	# 1 to 254.  Endpoint names and UIDs must be unique within this device.
	# Output hashes (i.e. those endpoints that can be changed via xAP) are
	# identified by including a :callback key that is a proc to be called
	# with the endpoint hash when any of the output endpoint's attributes
	# are changed by an incoming xAP message.
	#
	# See add_endpoint for a summary of endpoint fields.
	#
	# Example:
	#
	# XapBscDevice.new XapAddress.new('vendor', 'dev', 'hostname'), Xap.random_uid,
	# 	[
	# 	{ :endpoint => 'Input 1', :uid => 1, :State => true },
	# 	{ :endpoint => 'Output 1', :State => true, :callback => proc { |ep| puts 'Output 1' } }
	# 	]
	def initialize address, uid, endpoints, interval = 5
		super address, uid, interval

		# TODO: Make endpoints a hash, with what is currently the
		# :endpoint field as the hash key, then store the hash key back
		# into the hash (will simplify calls to XapBscDevice.new, so
		# the user can type => instead of :endpoint)

		@input_count = 0
		@output_count = 0
		@endpoints = {} # Mapping from endpoint name to endpoint hash
		@uids = []
		@outputs = [] # Array containing only output endpoints to simplify handling command messages
		endpoints.each do |ep|
			add_endpoint ep
		end
	end

	# Assigns the handler that owns this device, then sends the initial
	# state of all input and output blocks as xAPBSC.info messages.
	def handler= handler
		super handler

		@endpoints.each do |name, ep|
			send_info ep
		end
	end

	# Called when a message targeting this device's address is received.
	def receive_message msg
		if msg.is_a? XapBscCommand
			puts "Command message for #{self}"

			if @output_count > 0
				eps = []
				if msg.target_addr.wildcard?
					@outputs.each do |out|
						eps << out if msg.target_addr.endpoint_match out[:endpoint]
					end
				else
					ep = @endpoints[msg.target_addr.endpoint.downcase]
					eps << ep if ep
				end

				# For each message block, if ID=*, apply the
				# change to all matched endpoints.  If ID!=*,
				# apply the change to the matching endpoint,
				# iff that endpoint is in the eps list.
				msg.each_block do |blk|
					id = blk.id
					if id == nil || id == '*'
						eps.each do |ep|
							update_endpoint ep, blk
						end
					else
						ep = @uids[id.to_i]
						if ep && eps.include?(ep)
							update_endpoint ep, blk
						end
					end
				end
			end

		elsif msg.is_a? XapBscQuery
			puts "Query message for #{self}, target #{msg.target_addr}, wildcard #{msg.target_addr.wildcard?}"

			if msg.target_addr.wildcard?
				@endpoints.each do |name, ep|
					send_info ep if msg.target_addr.endpoint_match name
				end
			else
				ep = @endpoints[msg.target_addr.endpoint.downcase]
				send_info ep if ep
			end

		elsif msg.is_a? XapBscInfo
			puts "Info message for #{self}"

		elsif msg.is_a? XapBscEvent
			puts "Event message for #{self}"

		end
	end

	# Adds a new endpoint hash to the list of endpoints, generating an
	# xAPBSC.info message if the addition is successful..  The endpoint's
	# name must be unique.  UID collision will result in an exception being
	# raised.  If the UID is not specified, the lowest available UID will
	# be used.
	#
	# Summary of endpoint fields:
	# :endpoint - Name of endpoint - mandatory, must be unique when downcased, String
	# :uid - UID of endpoint - optional, must be unique, Fixnum 1-254
	# :callback - Output change callback - mandatory for outputs, may be nil
	# :State - On/off/? state - mandatory according to xAP BSC spec
	# :Level - numerator / denominator - optional<commit_msg>Removed a duplicate period from a documentation comment.<commit_after># An XapDevice model of an xAP Basic Status and Control device.
# (C)2012 <NAME>

path = File.expand_path(File.dirname(__FILE__))
require File.join(path, '..', 'xap.rb')
require File.join(path, 'xap_bsc.rb')

# Represents an xAP BSC Device.  See the xAP Basic Status and Control Schema.
# http://www.xapautomation.org/index.php?title=Basic_Status_and_Control_Schema
class XapBscDevice < XapDevice
	# Initializes an XapBscDevice with the given address, uid.  Endpoints
	# is an array of hashes containing :State, :Level, :Text, and/or
	# optionally :DisplayText.  :State should be a boolean value or nil,
	# :Level should be an array of [numerator, denominator], and :Text and
	# :DisplayText should be Strings.  Each input and output block must
	# also have an :endpoint key that contains the endpoint name for the
	# given block and may include a :uid key that contains an integer from
	# 1 to 254.  Endpoint names and UIDs must be unique within this device.
	# Output hashes (i.e. those endpoints that can be changed via xAP) are
	# identified by including a :callback key that is a proc to be called
	# with the endpoint hash when any of the output endpoint's attributes
	# are changed by an incoming xAP message.
	#
	# See add_endpoint for a summary of endpoint fields.
	#
	# Example:
	#
	# XapBscDevice.new XapAddress.new('vendor', 'dev', 'hostname'), Xap.random_uid,
	# 	[
	# 	{ :endpoint => 'Input 1', :uid => 1, :State => true },
	# 	{ :endpoint => 'Output 1', :State => true, :callback => proc { |ep| puts 'Output 1' } }
	# 	]
	def initialize address, uid, endpoints, interval = 5
		super address, uid, interval

		# TODO: Make endpoints a hash, with what is currently the
		# :endpoint field as the hash key, then store the hash key back
		# into the hash (will simplify calls to XapBscDevice.new, so
		# the user can type => instead of :endpoint)

		@input_count = 0
		@output_count = 0
		@endpoints = {} # Mapping from endpoint name to endpoint hash
		@uids = []
		@outputs = [] # Array containing only output endpoints to simplify handling command messages
		endpoints.each do |ep|
			add_endpoint ep
		end
	end

	# Assigns the handler that owns this device, then sends the initial
	# state of all input and output blocks as xAPBSC.info messages.
	def handler= handler
		super handler

		@endpoints.each do |name, ep|
			send_info ep
		end
	end

	# Called when a message targeting this device's address is received.
	def receive_message msg
		if msg.is_a? XapBscCommand
			puts "Command message for #{self}"

			if @output_count > 0
				eps = []
				if msg.target_addr.wildcard?
					@outputs.each do |out|
						eps << out if msg.target_addr.endpoint_match out[:endpoint]
					end
				else
					ep = @endpoints[msg.target_addr.endpoint.downcase]
					eps << ep if ep
				end

				# For each message block, if ID=*, apply the
				# change to all matched endpoints.  If ID!=*,
				# apply the change to the matching endpoint,
				# iff that endpoint is in the eps list.
				msg.each_block do |blk|
					id = blk.id
					if id == nil || id == '*'
						eps.each do |ep|
							update_endpoint ep, blk
						end
					else
						ep = @uids[id.to_i]
						if ep && eps.include?(ep)
							update_endpoint ep, blk
						end
					end
				end
			end

		elsif msg.is_a? XapBscQuery
			puts "Query message for #{self}, target #{msg.target_addr}, wildcard #{msg.target_addr.wildcard?}"

			if msg.target_addr.wildcard?
				@endpoints.each do |name, ep|
					send_info ep if msg.target_addr.endpoint_match name
				end
			else
				ep = @endpoints[msg.target_addr.endpoint.downcase]
				send_info ep if ep
			end

		elsif msg.is_a? XapBscInfo
			puts "Info message for #{self}"

		elsif msg.is_a? XapBscEvent
			puts "Event message for #{self}"

		end
	end

	# Adds a new endpoint hash to the list of endpoints, generating an
	# xAPBSC.info message if the addition is successful.  The endpoint's
	# name must be unique.  UID collision will result in an exception being
	# raised.  If the UID is not specified, the lowest available UID will
	# be used.
	#
	# Summary of endpoint fields:
	# :endpoint - Name of endpoint - mandatory, must be unique when downcased, String
	# :uid - UID of endpoint - optional, must be unique, Fixnum 1-254
	# :callback - Output change callback - mandatory for outputs, may be nil
	# :State - On/off/? state - mandatory according to xAP BSC spec
	# :Level - numerator / denominator - optional
{'fraction_non_alphanumeric': 0.08791946308724832, 'fraction_numerical': 0.0044742729306487695, 'mean_word_length': 3.2576190476190474, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 21, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '621102', 'n_tokens_mistral': 3209, 'n_tokens_neox': 2778, 'n_words': 1134}