#!/usr/bin/env ruby

require 'maruku'

require 'maruku/parse_span_better'

#MARKER = "\n***EOF***\n"
SPLIT = %r{\n\*\*\*[^\*]+\*\*\*\n}m

def marker(x)
	"\n*** Output of #{x} ***\n"
end

TOTEST = [:inspect,:to_html,:to_latex,:to_s,:to_s]

def run_test(filename, its_ok, verbose=true)
	# read file content
	input =  (f=File.open(filename,'r')).read; f.close
	
	# split the input in sections
	
	stuff = input.split(SPLIT)

	comment   = stuff.shift
	params_s = stuff.shift
	
	params = eval(params_s)
	if params == nil
		raise "Null params? #{params_s.inspect}"
	end
	
	markdown  = stuff.shift

#	puts "comment: #{markdown.inspect}"	
#	puts "markdown: #{markdown.inspect}"
	
	failed = []
	relaxed = []
	crashed = []
	actual = {}
	
	doc = Maruku.new(markdown, params)

	for s in TOTEST
		begin
			if s==:to_html
				actual[s] = doc.to_html
			else
				actual[s] = doc.send s
				raise "Methods #{s} gave nil" if not actual[s]
			end
		rescue Exception => e
			crashed << s
			actual[s] = e.inspect+ "\n"+ e.backtrace.join("\n")
			puts actual[s]
		end
	end
	

		begin
			m = Maruku.new
			d = m.instance_eval(actual[:inspect])
		rescue Exception => e
			s = e.inspect + e.backtrace.join("\n")
			raise "Inspect is not correct:\n ========\n#{actual[:inspect]}"+
			"============\n #{s}"
		end

	expected = {}
	if (stuff.size < TOTEST.size)
		$stdout.write " (first time!) "
		TOTEST.each do |x| expected[x] = actual[x] end
	else
		TOTEST.each_index do |i|
			symbol = TOTEST[i]
			expected[symbol] = stuff[i]
#			puts "symbol: #{symbol.inspect} = #{stuff[i].inspect}"
		end
	end

	if not its_ok.include? :inspect
		begin
			m = Maruku.new
			d = m.instance_eval(expected[:inspect])
	#		puts "Eval: #{d.inspect}"
			expected[:inspect] = d.inspect
		rescue Exception => e
			s = e.inspect + e.backtrace.join("\n")
			raise "Cannot eval user-provided string:\n #{expected[:inspect].to_s}"+
			"\n #{s}"
		end
	end

	
	TOTEST.each do |x|
		if actual[x] != expected[x]
			if its_ok.include? x
				expected[x] = actual[x]
				$stdout.write " relax:#{x} "
				relaxed << x
			else
				actual[x] = "-----| WARNING | -----\n" + actual[x]
				failed << x
			end
		end
	end
	
	f = File.open(filename, 'w')
	
	f.write comment
	f.write "\n*** Parameters: ***\n"
	f.write params.inspect
	f.write "\n*** Markdown input: ***\n"
	f.write markdown

	TOTEST.each do |x|
		f.write marker(x) 
		f.write expected[x]
	end
	f.write "\n*** EOF ***\n"
	
	if not failed.empty? or not crashed.empty? 
		
		f.puts "\n\n\n\nFailed tests:   #{failed.inspect} \n" 
	
		TOTEST.each do |x|
			f.write marker(x) 
			f.write actual[x]
		end

	else
		f.puts "\n\n\n\tOK!\n\n\n"
	end

	
	md_pl = markdown_pl(markdown)
		
	f.write "\n*** Output of Markdown.pl ***\n" 
	f.write md_pl
	
	f.write "\n*** Output of Markdown.pl (parsed) ***\n"
	begin 
		doc = REXML::Document.new("<div>#{md_pl}</div>",{
			:compress_whitespace=>['div','p'],
			:ignore_whitespace_nodes=>['div','p'],
			:respect_whitespace=>['pre','code']
		})
		div = doc.root
		xml =""
		div.write_children(xml,indent=1,transitive=true,ie_hack=false)
		f.write xml
	rescue Exception=>e
		f.puts "Error: #{e.inspect}"
	end
	f.close
	
	
	return failed, relaxed, crashed
end

def markdown_pl(markdown)
	tmp1 = "/tmp/marutest1"
	tmp2 = "/tmp/marutest2"
	File.open(tmp1,'w') do |f| f.puts markdown end
	system "Markdown.pl < #{tmp1} > #{tmp2}"
	f = File.open(tmp2,'r')
	s = f.read
	f.close
	s
end

def passed?(args, arg)
	if args.include? arg
		args.delete arg
		true
	else
		false
	end
end

def marutest
	args = ARGV.clone

	dont_worry = []
	TOTEST.each do |x|
		arg = "ok:#{x}"
	#	puts arg
		if passed?(args, arg)
			dont_worry << x
		end
	end
	
	if passed?(args, 'ok')
		dont_worry = TOTEST.clone
	end
	
	if dont_worry.size > 0
		puts "Relaxed on #{dont_worry.inspect}"
	end
	

	failed = {}
	relaxed = {}
	
	args.each do |f|
		$stdout.write "#{f}\n\t\t"
		tf, tr, tcrashed = run_test(f, dont_worry)
		
		tf = tf + tcrashed

		
		if tr.size > 0
			$stdout.write " relax #{tr.inspect} "
		end
		
		if tf.size>0
			$stdout.write " failed on #{tf.inspect} "
		else
			$stdout.write " OK "
		end

		if tcrashed.size > 0
			$stdout.write "    CRASHED on #{tcrashed.inspect}"
		end

			$stdout.write "\n"		
			
		failed[f]  = tf
		relaxed[f]  = tr	
	end
	
	num_failed = 0
	failed_cat = {}

	puts "\n\n\n**** FINAL REPORT ****\n\n"

	
	if failed.size > 0
		failed.each do |file, fl|
			num_failed += failed.size
			if fl.size > 0
				puts "\t#{file}\tfailed on #{fl.inspect}"
			end
			fl.each do |x|
				failed_cat[x] = failed_cat[x] || 0
				failed_cat[x] = failed_cat[x]  + 1
			end
		end
	end

	if dont_worry.size > 0
		puts "Relaxed on #{dont_worry.inspect}"
	end

	if relaxed.size > 0
		relaxed.each do |file, r|
			if r.size > 0
				puts "\t#{file}\t\trelaxed on #{r.inspect}"
			end
		end
	end
	
	if failed_cat.size > 0
		puts "\nCategories:\n"
	
		failed_cat.each do |x, num|
			puts "\t#{x.inspect} \tfailed #{num}/#{args.size}"
		end
	end
	
	num_failed
end


marutest