require "graph/directed_graph"

class Node
	attr_accessor :kind
	attr_reader :name
	def initialize name, type
		@name = name
		@kind = type
	end
	def inspect
		@name
	end
	def to_s
		"<#@kind #@name>"
	end
	def ==(other)
		@name == other.name
	end
	def hash
		@name.hash
	end
end

class Graph
	def initialize
		@graph = DirectedGraph.new
		@nodes = {}
	end

	def get_node element
		node = @nodes[ element.attributes["name"] ]
		unless node
			node = Node.new( element.attributes["name"], element.name )
			@nodes[ node.name ] = node
		end
		node.kind = element.name unless node.kind =~ /class|module/
		node
	end

	# Adds an API2XML tree to the inheritance graph
	def add element
		parent_node = get_node element
		# subclasses
		element.elements.each("class") { |element|
			if element.attributes["name"]
				node = get_node element
				add_extends node, element.elements["extends"]
				@graph.add_link( parent_node, node, "contains" )
				element.elements.each("include"){|include|add_include node,include}
				add node, element
			end
		}
		# submodules
		element.elements.each("module") { |element|
			if element.attributes["name"]
				node = get_node element
				@graph.add_link( parent_node, node, "contains" )
				element.elements.each("include"){|include|add_include node,include}
				add node, element
			end
		}
		add_extends parent_node, element.attributes["extends"]
		element.elements.each("include"){|include| 
			add_include parent_node, include 
		}
	end

	def add_extends node, item
		return unless item
		n = @nodes[ item ]
		unless n
			n = Node.new( item, "include" )
			@nodes[n.name] = n
		end
		@graph.add_link( n, node, "extends" )
	end

	def add_include node, element
		return unless element
		n = get_node element
		@graph.add_link( n, node, "includes" )
	end

	def write_to file_name, type="ps", size="11,9"
		dot = @graph.to_dot(
			# Node shaper
			proc {|n| 
				case n.kind
				when "module" 
					"ellipse"
				when "class"
					"box"
				else
					"diamond"
				end
			}, proc {|n| n.name }, proc {|n| n } )
		dot.orientation = "landscape" if type == "ps"
		dot.size = size
		dot.write_to_file file_name, type
	end
end
