#!python

'''
Usage:
    fgate.py --config <configfile> --gate <gate> <source_file>
    fgate.py --gate-module <module> --gate-function <func> --format (csv | json) <source_file> [--delimiter=<delimiter>]
    fgate.py --gate-module <module> --service_module <svc-module> --gate-function <func> --format (csv | json) <source_file> [--delimiter=<delimiter>]
'''

'''
fgate (file gate): a data utility for all-or-nothing validation of a datafile.

fgate is intended to run against a source datafile (supported formats are csv and json). The user
is to supply a "gate function" which receives an open file handle and can step through the file's
contents, returning True if the file should pass (a "GO" condition) and False if it should fail
(a "NO-GO" condition).

In the case of a GO condition, fgate will emit the name of the datafile to standard out. In the case
of a NO-GO condition, fgate will return an empty string.
'''


import sys
from collections import namedtuple
import docopt
from snap import snap, common
from mercury.utils import open_in_place

FileGate = namedtuple('FileGate', 'format function_name delimiter')
ACCEPTED_FORMATS = ['csv', 'json']

def load_gates(yaml_config):
    gates = {}
    if 'gates' not in yaml_config:
        raise Exception('Your YAML config must contain a top-level "gates" section.')

    for gate_name in yaml_config['gates']:
        gate_config = yaml_config['gates'][gate_name]

        gates[gate_name] = FileGate(format=gate_config['format'],
                                    delimiter=gate_config.get('delimiter'), # delimiter can be null (e.g. if format is JSON)
                                    function_name=gate_config['gate_function'])

    return gates


def main(args):
    configfile_mode = False
    if args['--config']:
        configfile_mode = True

    if configfile_mode:
        configfile = args['<configfile>']
        yaml_config = common.read_config_file(configfile)

        common.load_config_var(yaml_config['globals']['project_home'])
        service_tbl = snap.initialize_services(yaml_config)
        svc_registry = common.ServiceObjectRegistry(service_tbl)

        gates = load_gates(yaml_config)
    
        target_gate_name = args['<gate>']
        target_gate = gates.get(target_gate_name)
        if not target_gate:
            print('No gate registered under the name %s. Please check your configuration file.' % target_gate_name, file=sys.stderr)
            return 1

        gate_module = yaml_config['globals']['gate_module']
        
    else: 
        src_format = None
        for file_format in ACCEPTED_FORMATS:
            if args.get(file_format):
                src_format = file_format
                break

        if not src_format:
            print('Invalid file format specified. Accepted formats are: %s' % (ACCEPTED_FORMATS), file=sys.stderr)
            return 1

        delimiter = args.get('--delimiter', None)
        if src_format == 'csv' and not delimiter:
            print('You must specify a delimiter when the datafile format is csv.', file=sys.stderr)
            return 1

        target_gate = FileGate(format=src_format, function_name=args['<func>'], delimiter=delimiter)
        gate_module = args['<module>']
        svc_registry = common.ServiceObjectRegistry({})
    
    gate_function = common.load_class(target_gate.function_name, gate_module)
    source_file = args['<source_file>']

    try:
        with open_in_place(source_file, 'r') as f:
            result = gate_function(f, target_gate.format, svc_registry, delimiter=target_gate.delimiter)
            if result:
                print('fgate: datafile %s is GO for gate function %s' % (source_file, target_gate.function_name), file=sys.stderr)
                print(source_file)
            else:
                print('fgate: datafile %s is NO-GO for gate %s' % (source_file, target_gate.function_name), file=sys.stderr)                    
                print('')

    except Exception as e:
        print(e, file=sys.stderr)
        print('')


if __name__ == '__main__':
    args = docopt.docopt(__doc__)
    main(args)
