# PrettyXML
# Thomas Sawyer (transami)
# May 2002

require 'rexml/document'

module PrettyXML

	def PrettyXML.pretty source
		@pretty_listener = PrettyListener.new
		REXML::Document.parse_stream(source, @pretty_listener)
		return @pretty_listener.prettyxml
	end
	

	class PrettyListener
	
		def initialize
			@buildxml = ""
			@depth = 0
		end

		
		def xmldecl ver, enc, stand
			@buildxml = "#{@buildxml}<?xml"
			if ver
				@buildxml = "#{@buildxml} version='#{ver}'"
			end
			if enc
				@buildxml = "#{@buildxml} encoding='#{enc}'"
			end
			if stand
				@buildxml = "#{@buildxml} standalone='#{stand}'"
			end
			@buildxml = "#{@buildxml}?>\n"
		end
		
		
		def doctype(name, *contents)
			@buildxml = "#{@buildxml}\n<!DOCTYPE #{name}"
			contents.each do |c|
				@buildxml = "#{@buildxml} #{c}"
			end
			@buildxml = "#{@buildxml.strip}>\n"
		end
		
		
		def instruction name, instruction
			@buildxml = "#{@buildxml}\n<?#{name} instruction='#{instruction}'?>\n"
		end
		
		
		def comment comment
			@buildxml = "#{@buildxml}\n<!-- #{comment} -->\n"
		end
		

		def tag_start name, attributes
			@buildxml = "#{@buildxml}\n" + "\t"*@depth + "<#{name}"
			attributes.each do |a|
				buildxml = "#{@buildxml} #{attr_to_s(a)}"
			end
			@buildxml = "#{@buildxml}>"
			@depth += 1
			@closed_element = false
		end
	
	
		def tag_end name
			@depth -= 1
			if @closed_element then
				@buildxml = "#{@buildxml}\n" + "\t"*@depth + "</#{name}>"
			else
				@buildxml = "#{@buildxml}</#{name}>"
			end
			@closed_element = true
		end
		
	
		def text text
			if text =~ /\n/
				text = "\n" + text
				text = text.gsub(/(\n)/, "\n" + "\t"*@depth)
				text = text + "\n" + "\t"*(@depth - 1)
			end
			@buildxml = "#{@buildxml}#{text}"
			@closed_element = false
		end
		
		
		def method_missing(a, *b)
			raise "Method Missing: #{a}, #{b}"
		end
		
		
		#
		def attr_to_s attr
			return(attr[0] + "=" + attr[1])
		end
		
		#
		def prettyxml
			return @buildxml
		end
	
	end

end
