#!/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)

import gc
import sys
import traceback

# Local imports
from dqc_wrapper.utils.utils_files import *
from dqc_wrapper.utils.utils_pdf import *

from dqc_wrapper.test00_file_format import FileFormatCheck
from dqc_wrapper.test01_standard_compliance import StandardComplianceTest
from dqc_wrapper.test02_spatial_completeness import SpatialCompletenessTest
from dqc_wrapper.test03_temporal_completeness import TemporalCompletenessTest
from dqc_wrapper.test04_spatial_consistency import SpatialConsistencyTest
from dqc_wrapper.test05_temporal_consistency import TemporalConsistencyTest
from dqc_wrapper.test06_valid_ranges import ValidRangesTest

"""
Class: Versioning and messages of the wrapper
"""
class checker_body:

    def __init__(self, name):
        self.name = name
        self.version = "0.0.4"
        self.help_msg()

    def __version__(self):
        
        string = """        
          _____     ____     _____
         |  __ \   / __ \   / ____|
         | |  | | | |  | | | |
         | |  | | | |  | | | |
         | |__| | | |__| | | |____
         |_____/   \___\_\  \_____|
        
          Data Quality Checker - version {} (C3512 project)
        """.format(self.version)
        
        print(string.replace('\t', ''))

    def help_msg(self):
        string = "\n#"+ "#" * 80 + "\n#\n"
        string += "#"+ " " * 2+"Data Quality Checker Help message - How to run the DQC:\n#\n"
        string += "#"+ " " * 4+"$ python checker.py <config_file.ini>\n#\n"
        string += "#" + "#" * 80 + "\n"

        self.help = string

"""
Class: Main interface to the checks
---
- Reads config file as unique commandline operator
- Loops over the different checks/sections
"""
def main(args):
    dqc = checker_body("testing")
    dqc.__version__()

    # Help display
    try:
        if len(args) > 1:
            raise Exception('Too many arguments')
        if (args[0] in ["--help","-h","help","sos","commands"]):
            raise Exception('Help message')
    except:
        print(dqc.help)
        sys.exit()        

    # Read configuration and check mandatory fields in the general section
    c = CheckerConfig(args[0])
    try:
        c.read_config()
    except Exception as e:
        print('ERROR: {}'.format(e))
        sys.exit()
        
    # Skip if zip file exists
    zipfname = get_zip_fname(c.res_dir, args[0])

    # For each section/test
    files2zip = []
    err = False

    for s in c.config.sections():
        # Section header
        print_header("Data Quality Checker [check={}]".format(s))

        # Free memory (every test)
        gc.collect()

        # Each section is a different test available
        try:
            test_res = None

            ## TEST 00 - File format (both for original GRIB + converted/experimental NetCDF)
            if s == 'file_format':
                file_format_ck = FileFormatCheck(c.file_list['original'] + c.file_list['nc_converter'])
                test_res = file_format_ck.main()
                del file_format_ck

            ## TEST 011 - Standard compliance (original GRIB files)
            elif s == 'standard_compliance_grib':
                standard_ck = StandardComplianceTest(c.file_list['original'],
                                                     c.forms_dir, c.cds_dataset, c.cds_variable, suffix='grib')
                test_res = standard_ck.main()
                del standard_ck

            ## TEST 012 - Standard compliance (converted/experimental NetCDF)
            elif s == 'standard_compliance_netcdf':
                standard_ck = StandardComplianceTest(c.file_list['nc_converter'],
                                                     c.forms_dir, c.cds_dataset, c.cds_variable, suffix='netcdf')
                test_res = standard_ck.main()
                del standard_ck

            ## TEST 02
            elif s == 'spatial_completeness':
                spatial_completeness_ck = SpatialCompletenessTest(
                    c.file_list['original'], c.varname, c.datatype, c.cds_dataset, c.system, c.origin, c.masks_dir, c.land_sea_mask, c.land_variable
                )
                test_res = spatial_completeness_ck.main()
                del spatial_completeness_ck

            ## TEST 03
            elif s == 'temporal_completeness':
                temporal_completeness_ck = TemporalCompletenessTest(
                    c.res_dir, c.config_fname, c.file_list['original'], c.forms_dir,
                    c.cds_dataset, c.cds_variable, c.origin, c.system, c.is_seasonal, c.is_complete,
                )
                test_res = temporal_completeness_ck.main()
                del temporal_completeness_ck

            ## TEST 04
            elif s == 'spatial_consistency':
                spatial_consistency_ck = SpatialConsistencyTest(
                    c.file_list['original'], c.grid_type, c.grid_int, c.grid_map, c.dual_res
                )
                test_res = spatial_consistency_ck.main()
                del spatial_consistency_ck

            ## TEST 05
            elif s == 'temporal_consistency':
                temporal_consistency_ck = TemporalConsistencyTest(
                    c.res_dir, c.config_fname, c.file_list['original'], c.time_step, c.time_granularity, c.is_complete
                )
                test_res = temporal_consistency_ck.main()
                del temporal_consistency_ck

            ## TEST 06
            elif s == 'valid_ranges':
                valid_ranges_ck = ValidRangesTest(
                    c.res_dir, c.config_fname, c.file_list['original'], c.varname, c.valid_min, c.valid_max, c.datatype,
                    c.forms_dir, c.cds_dataset, c.cds_variable
                )
                test_res = valid_ranges_ck.main()          
                files2zip.append(test_res['plot'])
                del valid_ranges_ck

            else:
                raise Exception('Test {} is not available in the current checker implementation. Please check your config syntax')

        # Exceptions/Errors
        except KeyboardInterrupt:
            print_progress(100, 100)
            err=True
            print('Cancelled, exiting...')
            exit()
        except:            
            print_progress(100, 100)
            err=True
            print('ERROR: Processing section {}'.format(s))
            print('ERROR: {}'.format(traceback.format_exc()))

        # Append result
        finally:
            c.save_config(s, test_res)

    if not(err):

        # Save config and PDF export
        try:
            # Save TXT result object (ini file, overview of all results)
            res_file = save_result(c.config, c.res_dir, c.config_fname)

            # Save PDF report (result + log)
            if os.path.exists(res_file) and os.path.exists(c.log_file):
                files2zip += save_all_pdf_reports(c, res_file)

            # Zip all results (if completed - 6 tests + 1 html)
            if len(files2zip) >= 7:
                zip_results(zipfname, files2zip)

        except:
            print('ERROR: Could not save results. Check res_dir and log_dir permissions')

if __name__ == "__main__":
    args = sys.argv[1:]
    sys.exit(main(args))
