#!/usr/bin/python3
"""
@file
@copyright
  (c) Copyright ESO - European Southern Observatory, 2022
  All Rights Reserved
  ESO (eso.org) is an Intergovernmental Organisation, and therefore
  special legal conditions apply.
@author N. Benes

@brief Simulator of ptpmond/ntpmon local interface to test client applications
"""

import argparse
from inspect import cleandoc
import logging
import os
import signal
from sys import stdin

from ptpmon.local_interface import GlobalStatus, UdsServer

class _Dummy:
    """
    Client-facing simulator of ptpmond/ntpmon.

    It allows applications to connect to its UNIX domain socket and simulated
    TRS health status updates. The status can be set by the user via an
    interactive interface.
    """

    def __init__(self, uds_adrs):
        self.logger = logging.getLogger('trsmond-dummy')
        self.global_status = GlobalStatus.PTP_BAD
        if uds_adrs is None:
            self.local_if = UdsServer(monitor=self, logger=self.logger)
        else:
            self.local_if = UdsServer(monitor=self, logger=self.logger,
                                      uds_adrs='\0' + uds_adrs)

    def run(self):
        """Simulator entry point"""
        print(cleandoc("""
        Supported commands:
          Set status: G|GOOD|PG|PTP_GOOD, B|BAD|PB|PTP_BAD, NG|NTP_GOOD, NB|NTP_BAD, T|TGL|TOGGLE
          Exit: Q|QUIT, EXIT, ^D
          """))

        status_name = {
            GlobalStatus.PTP_GOOD: 'PTP_GOOD',
            GlobalStatus.PTP_BAD : 'PTP_BAD',
            GlobalStatus.NTP_GOOD: 'NTP_GOOD',
            GlobalStatus.NTP_BAD : 'NTP_BAD',
        }

        self.local_if.start()
        try:
            while True:
                print('Status: {:>4}'.format(status_name[self.global_status]))
                line = input('--> ').upper()

                if line in ['G', 'GOOD', 'PG', 'PTP_GOOD']:
                    self.global_status = GlobalStatus.PTP_GOOD
                    self.local_if.notify(self.global_status, 'user cmd')
                elif line in ['B', 'BAD', 'PB', 'PTP_BAD']:
                    self.global_status = GlobalStatus.PTP_BAD
                    self.local_if.notify(self.global_status, 'user cmd')
                elif line in ['NG', 'NTP_GOOD']:
                    self.global_status = GlobalStatus.NTP_GOOD
                    self.local_if.notify(self.global_status, 'user cmd')
                elif line in ['NB', 'NTP_BAD']:
                    self.global_status = GlobalStatus.NTP_BAD
                    self.local_if.notify(self.global_status, 'user cmd')
                elif line in ['T', 'TGL', 'TOGGLE']:
                    if self.global_status in [GlobalStatus.PTP_GOOD, GlobalStatus.PTP_BAD]:
                        if self.global_status == GlobalStatus.PTP_GOOD:
                            self.global_status = GlobalStatus.PTP_BAD
                        elif self.global_status == GlobalStatus.PTP_BAD:
                            self.global_status = GlobalStatus.PTP_GOOD
                        self.local_if.notify(self.global_status, 'user cmd')
                    elif self.global_status in [GlobalStatus.NTP_GOOD, GlobalStatus.NTP_BAD]:
                        if self.global_status == GlobalStatus.NTP_GOOD:
                            self.global_status = GlobalStatus.NTP_BAD
                        elif self.global_status == GlobalStatus.NTP_BAD:
                            self.global_status = GlobalStatus.NTP_GOOD
                        self.local_if.notify(self.global_status, 'user cmd')
                elif line in ['Q', 'QUIT', 'EXIT']:
                    break
                elif line == '':
                    pass
                else:
                    print('Unknown command: {}'.format(line))
        except EOFError:    # CTRL-D
            pass
        self.local_if.stop()


def parse_args():
    """Parse command line arguments"""
    description = 'Simulator of ptpmond/ntpmon local interface to test client applications'
    parser = argparse.ArgumentParser(description=description,
                                     formatter_class=argparse.RawDescriptionHelpFormatter)
    parser.add_argument('--uds-adrs',
                        help='UDS address of the simulator without the leading \\0',
                        action='store', dest='uds_adrs')
    args = parser.parse_args()

    return args


def _sig_handler(signum, frame):
    """Make `input()` fail and unblock by closing stdin."""
    os.close(stdin.fileno())


def main(args):
    """Start the ptpmond/ntpmond simulator."""
    signal.signal(signal.SIGINT,  _sig_handler)
    signal.signal(signal.SIGTERM, _sig_handler)

    dummy = _Dummy(args.uds_adrs)
    dummy.run()


if __name__ == '__main__':
    args = parse_args()
    main(args)
