# PrettyXML
# Thomas Sawyer (transami)
# May 2002

require 'rexml/document'

module PrettyXML

  # Returns the pretty result formatted into html
  def PrettyXML.pretty_in_html(source)
    out = PrettyXML.pretty(source)
    out.gsub!(/&/n, '&amp;')
    out.gsub!(/>/n, '&gt;')
    out.gsub!(/</n, '&lt;')
    out.gsub!(/\n/,'<br>')
    out.gsub!(/\t/,'&nbsp;&nbsp;')
    out.gsub!(/\"/n, '&quot;')
    return out
  end
  
  # Return source all pretty'd up.
  #   tab specifies indention
  #   tab = 0 for "\t" or a positive integer for ' ' * tab spaces
	def PrettyXML.pretty(source, tab=0)
		@pretty_listener = PrettyListener.new(tab)
		REXML::Document.parse_stream(source, @pretty_listener)
		return @pretty_listener.prettyxml
	end
	
  
  # private -----------------------------------------------
  
	class PrettyListener
	
		def initialize(tab=0)
			@buildxml = ""
			@depth = 0
      if tab == 0 then
        @tb = "\t"
      else
        @tb = ' ' * tab
      end
		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}?>"
		end
		
		
		def doctype(name, *contents)
			@buildxml = "#{@buildxml}\n<!DOCTYPE #{name}"
			contents.each do |c|
				@buildxml = "#{@buildxml} #{c}"
			end
			@buildxml = "#{@buildxml.strip}>"
		end
		
		
		def instruction(name, instruction)
			@buildxml = "#{@buildxml}\n<?#{name} #{instruction.strip} ?>"
		end
		
		
		def comment(comment)
			@buildxml = "#{@buildxml}\n<!-- #{comment} -->"
		end
		

		def tag_start(name, attributes)
			@buildxml = "#{@buildxml}\n" + @tb * @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" + @tb * @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" + @tb * @depth)
        text.strip!
				#text = text + "\n" + @tb * (@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
