#!python
"""
Usage:
    gnomehat_websocket --experiments_dir=<dir> [--port=<portnum>]

Options:
  --port=<portnum>          Integer port to serve websocket [default: 8765]
  --experiments_dir=<dir>   Directory name of gnomehat experiments
"""
import os
import asyncio
import websockets
import time
import subprocess
import sys
import docopt
import functools
import json
import select

from gnomehat import server_config

experiments_dir = None
TAIL_LINES = 500

@asyncio.coroutine
def serve_public_client(websocket, path):
    if path != '/stdoutstream':
        print('Error: did not recognize websocket request path')
        return
    print('Waiting for request_data...')
    request_data = yield from websocket.recv()
    print('Validating websocket request...')

    # client says hello with a friendly json message
    client_hello = json.loads(request_data)

    # let's see which experiment this client wants to listen to
    requested_namespace = os.path.split(client_hello['experiment_namespace'])[-1]
    requested_experiment = os.path.split(client_hello['experiment_id'])[-1]

    # validate that this is a real namespace and experiment
    namespaces = os.listdir(experiments_dir)
    if requested_namespace not in namespaces:
        raise ValueError("Requested namespace does not exist")

    experiments = os.listdir(os.path.join(experiments_dir, requested_namespace))
    if requested_experiment not in experiments:
        raise ValueError("Requested experiment does not exist")

    # Start a tail -F process (which should work even if stdout.txt doesn't exist yet)
    print('Generating standard output stream for experiment {}'.format(requested_experiment))
    stdout_filename = os.path.join(experiments_dir, requested_namespace, requested_experiment, 'stdout.txt')
    cmd = ['timeout', '30m', 'tail', '-n', str(TAIL_LINES), '-F', stdout_filename]
    proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)

    # Set the subprocess stdout to nonblocking with a fcntl flag
    from fcntl import fcntl, F_GETFL, F_SETFL
    flags = fcntl(proc.stdout, F_GETFL) # get current p.stdout flags
    fcntl(proc.stdout, F_SETFL, flags | os.O_NONBLOCK)

    yield from websocket.send("[Reading from file {}...]\n".format(stdout_filename))
    while True:
        proc_output = proc.stdout.readline()
        if proc_output:
            line = str(proc_output, 'utf-8')
            yield from websocket.send(line)
            yield from asyncio.sleep(.001)
        else:
            yield from asyncio.sleep(.1)


if __name__ == '__main__':
    opts = docopt.docopt(__doc__)
    port = int(opts['--port']) if opts['--port'] else None
    experiments_dir = opts['--experiments_dir']

    server_config = server_config.get_config(experiments_dir)
    print(server_config)
    if port is None:
        port = server_config['GNOMEHAT_WEBSOCKET_PORT']
    bind_ip = server_config['GNOMEHAT_BIND_IP']
    print('Starting websocket server on port {}'.format(port))
    start_server = websockets.serve(serve_public_client, bind_ip, port)

    asyncio.get_event_loop().run_until_complete(start_server)
    asyncio.get_event_loop().run_forever()
