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

require 'etc'

require 'arborist/node'
require 'arborist/mixins'


# A node type for Arborist trees that represent network-connected hosts.
#
#    host_node = Arborist::Node.create( :host, 'acme' ) do
#        description "Public-facing webserver"
#        address '93.184.216.34'
#
#        tags :public, :dmz
#
#        resource 'disk'
#        resource 'memory' do
#            config hwm: '3.4G'
#        end
#        resource 'loadavg'
#        resource 'processes' do
#            config expect: { nginx: 2 }
#        end
#
#        service 'ssh'
#        service 'www'
#
#    end
#
#
class Arborist::Node::Host < Arborist::Node
	include Arborist::NetworkUtilities

	### Create a new Host node.
	def initialize( identifier, attributes={}, &block )
		@addresses = []
		super
	end


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

	##
	# The network address(es) of this Host as an Array of IPAddr objects
	attr_reader :addresses


	### Set one or more node +attributes+. Supported attributes (in addition to
	### those supported by Node) are: +addresses+.
	def modify( attributes )
		attributes = stringify_keys( attributes )

		super

		if attributes['addresses']
			self.addresses.clear
			Array( attributes['addresses'] ).each do |addr|
				self.address( addr )
			end
		end
	end


	### Return the host's operational attributes.
	def operational_values
		properties = super
		return properties.merge( addresses: self.addresses.map(&:to_s) )
	end


	### Set an IP address of the host.
	def address( new_address )
		self.log.debug "Adding address %p to %p" % [ new_address, self ]
		@addresses += normalize_address( new_address )
	end


	### Returns +true+ if the node matches the specified +key+ and +val+ criteria.
	def match_criteria?( key, val )
		return case key
			when 'address'
				search_addr = IPAddr.new( val )
				@addresses.any? {|a| search_addr.include?(a) }
			else
				super
			end
	end


	### Return host-node-specific information for #inspect.
	def node_description
		return "{no addresses}" if self.addresses.empty?
		return "{addresses: %s}" % [ self.addresses.map(&:to_s).join(', ') ]
	end


	#
	# Serialization
	#

	### Return a Hash of the host node's state.
	def to_h
		return super.merge( addresses: self.addresses.map(&:to_s) )
	end


	### Marshal API -- set up the object's state using the +hash+ from a previously-marshalled
	### node. Overridden to turn the addresses back into IPAddr objects.
	def marshal_load( hash )
		super
		@addresses = hash[:addresses].map {|addr| IPAddr.new(addr) }
	end


	### Equality operator -- returns +true+ if +other_node+ is equal to the
	### receiver. Overridden to also compare addresses.
	def ==( other_host )
		return super && other_host.addresses == self.addresses
	end

end # class Arborist::Node::Host