#
# Copyright (C) 2019 Marko Myllynen <myllynen@redhat.com>
#
# 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 2 of the License, or
# (at your option) 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.
#
"""PCP netcheck PMDA helper routines"""

# pylint: disable=too-many-branches, too-many-locals, too-many-nested-blocks

try:
    from time import perf_counter as time
except ImportError:
    from time import time

from time import sleep
from threading import Thread
from collections import OrderedDict


class CheckRunner(object):
    """Check runner helper"""
    def __init__(self, dbg, log, err):
        """Constructor"""
        self._dbg = dbg
        self._log = log
        self._err = err

        self._objects = OrderedDict()
        self._threads = []

    def add_module(self, module, obj, interval, align):
        """Add module to check"""
        self._objects[module] = (obj, interval, align)

    def start(self):
        """Start check runner threads"""
        if not self._threads:
            for module in self._objects:
                thread = Thread(target=self._run_module_check, name=module,
                                args=(module, self._objects[module]))
                thread.setDaemon(True)
                thread.start()
                self._threads.append(thread)
            sleep(0.01)  # Yield

    def _run_module_check(self, module, params):
        """Run module check periodically"""
        obj, interval, align = params[0], params[1], params[2]
        aligned = "aligned" if align else "unaligned"
        self._log("Starting periodic %s check, %s interval: %d s." % (module, aligned, interval))
        while True:
            start_time = time()
            try:
                obj.do_check()
            except Exception as error:  # pylint: disable=broad-except
                self._err("%s: %s" % (module, str(error)))
                self._err("%s has failed, disabling!" % module)
            sleep_time = start_time + interval - time() if align else interval
            if sleep_time > 0:
                sleep(sleep_time)
