#!/usr/bin/env python3

import os
import yaml
import glob
import argparse
import subprocess

# Provide some config options
parser = argparse.ArgumentParser(
    description='Manage instances of the COB server.')
parser.add_argument(
    '-c',
    '--config',
    dest='userConf',
    action='store',
    default=None,
    help=
    'Provide a YAML formatted configuration file, if not provided, general Camoco config file is used.'
)
parser.add_argument(
    '-d',
    '--daemon',
    dest='daemon',
    action='store_true',
    default=False,
    help='Run gunicorn as a daemon (allows closing of this terminal).')
parser.add_argument(
    '-k',
    '--kill',
    dest='kill',
    action='store_true',
    default=False,
    help=
    'Kill running server. Use \'-n\' to define specific server to kill otherwise all will be.'
)
parser.add_argument(
    '-l',
    '--list',
    dest='list',
    action='store_true',
    default=False,
    help=
    'Kill running server. Use \'-n\' to define specific server to kill otherwise all will be.'
)
parser.add_argument(
    '-n',
    '--name',
    dest='name',
    action='store',
    default=None,
    help='Name of server to start or kill.')
args = parser.parse_args()


# Helper function to kill servers defined by a list of pid files
def killServers(pids):
    for pid in pids:
        subprocess.run('kill `cat ' + pid + '`', shell=True)
        print('Killed: ' + pid.split('_')[-1])


# Pull the camoco conf file to find the base dir
camocoConf = yaml.load(open(os.path.expanduser('~/.camoco.conf'), 'r'))

# Location of scratch folder
base = os.path.join(
    os.path.expanduser(camocoConf['options']['basedir']), 'web')
os.makedirs(base, exist_ok=True)

if args.list:
    pids = glob.glob(base + '/*/.pid_*')
    if len(pids) < 1:
        print('No running servers')
    else:
        print('Running Servers:')
        for pid in pids:
            print(pid.split('_')[-1])

# Handle the kill command
elif args.kill:
    # Get the relevant PIDs
    if args.name:
        pids = glob.glob(base + '/*/.pid_' + args.name)
    else:
        pids = glob.glob(base + '/*/.pid_*')

    # Kill them if they exist
    if len(pids) < 1:
        print('No running servers found')
    else:
        killServers(pids)
        for pid in pids:
            try:
                os.remove(pid)
            except FileNotFoundError:
                pass

else:
    # Default config values
    opts = {
        'name': 'cob',
        'port': 50000,
        'host': 'localhost',
        'threads': 4,
        'timeout': 300,
        'networks': [],
        'gwas': [],
        'dev': False,
        'refLinks': {},
        'defaults': {
            'overlapMethod': 'density',
            'overlapSNPs': 'strongest',
            'logSpacing': True,
            'hpo': False,
            'visEnrich': True,
            'fdrFilter': True,
            'nodeCutoff': 0,
            'edgeCutoff': 2.5,
            'fdrCutoff': 0.35,
            'windowSize': 50000,
            'flankLimit': 2,
            'visNeighbors': 25,
            'nodeSize': 10,
            'pCutoff': 0.05,
            'minTerm': 5,
            'maxTerm': 300
        }
    }

    # If there is a config file, use it
    if args.userConf:
        conf = yaml.load(open(args.userConf, 'r'))
    elif 'web' in camocoConf:
        conf = camocoConf['web']
    else:
        conf = opts

    # Update any options that were defined
    for key, val in conf.items():
        if key in opts:
            if key == 'defaults':
                for k2, v2 in val.items():
                    if k2 in opts['defaults']:
                        opts['defaults'][k2] = v2
            else:
                opts[key] = val

    # Override the name if needed
    if args.name:
        opts['name'] = args.name

    # Setup the scratch folder
    opts['scratch'] = os.path.join(base, opts['name'])
    os.makedirs(opts['scratch'], exist_ok=True)

    # Make it a daemon if so deemed
    if args.daemon:
        daemon = '--daemon --pid ' + os.path.join(opts['scratch'],
                                                  '.pid_' + opts['name'])
    else:
        daemon = '--pid ' + os.path.join(opts['scratch'],
                                         '.pid_' + opts['name'])

    # Check if running, kill if so
    pids = glob.glob(opts['scratch'] + '/.pid_*')
    if len(pids) > 0:
        print('Found running server with this name, killing...')
        killServers(pids)

    # Run the server!
    print('Starting your server...')
    p = subprocess.Popen(
        'gunicorn' + ' --bind ' + str(opts['host']) + ':' + str(opts['port']) +
        ' --threads ' + str(opts['threads']) + ' --timeout ' + str(
            opts['timeout']) + ' --graceful-timeout ' + str(
                opts['timeout']) + ' ' + daemon + ' --env "COB_CONF=' +
        yaml.dump(opts) + '"' + ' cob.server:app',
        shell=True)
    try:
        p.wait()
    except KeyboardInterrupt:
        try:
            p.terminate()
        except OSError:
            pass
        p.wait()

    if args.daemon:
        print('Your server is now loading, when ready you can access it at ' +
              str(opts['host']) + ':' + str(opts['port']) +
              '\'. To kill it, simply run \'cob -k\'.')
