"""Contains definitions of various executors"""
import abc

from failsafe.failsafe import Failsafe


class IExecutor(object):
    """Interface of the executor"""

    @abc.abstractmethod
    def execute(self, func, **kwargs):
        """
        :param func: Action to be performed
        """
        pass


class Decorator(IExecutor):
    """
    Standard decorator design pattern
    """
    def __init__(self, parent=None):
        assert not parent or isinstance(parent, IExecutor)
        self._parent = parent

    def execute(self, func, **kwargs):
        """
        @param func: the action to be performed
        @return: Any, the result of the action
        """
        if self._parent:
            return self._parent.execute(func, **kwargs)
        return func()

    def __call__(self, *args, **kwargs):
        """
        Convenience method to invoke the `execute` function.
        Just a syntactic sugar to make it look more Pythonic
        """
        return self.execute(*args, **kwargs)


class _BasicExecutorImpl(Decorator):
    """
    A basic no-op executor. Simply invokes the given
    function and returns the response.
    """

    def __init__(self, parent):
        super(_BasicExecutorImpl, self).__init__(parent)

    def execute(self, func, **kwargs):
        """Executes the given function and returns the response"""
        return super(_BasicExecutorImpl, self).execute(func, **kwargs)


class _FailSafeExecutorImpl(Decorator):
    """
    A basic no-op executor. Simply invokes the given
    function and returns the response.
    """

    def __init__(self):
        super(_FailSafeExecutorImpl, self).__init__()

    def execute(self, func, **kwargs):
        """Executes the given function and returns the response"""

        def wrapper(*args, **kwargs):
            return super(_FailSafeExecutorImpl, self).execute(func)
        err_threshold = kwargs.get('err_threshold')
        request_volume_window = kwargs.get('request_volume_window')
        reset_timeout = kwargs.get('reset_timeout')
        svc = kwargs.get('svc_name')
        failsafe = Failsafe(service_name=svc)
        breaker = failsafe.breaker(err_threshold=err_threshold,
                                   request_volume_window=request_volume_window,
                                   reset_timeout=reset_timeout)
        return breaker(wrapper)(key=kwargs.get('key'))


failsafe_executor = _FailSafeExecutorImpl()
basic_executor = _BasicExecutorImpl(parent=failsafe_executor)
