import threading


class AbstractThread(object):
    """
    Simple thread wrapper with support for stopping by request.
    """

    def __init__(self, *args):
        self.__args = args
        self.__alive = True
        self.__t = None

    def is_alive(self):
        """
        Determine if the thread is running and not terminating.
        """
        return self.__t is not None and self.__alive and self.__t.is_alive()

    def is_finished(self):
        """
        Determine if the thread has started and is still running.
        """
        return self.__t is not None and not self.__t.is_alive()

    def _keep_running(self):
        """
        The thread should poll this periodically to check if it has to terminate.
        """
        return self.__alive

    def start(self, callback=None, daemon=True, name_prefix=None):
        if self.__t is not None or not self.__alive:
            raise Exception(f"Restarting {self.__class__.__name__} is not supported")
        self.__t = threading.Thread(
            target=self._thread_wrapper,
            args=(callback, self.__args),
            daemon=daemon,
            name=f"{name_prefix}-{self.__class__.__name__}" if name_prefix else self.__class__.__name__,
        )
        del self.__args
        self.__t.start()

    def stop(self, timeout=5.0):
        self.__alive = False
        if timeout > 0 and not self.is_finished():
            self.__t.join(timeout)

    def _thread_wrapper(self, callback, args):
        try:
            self._thread(*args)
        finally:
            if callback:
                callback()

    def _thread(self, *args):
        raise NotImplementedError()
