#!/usr/bin/python3

"""
@file
@ingroup trs_common_trsmonc
@copyright ESO - European Southern Observatory
@author C. Soenke

@brief Command line interface to the PTP/NTP monitoring daemon

Detailed description TBD
"""

import argparse
import signal
import socket
import textwrap
from threading import Event
import sys

from ptpmon import local_interface as local_if

TRSMOND_ADRS = 'trsmon'

stop = Event()

# Signal handler
def sig_handler(signum, frame):
    """Signal handler function"""
    print('trsmonc - received signal', signum)
    stop.set()


# Argument parser
def parse_args():
    """
    Parse command line arguments
    """
    description = textwrap.dedent('''\
            PTP/NTP monitoring client

            Supported commands are:
                status   print current status
                events   subscribe to events and print them
                stats    print ptp4l stats
            ''')

    parser = argparse.ArgumentParser(description=description,
                                     formatter_class=argparse.RawDescriptionHelpFormatter)
    parser.add_argument('command', nargs=1, help='Command to be executed')
    parser.add_argument('--uds-adrs',
                        help='UDS address of the monitoring daemon without the leading \\0',
                        action='store', dest='uds_adrs', default=TRSMOND_ADRS)

    args = parser.parse_args()
    return args


def handle_status_cmd(sock):
    """Handle status command."""

    sock.settimeout(5)

    # Send poll request
    sock.sendall(bytes([local_if.PayloadType.STATUS_REQ.value]))

    # Get the reply
    try:
        data = sock.recv(512)
    except Exception as e:
        print('Error waiting for reply', e)
        return

    msg_type, status, msg_text = local_if.decode_status_msg(data)
    if msg_type != local_if.PayloadType.STATUS_REPLY:
        print('ERROR: wrong payload type ({})'.format(msg_type))
    else:
        print(status, msg_text)


def handle_events_cmd(sock):
    """Handle events command."""

    sock.settimeout(5)

    # Subscribe events
    sock.sendall(bytes([local_if.PayloadType.SUBSCRIBE_REQ.value]))

    # Get subscription reply
    try:
        data = sock.recv(512)
    except Exception as e:
        print('Error during event subscription', e)
        return

    if data[0] == local_if.PayloadType.SUBSCRIBE_REPLY.value:
        print('Server acknowledged subscription')
    else:
        print('Error receiving acknowledge for subscription ({})'.format(data))
        return

    # Register the signal handler
    signal.signal(2, sig_handler)

    # Wait for events
    sock.settimeout(1)
    while not stop.is_set():
        # Loop
        try:
            data = sock.recv(1024)
        except socket.timeout:
            continue
        except Exception as e:
            print(e)

        if not data:
            print('No data received, connection closed')
            # TODO: here we could reconnect
            return

        msg_type, status, msg_text = local_if.decode_status_msg(data)
        print(status, msg_text)


def handle_stats_cmd(sock):
    """Handle stats command."""

    sock.settimeout(5)

    # Send poll request
    sock.sendall(bytes([local_if.PayloadType.STATS_REQ.value]))

    # Get the reply
    try:
        data = sock.recv(65536)
    except Exception as e:
        print('Error waiting for reply', e)
        return

    print(data.decode('utf-8'))


def main(args):
    """Main function of trsmonc"""

    uds_adrs = '\0' + args.uds_adrs
    uds_adrs_txt = uds_adrs.replace('\0', '\\0')

    # Create socket
    sock = socket.socket(socket.AF_UNIX, socket.SOCK_SEQPACKET)
    try:
        sock.connect(uds_adrs)
    except Exception as e:
        print(f'Failed to connect to UDS socket {uds_adrs_txt}')
        print(e)
        sys.exit(1)

    cmd = args.command[0]

    print('Sending {} command to {}'.format(cmd, uds_adrs_txt))

    # Switch command
    if cmd == 'status':
        handle_status_cmd(sock)
    elif cmd == 'events':
        handle_events_cmd(sock)
    elif cmd == 'stats':
        handle_stats_cmd(sock)
    else:
        print('Unrecognized command', cmd)

    # Close socket
    sock.close()


if __name__ == "__main__":
    # Parse command line arguments
    args = parse_args()

    # Run main
    main(args)
