#!/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,
        'threads':4,
        'timeout':300,
        'networks':[],
        'gwas':[],
        '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 localhost:'+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 \'localhost:'+str(opts['port'])+'\'. To kill it, simply run \'cob -k\'.')
