#!/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)
#       Ivan Jose Cernicharo Ortiz (ivan.cernicharo@bsc.es)

import sys, logging, subprocess
from cdo import Cdo
import magic
import zipfile

# Local import
from utils.utils_files import *

        

"""
Class: File format checks
---
- Checks for file format correctness
- Uses bash 'file' operation
"""
class file_format_check:

    def __init__(self, logdir, files):
        self.testid = 'test00-file-format'
        self.logger = logging.getLogger(self.testid)
        self.logdir = logdir        
        self.files = files

    """
    This function uses the CDO module, with command sinfon to retrieve file format
    To be used with gridded files
    """
    def cdo_return_format(self, filename):

        # This is faster than using the cdo bindings (avoids reading whole file)
        cmd0 = "cdo sinfon %s | head | grep \"File format\"" %filename
        p0 = subprocess.Popen(
            cmd0, shell=True,
            stdout=subprocess.PIPE,
            stderr=subprocess.STDOUT
            )
        out0, _ = p0.communicate()
        out0 = str(out0).lower()
        
        # Allowed file formats        
        if 'grib' in out0:      
            if 'grib2' in out0:         return 'GRIB2'
            elif 'version 2' in out0:   return 'GRIB2'
            elif 'v2' in out0:          return 'GRIB2'
            else:                       return 'GRIB'
        
        if 'netcdf' in out0:
            if 'netcdf4' in out0:       return 'NetCDF4'
            elif 'netcdf3' in out0:     return 'NetCDF3'
            elif 'netcdf2' in out0:     return 'NetCDF2'
            else:                       return 'NetCDF'

        return 'unkown format'    

    """
    This function returns the type of a file (using the bytes: equivalent to file UNIX operation)
    To be used with other files
    """
    def file_return_format(self, filename):    
        return magic.from_file(filename)

    """
    This function returns the type of the files contained in a zip file
    For that purpose creates a temporary dir
    """
    def zip_return_formats(self, filename):

        formats = []
        with tempdir() as tmpdir:
            with zipfile.ZipFile(filename, 'r') as zipf:
                zipf.extractall(tmpdir)
                for f in os.listdir(tmpdir):
                    if f.endswith('.grib') or f.endswith('.grb') or f.endswith('.nc'):
                        formats.append(self.cdo_return_format(os.path.join(tmpdir, f)))
                    else:
                        formats.append(self.file_return_format(os.path.join(tmpdir, f)))

        return formats

    def main(self):

        # Init
        res = 'ok'
        msg = ''

        # Progress init
        i = 0
        n = len(self.files)
        print()

        # Loop over files
        ffchecks = []
        for f in self.files:

            # Progress update            
            i+=1
            print_progress(i, n)                                      

            if f.endswith('.grib') or f.endswith('.grb') or f.endswith('.nc'):
                ffchecks.append(self.cdo_return_format(f))
            elif zipfile.is_zipfile(f):
                ffchecks += self.zip_return_formats(f)
            else:
                ffchecks.append(self.file_return_format(f))

        # Only unique values
        ffchecks = list(set(ffchecks))

        # Gridded files check (directory contains)        
        for f in ffchecks:
            if 'grib' in f.lower() or 'netcdf' in f.lower():                  
                msg = 'File formats found: {}'.format(ffchecks)              

        # GRIB1 check        
        if 'GRIB' in ffchecks:
            res = 'err'
            msg = 'GRIB version 1 is deprecated. The recommendation is to use version 2'

        # Prepare output
        return { 
            'res': res, 
            'msg': msg
        }


if __name__ == "__main__":        
    sys.exit()
