#!/bin/env python3

import logging
import json
import retemplate
import sys
import yaml

from argparse import ArgumentParser
from threading import Thread

'''
This file serves as an entry point to the module's features, and is the recommended method of
executing templates.
'''

def parseargs():
    '''
    Interpets command line arguments
    '''

    parser = ArgumentParser(description='Schedule file templating')
    parser.add_argument('-c', '--config',
                        help='Config file to read in',
                        default='config.yml')
    parser.add_argument('-l', '--logfile',
                        help='The file to direct log output to (see readme for details)',
                        default=None)
    parser.add_argument('-v', '--values',
                        help='Log all values retrieved from data stores',
                        default=False,
                        action='store_true')
    return parser.parse_args()

def main():
    '''
    Main entry point to the rtpl utility. This handles configuration of the application before
    launching Retemplate objects as simultaneous threads.
    '''

    args = parseargs()

    # First set up basic logging so we can emit events before the user's custom configs can be read
    logcfg = {
        'level': 'INFO',
        'filename': args.logfile,
        'format': '%(levelname)s %(asctime)s %(message)s',
        'style': '%'
    }

    # Forcible reconfiguration of live logging is only available after Python 3.8
    if sys.version_info.minor >= 8:
        logcfg['force'] = True
    logging.basicConfig(**logcfg)

    logging.info('Starting up Retemplate')
    config = dict()
    stores = dict()
    templates = list()
    threads = list()

    # Parse the config file
    logging.info('Parsing config file at {}'.format(args.config))
    try:
        with open(args.config, 'r') as fh:
            config = yaml.load(fh.read(), Loader=yaml.FullLoader)
    except IOError:
        logging.error('Could not read config file: {}'.format(args.config))
        sys.exit(1)

    # Update logging config based on user configs if Python allows it
    if 'retemplate' in config and 'logging' in config['retemplate'] and sys.version_info.minor >= 8:
        logcfg.update(config['retemplate']['logging'])
        logging.basicConfig(**logcfg)
        logging.debug('Logging configured')

    # Configure DataStores
    for store in config['stores']:
        if config['stores'][store]['type'] == 'aws-local-meta':
            stores[store] = retemplate.AwsLocalMetadataServer(store, **config['stores'][store])
        if config['stores'][store]['type'] == 'aws-secrets-manager':
            stores[store] = retemplate.AwsSecretsManagerStore(store, **config['stores'][store])
        if config['stores'][store]['type'] == 'aws-systems-manager':
            stores[store] = retemplate.AwsSystemsManagerStore(store, **config['stores'][store])
        if config['stores'][store]['type'] == 'local-exec':
            stores[store] = retemplate.LocalExecutionStore(store, **config['stores'][store])
        if config['stores'][store]['type'] == 'redis':
            stores[store] = retemplate.RedisStore(store, **config['stores'][store])
        logging.debug('Configured data store {}'.format(store))

    # Configure templates
    for target in config['templates']:
        template = config['templates'][target]['template']
        del(config['templates'][target]['template'])
        tpl = retemplate.Retemplate(target, template, stores, args.values, **config['templates'][target])
        templates.append(tpl)
        logging.debug('Configured template for target {}'.format(target))

    # Run each template as a thread
    for tpl in templates:
        thread = Thread(target=tpl.run)
        threads.append(thread)
        thread.start()

    # Wait for all threads to finish before exiting
    # (They should only ever finish if they error out, since they run in infinite loops)
    for thread in threads:
        thread.join()

    logging.info('Shutting down Retemplate')

if __name__ == '__main__':
    main()
