#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# Onionprobe test/monitor tool.
#
# Copyright (C) 2022 The Tor Project, Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published
# by the Free Software Foundation, either version 3 of the License,
# or any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

# Dependencies
import sys
import os
import signal

try:
    from .init        import OnionprobeInit
    from .config      import OnionprobeConfig
    from .logger      import OnionprobeLogger
    from .time        import OnionprobeTime
    from .tor         import OnionprobeTor
    from .descriptor  import OnionprobeDescriptor
    from .metrics     import OnionprobeMetrics
    from .prober      import OnionprobeProber
    from .http        import OnionprobeHTTP
    from .tls         import OnionprobeTLS
    from .certificate import OnionprobeCertificate
    from .teardown    import OnionprobeTeardown
    from .main        import OnionprobeMain
except ImportError:
    exit(1)

class Onionprobe(
        # Inherit from subsystems
        OnionprobeInit,
        OnionprobeConfig,
        OnionprobeLogger,
        OnionprobeTime,
        OnionprobeTor,
        OnionprobeDescriptor,
        OnionprobeMetrics,
        OnionprobeProber,
        OnionprobeHTTP,
        OnionprobeTLS,
        OnionprobeCertificate,
        OnionprobeTeardown,
        OnionprobeMain,
        ):
    """
    Onionprobe class to test and monitor Tor Onion Services
    """

def finish(status=0):
    """
    Stops Onionprobe

    :type  status: int
    :param status: Exit status code.
    """

    try:
        sys.exit(status)
    except SystemExit:
        os._exit(status)

def finish_handler(signal, frame):
    """
    Wrapper around finish() for handling system signals

    :type  signal: int
    :param signal: Signal number.

    :type  frame: object
    :param frame: Current stack frame.
    """

    print('Signal received, stopping Onionprobe..')

    finish(1)

def run(args):
    """
    Run Onionprobe from arguments

    :type  args: dict
    :param args: Instance arguments.
    """

    # Register signal handling
    #signal.signal(signal.SIGINT, finish_handler)
    signal.signal(signal.SIGTERM, finish_handler)

    # Exit status (shell convention means 0 is success, failure otherwise)
    status = 0

    # Dispatch
    try:
        probe = Onionprobe(args)

        if probe.initialize() is not False:
            status = 0 if probe.run() else 1
        else:
            status = 1

            print('Error: could not initialize')

    # Handle user interruption
    # See https://stackoverflow.com/questions/21120947/catching-keyboardinterrupt-in-python-during-program-shutdown
    except KeyboardInterrupt as e:
        probe.log('Stopping Onionprobe due to user request...')

    except FileNotFoundError as e:
        status = 1

        print('File not found: ' + str(e))

    except Exception as e:
        status = 1

        print(repr(e))

    finally:
        if 'probe' in locals():
            probe.close()

        finish(status)

def run_from_cmdline():
    """
    Run Onionprobe getting arguments from the command line.
    """

    from .config import cmdline

    run(cmdline())
