#!/usr/bin/env python3
'''
Interact with a Traffic Server process.
'''
#  Licensed to the Apache Software Foundation (ASF) under one
#  or more contributor license agreements.  See the NOTICE file
#  distributed with this work for additional information
#  regarding copyright ownership.  The ASF licenses this file
#  to you under the Apache License, Version 2.0 (the
#  "License"); you may not use this file except in compliance
#  with the License.  You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
#  Unless required by applicable law or agreed to in writing, software
#  distributed under the License is distributed on an "AS IS" BASIS,
#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#  See the License for the specific language governing permissions and
#  limitations under the License.

import argparse
import psutil
import signal
import sys
import traceback


class GetPidError(Exception):
    """ Raised when there was an error retrieving the specified PID."""

    def __init__(self, message):
        self.message = message
        super().__init__(self.message)


def get_ts_process_pid(ts_identifier):
    processes = []
    for proc in psutil.process_iter(['cmdline']):
        commandline = ' '.join(proc.info['cmdline'])
        if '/traffic_server' in commandline and ts_identifier in commandline:
            return proc
    raise GetPidError("Could not find a traffic_server process")


def convert_signal_name_to_signal(signal_name):
    """
    >>> convert_signal_name_to_signal('-SIGUSR2')
    <Signals.SIGUSR2: 12>
    >>> convert_signal_name_to_signal('SIGUSR2')
    <Signals.SIGUSR2: 12>
    >>> convert_signal_name_to_signal('USR2')
    <Signals.SIGUSR2: 12>
    >>> convert_signal_name_to_signal('-USR2')
    <Signals.SIGUSR2: 12>
    >>> convert_signal_name_to_signal('KILL')
    <Signals.SIGKILL: 9>
    >>> convert_signal_name_to_signal('notasignal')
    Traceback (most recent call last):
    ...
    ValueError: Could not find a signal matching SIGnotasignal

    """
    if signal_name.startswith('-'):
        signal_name = signal_name[1:]
    if not signal_name.startswith('SIG'):
        signal_name = 'SIG' + signal_name
    for signal_value in dir(signal):
        if not signal_value.startswith('SIG'):
            continue
        if signal_name == signal_value:
            return getattr(signal, signal_value)
    raise ValueError("Could not find a signal matching {}".format(signal_name))


def parse_args():
    parser = argparse.ArgumentParser(description='Interact with a Traffic Server process')
    parser.add_argument(
        'ts_identifier', help='An identifier in the command line for the desired '
        'Traffic Server process.')
    parser.add_argument('--signal', help='Send the given signal to the process.')

    return parser.parse_args()


def main():
    args = parse_args()
    try:
        process = get_ts_process_pid(args.ts_identifier)
    except GetPidError as e:
        print(traceback.format_exception(None, e, e.__traceback__), file=sys.stderr, flush=True)
        return 1

    if args.signal:
        signal_constant = convert_signal_name_to_signal(args.signal)
        process.send_signal(signal_constant)
    else:
        print(process.pid)
    return 0


if __name__ == '__main__':
    import doctest
    doctest.testmod()
    sys.exit(main())
