#!/usr/bin/env python
#
# Data Quality Checker also known as DQC
#
# Read the README.md for more detailed information
#
#       Barcelona Supercomputing Center - Centro Nacional de Supercomputacion
#       Earth Sciences Department - Computational Earth Sciences
#     
#     Authors: 
#       Joan Sala Calero (joan.sala@bsc.es)
#       Daniel Trujillo Viedma (daniel.trujillo@bsc.es)
#

import json
import sys
from datetime import datetime

if len(sys.argv) != 4:
    print('usage: python json2txt_util.py <input JSON> <section1.txt> <section2.txt>')
    sys.exit()

with open(sys.argv[1], 'r') as f:
    input_read = f.read()

json_string = "[" + (input_read.rstrip("\n").replace("\n", ",")) + "]"

json_parsed = json.loads(json_string)

##########
## Extract preliminary data
##########
is_test_report = lambda report: report["$report_type"] == "TestReport"
tests_data     = filter(is_test_report, json_parsed)

##########
## Filter out non-relevant setup and teardown entries
##########
is_call_result = lambda result: result["when"] == "call"
tests_call_data = filter(is_call_result, tests_data)

##########
## Now extract relevant data for the report
## Creates tuples (res, msg, unit test, generation time)
##########
extract_data = (lambda result: 
                ("This test verifies whether the tool is working as expected, without considering dependencies on code outside the unit tested. For instance, given an example tool that performs additions on its numerical inputs, a unit test would execute it with two synthetic (mocked) inputs e.g. numbers 1 and 2, and check that its output is the number 3, as expected. Therefore, unit testing focuses on testing the functionality of the individual tool in isolation and does not uncover the issues arising when different modules interact with each other. The coverage of the test is complete when it checks the behaviour of both mandatory and optional tool's arguments.\n \nThe checks were performed using a Python-based software package, which runs on the ECMWF virtual machines dedicated to the evaluation and quality control. The code is available upon request at copernicus-support@ecmwf.int.\n \nThe summary of the results is given below, the log details are available in the following pages.\n________________________________________________________________________________",
                 "res = {outcome}".format(**result), 
                 "msg = the tool " + result["location"][2][5:] + " has " + ("" if (result["outcome"]=="passed") else "not") + "passed the unit test " + result["location"][2], 
                 "unit test applied = " + result["nodeid"], 
                 "time = generated on " + datetime.today().strftime('%Y-%m-%d'),
                 "No detailed log output captured" if (result["outcome"]=="passed") else "{}:{} - {}".format(result["longrepr"]["reprtraceback"]["reprentries"][0]["data"]["reprfileloc"]["path"], result["longrepr"]["reprtraceback"]["reprentries"][0]["data"]["reprfileloc"]["lineno"], result["longrepr"]["reprtraceback"]["reprentries"][0]["data"]["reprfileloc"]["message"]))          
                )

##########
## So, this has to be inside a list() because in the next section we use 2 times
## relevant_data and, although iterators are lazy, they are also mutable, so the first
## following map would consume the iterator, leaving none for the second map.
##########
relevant_data = list(map(extract_data, tests_call_data))

##########
## The final step is to format the relevant data
##########
format_data = lambda data: "{}\n \n[unit]\n \n[unit_result]\n{}\n{}\n \n[metadata]\n{}\ntest = unit\n{}\n".format(data[0], data[1], data[2], data[3], data[4])
format_log  = lambda data: "{}\n".format(data[5])
     
relevant_data_formatted = map(format_data, relevant_data)
relevant_log_formatted  = map(format_log, relevant_data)

##########
## And write the files
##########
with open(sys.argv[2], 'w') as f:
    list(map(lambda s: f.write(s), relevant_data_formatted))

with open(sys.argv[3], 'w') as f:
    list(map(lambda s: f.write(s), relevant_log_formatted))




