#!/usr/bin/python

import sys
from sys import stdin
import os
import re
import datetime
import time
import hashlib
import subprocess


start_time = str(datetime.datetime.now())
start_time = re.sub(r'\.[0-9]*','',start_time)
start_time = re.sub('[ :]','+',start_time)
html_file = "/tmp/status-report-"+start_time+".html"

#html = 0
#if os.access ("/tmp/status.html",os.W_OK):
#	html = open("/tmp/status.html","wt")
#else:
#	html = open("/dev/null","wt")
#if os.access ("/tmp/status-dribble.txt",os.W_OK):
#	sd = open("/tmp/status-dribble.txt","wt")
#else:
#	sd = open("/dev/null","wt")
try:
	html = open(html_file,"wt")
except IOError as e:
	html = open("/dev/null","wt")
try:
	sd = open("/tmp/status-dribble.txt","wt")
except IOError as e:
	sd = open("/dev/null","wt")

os_info = os.uname()
ver = "Tool: @(#) ft-di-get_test_status.py Version 1.6 created 05/23/18 at 16:07:21\n"+"<br>OS: %s Version %s\n"%(os_info[0],os_info[2])
sd.write(ver+'\n')

Test_mode = False
#print "\n\n================ TM is ",Test_mode

head = """<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
  <meta content="text/html; charset=ISO-8859-1"
 http-equiv="Content-Type">
  <title>Federated Testing Test Status</title>
  <meta content="J Lyle NIST/CFTT" name="author">
  <meta content="Generate set of test cases for drive erasing"
 name="description">
</head>
<body>
"""
tail = """
</body>
</html>
"""

table_head = """
<table style="text-align: left;" border="2" cellpadding="2" cellspacing="2">
<tbody>
"""

table_tail = """
</tbody>
</table>
"""
#========================                    ===================
#########################################################
def shut_down(success):
	finish_time = str(datetime.datetime.now())
	html.write("<br>\n")
	if not success:
		html.write("<H1>Report Generation Failed</H1>\n")
	html.write (ver+'\n<br>')
	html.write("Done: "+finish_time+'\n')
	html.write("<br>\n")
	html.write(tail+'\n')
	exit (0)

#######################################################
def scan_drives(path):
	qlist = os.listdir(path+"/setup")
	dlist = []
	for q in qlist:
		if os.path.isdir(path+"/setup/"+q): dlist.append(q)
	sd.write(str(dlist)+'\n')
	dlist.sort()
	for d in dlist:
		drive = {}
		drive ['id'] = d
		drive ['w'] = '-'
		drive ['s'] = '0'
		drive ['dev'] = '='

		sd.write('process drive%s\n'%(d))
		fflist = os.listdir(path+"/setup/"+d)
		flist = []
		for fn in fflist:
			if re.match('setup-',fn):flist.append(fn)
		sd.write(str(flist)+'\n')

#		f = open(path+"/setup/"+d+"/setup-wipe.txt")
#		for line in f:
#			v = line.split(' ')
#			if v[0] == "Wipe":
#				drive['s'] = v[1]
#				drive['w'] = v[8]
#				drive['dev'] = v[6]
#		f.close()
		if os.access(path+"/setup/"+d+"/setup-wipe.txt",os.F_OK):
			f = open(path+"/setup/"+d+"/setup-wipe.txt")
#			print path,"setup-wipe.txt"
			for line in f:
#				print "line:",line.strip()
				v = line.split(' ')
#				print len(v),v
#				if v[0] == "Wipe":
				if line.startswith("Wipe Drive"):
					drive['dev'] = v[2]
				elif line.find("sectors wiped with") > 0:
					drive['s'] = v[0]
					drive['w'] = v[4]
				elif line.startswith("Wipe "):
					drive['s'] = v[1]
					drive['w'] = v[8]
					drive['dev'] = v[6]
			f.close()
		else:
			drive['s'] = '0'
			drive['w'] = 'N/A'
			drive['dev'] = 'N/A'


		hash_seen = False
		for file_name in flist:
			hash_list = []
			if file_name.find('hash') != -1:
				hash_seen = True
#				hash_list.append(('/dev/sdz','MD5','SHA1','SHA256'))
				f = open(path+"/setup/"+d+"/"+file_name)
				ht = f.readlines()
				f.close()
				hash_vector = ['/dev/sdz','N/A','N/A','N/A']
				for line in ht:
					if line.find('Source device:') != -1:
						fields = line.strip().split(' ')
						hash_vector[0] = fields[2][5:]
						sz = fields[3]
						drive['s'] = sz
					if line.find('Brief') != -1:
						sd.write (line)
						fields = line.strip().split(':')
						sd.write (fields[0]+' ### '+fields[1].strip()+'\n')
						if fields[0].find('MD5') != -1: ix = 1
						if fields[0].find('SHA1') != -1: ix = 2
						if fields[0].find('256') != -1: ix = 3
						hash_vector[ix] = fields[1].strip()

				sd.write(sz+' '+str(hash_vector))
				hash_list.append(hash_vector)
				if len(hash_list) == 0:hash_list.append(('/dev/sdz','N/A','N/A','N/A'))
				h = hash_list[0]
				sd.write("\n===============\n")
				sd.write(str(hash_list))
				sd.write("\n===============\n")
				if len(h[0]) == 4:dx = drive['id']+'+'+h[0][-1]
				else: dx = drive['id']
#				html.write("<tr><td>"+drive['id'])
				html.write("<tr><td>"+dx)
				html.write("</td><td>"+drive['w'])
				if (int(drive['s'])) >= (2**28): big = "*"
				else: big = ''
				if (int(drive['s'])*512)/(1024**3) == 0:
					html.write("</td><td align=right>"+drive['s']+" ("+str((int(drive['s'])*512)/(1024**2))+'MiB)')
				else:
					html.write("</td><td align=right>"+drive['s']+" ("+str((int(drive['s'])*512)/(1024**3))+'GiB)'+big)
				html.write("</td><td>"+drive['dev']+"</td>\n")
				html.write("<td>%s</td><td>%s</td><td>%s</td><td>%s</td>"%(h[0],h[1],h[2],h[3]))
				html.write("</tr>\n")
		if not hash_seen:
			html.write("<tr><td>"+drive['id'])
			html.write("</td><td>"+drive['w'])
			if (int(drive['s'])) >= (2**28): big = "*"
			else: big = ''
			if (int(drive['s'])*512)/(1024**3) == 0:
				html.write("</td><td align=right>"+drive['s']+" ("+str((int(drive['s'])*512)/(1024**2))+'MiB)')
			else:
				html.write("</td><td align=right>"+drive['s']+" ("+str((int(drive['s'])*512)/(1024**3))+'GiB)'+big)
			html.write("</td><td>"+drive['dev']+"</th>\n")
			html.write("<td>%s</td><td>%s</td><td>%s</td><td>%s</td>"%(drive['dev'][5:],"N/A","N/A","N/A"))
			html.write("</tr>\n")
def check_case (p):
#	needs = {"01":["tool","hash","case"],
#	"02":["tool","hash","case"],
#	"03":["tool","hash","case"],
#	"04":["tool","cmp","hash","case","FASTcmp","wipe"],
#	"05":["tool","cmp","hash","case","FASTcmp","wipe"],
#	"06":["tool","cmp","hash","case","FASTcmp","wipe"],
#	"07":["tool","cmp","hash","case","FASTcmp","wipe"],
#	"08":["tool","cmp","hash","case","FASTcmp","wipe"],
#	"09":["tool","cmp","hash","case","FASTcmp","wipe"],
#	"10":["tool","case","wipe","mess"],
#	"11":["tool","case","wipe","mess"],
#	"12":["tool","cmp","hash","case","FASTcmp","wipe","mess"],
#	"13":["tool","case"],
#	"14":["tool","case"],
#	"15":["tool","cmp","case","FASTcmp","wipe"]}

	needs = {"01":["tool","case"],
	"02":["tool","wipe","case","cmp","FASTcmp"],
	"03":["tool","case"],
	"04":["tool","case","wipe","cmp","FASTcmp"],
	"05":["tool","case"],
	"06":["tool","case","cmp","FASTcmp","wipe"],
	"07":["tool","case","cmp","FASTcmp","wipe"],
	"08":["tool","case","cmp","FASTcmp","wipe"],
	"09":["tool","case","cmp","FASTcmp","wipe"],
	"10":["tool","case","mess"],
	"11":["tool","case","mess"],
	"12":["tool","case","mess"],
	"13":["tool","case"],
	"14":["tool","case"],
	"15":["tool","cmp","case","FASTcmp","wipe"]}

	file_logs = {
	"case":"case.txt",
	"FASTcmp":"compare.txt",
	"cmp":"compare.txt",
	"tool":"tool-specific-log.txt",
	"mess":"message.txt",
	"hash":"analysis-rehash.txt",
	"wipe":"dst-wipe-log.txt"
	}
	

	logs = {
	"case":"document_case",
	"FASTcmp":"compare_src_to_dst",
	"cmp":"compare_src_to_dst",
	"tool":"tool_specific_log",
	"mess":"tool_message",
	"hash":"rehash_src",
	"wipe":"initialize_dst"
	}
	
	sd.write("CHECK PATH: %s\n"%(p))
	flist = os.listdir(p)
	acts = []
	tool_seen = False
	for item in flist:
		sd.write ("\t%s\n"%(item))
		if item == "case.txt": acts.append("case")
		elif item == "compare.txt":
			acts.append("FASTcmp")
			acts.append("cmp")
		elif item == "analysis-compare.txt":
			acts.append("FASTcmp")
			acts.append("cmp")
		elif item == "dst-wipe-log.txt": acts.append("wipe")
		elif item == "analysis-dst-wipe.txt": acts.append("wipe")
		elif item == "message.txt": acts.append("mess")
		elif item.find("rehash") != -1 : acts.append("hash")
		else:
			if not tool_seen:
				tool_seen = True
				acts.append ("tool")
	ix = p.lower().find("ft-di-")
	case_no = p[ix+6:ix+8].lower()
	need = set(needs[case_no]).difference(set(acts))
	sd.write("\t\tSTEPS %s: "%(p[ix+6:ix+8]))
	for act in acts:
		sd.write(act)
		sd.write(" ")
	sd.write ('needs: ')
	if len(need) == 0: sd.write("Complete")
	missing_steps = ""
	missing_logs = set()
	for missing in need:
		missing_logs.add(logs[missing])
		sd.write(missing)
#		sd.write(' ')
#		if missing_steps != "": missing_steps = missing_steps + ':'
#		missing_steps = missing_steps + missing
	for log_file in missing_logs:
		if missing_steps != "": missing_steps = missing_steps + ':'
		missing_steps = missing_steps + log_file
	sd.write("\n") 
	if len(need) == 0: return "completed"
	return "partially-completed:"+missing_steps
#######################################################

#########################################################
#########################################################
########### S t a r t    H e r e ########################
#########################################################
#########################################################

case_list = ('01', '02', '03', '04', '05', '06',
	'07', '08', '09', '10', '11', '12',
	'13', '14', '15')

start_time = datetime.datetime.now()
conf = "test-configuration.txt"
sd.write("START\n")
sd.write(str(start_time)+'\n')


html.write(head+'\n')
html.write("<br>"+'\n')
html.write("call %s with %d args:"%(sys.argv[0],len(sys.argv)-1))
for arg in sys.argv[1:]:
	html.write(arg)
html.write('\n')

# check if configuration exists
if len(sys.argv) == 1:
	html.write("<h1>NO LOG Path given</h1>\n")
	shut_down(False)
else:
	html.write("<h1>LOG Path: %s</h1>\n"%(sys.argv[2]))
	conf = sys.argv[1]
	path = sys.argv[2]
	if not os.access(path,os.F_OK):
		html.write("<h1>LOG Path: %s does not exist</h1>\n"%(path))
		shut_down(False)
#if os.access (path+'/'+"toolname.txt",os.F_OK):
#	tn = open(path+'/'+"toolname.txt","rt")
#	tool_name = tn.readline()
#	html.write("<h1>Test status for %s</h1>\n"%(tool_name))
#	tn.close()
#else:
#	html.write("<h1>There is no tool name specified in %s</h1>\n"%(path))
if not os.access(path+"/"+conf,os.F_OK):
	html.write("<h1>There is no %s in %s</h1>\n"%(conf,path))
	shut_down(False)
cf = open (path+"/"+conf,"rt")
tn = cf.readline().strip()
tx = tn.find(' ')
tv = cf.readline().strip()
vx = tv.find(' ')
tool_name = tn[tx:]+ " Version: " + tv[vx:]
# ##############   Check for drive setup #################
if os.access(path+"/"+"setup",os.F_OK):
	html.write("<h1>Test drives</h1>\n")
	html.write(table_head+'\n')
	html.write("<caption>Test Drives</caption>"+'\n')
	html.write("<tr><th>Drive</th><th>Wipe</th><th>Sectors</th>")
	html.write("<th>Dev</th><th>Dev</th><th>MD5</th><th>SHA1</th><th>SHA256</th></tr>\n")
	scan_drives (path)
	html.write(table_tail+'\n')
	html.write('<br>* Large 48-bit address drive<br>\n')
else:
	html.write("<h1>No test drives have been setup in %s</h1>\n"%(path))
# ##############   Check test case status ################
html.write("<h1>Selected test cases</h1>\n")
#cf = open (path+"/"+conf,"rt")
html.write(table_head+'\n')
html.write("<caption>Test Case Status</caption>\n")
html.write("<tr><th>Case</th><th>Path</th><th>Status</th></tr>\n")
output_text = "tests-to-run"
tests_completed = "completed"
tests_not_started = "tests-to-run"
tests_in_progress = "partially-completed"
#sep = ":\n"
sep = ":"
for line in cf:
	if line[0:2].lower() == "ft":
		target = path+"/"+line.split(" ")[0].rstrip()
		html.write("<tr><td>\n")
		test_case_id = line.rstrip("\n\r")
		html.write(test_case_id)
#		html.write(line.rstrip("\n\r"))
		html.write("<td>"+target+"</td>\n")
#		check_case (target)
		output_text = output_text + sep + test_case_id		
		if os.path.exists(target) and os.listdir(target):
			check_out = check_case (target)
			output_text = output_text + sep + check_out
			html.write("</td><td>"+check_out+"</td>\n")
			if check_out[0] == 'c':
				tests_completed = tests_completed + sep + test_case_id
			else:
				tests_in_progress = tests_in_progress + sep + test_case_id
				tests_in_progress = tests_in_progress + check_out[check_out.find(':'):]
		else:
			html.write("</td><td>Pending</td>\n")
			tests_not_started = tests_not_started + sep + test_case_id
		html.write("</tr>\n")
html.write(table_tail+'\n')
#print output_text
#print tests_not_started+':',
#print tests_in_progress+':',
#print tests_completed
print tests_not_started+':'+tests_in_progress+':'+tests_completed
shut_down(True)
