#! /usr/bin/env python3

import os
import sys
import shutil
import yaml
import subprocess

tracediff_script = ""
traceunion_script = ""
traceontograph_script = ""
tracetodot_script = ""

def callTraceTools(work_dir, resources):
	global tracediff_script
	global traceunion_script
	global traceontograph_script
	global tracetodot_script

	golden_trace = resources['trace_prof']
	golden_trace_file = os.path.join(work_dir, golden_trace)
	if os.path.isfile(golden_trace_file) == False:
		return ("FAIL: golden_trace_file not found:", golden_trace)
	## call tracediff to generate the trace report file
	reports_list = []
	for faulty_trace in resources["trace_inject"]:
		faulty_trace_file = os.path.join(work_dir, faulty_trace)
		if os.path.isfile(faulty_trace_file) == False:
			print ("WARNING: faulty_trace_file not found:", faulty_trace, "work_dir:", work_dir)
			pass
		else:
			report_name = '.'.join(faulty_trace.split('.')[0:-1])+'.report.'+faulty_trace.split('.')[-1]
			report_file = os.path.join(work_dir, report_name)
			commands = [tracediff_script, golden_trace_file, faulty_trace_file, '>', report_file]
			p = subprocess.Popen(' '.join(commands), shell=True)
			p.wait()
			if p.returncode != 0:
				return ("FAIL: \'tracediff\' quits unnormally!")
			if os.path.isfile(report_file) == False:
				return ("FAIL: report_file not generated by \'tracediff\':", report_name)
			if os.path.getsize(report_file) == 0:
				return ("FAIL: report_file generated by \'tracediff\' is empty:", report_name)
			reports_list.append(report_file)

	## call traceunion to generate a union of all reports
	united_report_name = 'llfi.united.trace.report.txt'
	united_report_file = os.path.join(work_dir, united_report_name)
	commands = [traceunion_script]
	commands.extend(reports_list)
	commands.extend(['>', united_report_file])
	p = subprocess.Popen(' '.join(commands), shell=True)
	p.wait()
	if p.returncode != 0:
		return ("FAIL: \'traceunion\' quits unnormally!")
	if os.path.isfile(report_file) == False:
		return ("FAIL: united report_file not generated by \'traceunion\':", united_report_name)
	if os.path.getsize(report_file) == 0:
		return ("FAIL: united report_file generated by \'traceunion\' is empty:", united_report_name)

	## call traceontograph to generate the dot file
	cdfg_prof_file = os.path.join(work_dir, resources['cdfg_prof'])
	if os.path.isfile(cdfg_prof_file) == False:
		return ("FAIL: cdfg_prof_file not found:", resources['cdfg_prof'])
	commands = [traceontograph_script, united_report_file, cdfg_prof_file, '>']
	cdfg_faulty_name = 'llfi.faulty.graph.dot'
	cdfg_faulty_file = os.path.join(work_dir, cdfg_faulty_name)
	commands.append(cdfg_faulty_file)
	p = subprocess.Popen(' '.join(commands), shell=True)
	p.wait()
	if p.returncode != 0:
		return ("FAIL: \'traceontograph\' quits unnormally!")
	if os.path.isfile(report_file) == False:
		return ("FAIL: cdfg_faulty_file not generated by \'traceontograph\':", cdfg_faulty_name)
	if os.path.getsize(report_file) == 0:
		return ("FAIL: cdfg_faulty_file generated by \'traceontograph\' is empty:", cdfg_faulty_name)

	## call tracetodot to generate all dot and report files
	current_dir = os.path.abspath(os.path.curdir)
	llfi_stat_dir = os.path.join(work_dir, 'llfi', 'llfi_stat_output')
	os.chdir(llfi_stat_dir)
	#print (os.getcwd())
	p = subprocess.Popen(tracetodot_script, shell=True)
	p.wait()
	os.chdir(current_dir)
	if p.returncode != 0:
		return ("FAIL: \'tracetodot\' quits unnormally!")
	trace_dir = os.path.join(work_dir, 'llfi', 'trace_report_output')
	#print(trace_dir)
	if os.path.isdir(trace_dir) == False:
		return ("FAIL: trace_report_output/ not generated by\'tracetodot\'!", work_dir)
	t = [f for f in os.listdir(trace_dir)]
	if len(t) < 2:
		return ("FAIL: dot/report files generated by\'tracetodot\' not complete!", work_dir)

	return "PASS"



def test_trace_tools(*test_list):
	global tracediff_script
	global traceunion_script
	global traceontograph_script
	global tracetodot_script

	r = 0
	suite = {}
	script_dir = os.path.dirname(os.path.realpath(__file__))
	llfi_tools_dir = os.path.join(script_dir, '../../tools')
	tracediff_script = os.path.join(llfi_tools_dir, "tracediff")
	traceunion_script = os.path.join(llfi_tools_dir, "traceunion")
	traceontograph_script = os.path.join(llfi_tools_dir, "traceontograph")
	tracetodot_script = os.path.join(llfi_tools_dir, "tracetodot")
	
	testsuite_dir = os.path.join(script_dir, os.pardir)
	with open(os.path.join(testsuite_dir, "test_suite.yaml")) as f:
		try:
			suite = yaml.load(f)
		except:
			print("ERROR: Unable to load yaml file: test_suite.yaml", file=sys.stderr)
			return -1

	work_dict = {}
	for test in suite["Traces"]:
		if len(test_list) == 0 or test in test_list or "all" in test_list:
			work_dict["./Traces/"+test] = suite["Traces"][test]

	result_list = []
	for test_path in work_dict:
		print ("MSG: Testing on trace files of:", test_path)
		work_dir = os.path.abspath(os.path.join(testsuite_dir, test_path))
		result = callTraceTools(work_dir, work_dict[test_path])
		if result != 'PASS':
			r += 1
		record = {"name": test_path, "result": result}
		result_list.append(record)

	return r, result_list

if __name__ == "__main__":
	r, result_list = test_trace_tools(*sys.argv[1:])
	print ("=============== Result ===============")
	for record in result_list:
		print(record["name"], "\t\t", record["result"])

	sys.exit(r)
