import threading
import logging

logger = logging.getLogger(__name__)
logger.addHandler(logging.NullHandler())

class Loop(threading.Thread):
    """Calls a function every interval seconds:

            t = Loop(30.0, f, args=[], kwargs={})
            t.start()
            t.cancel()     # stop the loop's action if it's still waiting

    """

    STOP = True
    CONTINUE = False

    def __init__(self, interval, function, name=None, restart=False, args=[], kwargs={}):
        super(Loop, self).__init__(name=name)
        self.current_interval = 0
        self.interval = interval
        self.function = function
        self.args = args
        self.kwargs = kwargs
        self.finished = threading.Event()
        self.running = threading.Event()
        self.running.set()
        self.daemon = True
        self.restart = restart

    def start(self, paused=False):
        if paused:
            self.running.clear()
        super(Loop, self).start()

    def set_interval(self, interval):
        self.interval = interval

    def is_finished(self):
        return self.finished.is_set()

    def pause(self):
        self.running.clear()

    def unpause(self):
        self.running.set()

    def is_paused(self):
        return not self.running.is_set()

    def finish(self):
        self.unpause()
        self.finished.set()

    def cancel(self):
        self.finish()
        self.join()

    def run(self):
        logging.info("Starting loop {}".format(self.name))

        while True:
            try:
                while not self.finished.is_set():
                    self.finished.wait(self.current_interval)
                    self.running.wait()
                    if not self.finished.is_set():
                        stop = self.function(*self.args, **self.kwargs)
                        if stop:
                            break
                    else:
                        break
                    self.current_interval = self.interval
                break
            except Exception as e:
                logging.error("Exception in loop {}: {}".format(self.name, str(e)))
                if not self.restart:
                    break
                logging.info("Restarting loop {}".format(self.name))

        logging.info("Stopped loop {}".format(self.name))