# -*- coding: utf-8 -*-
"""Callable classes for Transition Predicates.

All the classes here should be a callable and return either True/False when
called (to indicate whether or not to take a transition). All classes should
inherit from CallableBase class and annoate their constructor (if there is one)
with the @record_kwargs decorator for proper serialization.
"""
import time

from gabrieltool.statemachine.callable_zoo import record_kwargs
from gabrieltool.statemachine.callable_zoo import CallableBase


class HasObjectClass(CallableBase):
    """Check if there is an object class in the extracted information of the sensor data.
    """

    @record_kwargs
    def __init__(self, class_name):
        """Constructor.

        Args:
            class_name (string): Class name or id.
        """
        super().__init__()
        self.class_name = class_name

    def __call__(self, app_state):
        return self.class_name in app_state


class Always(CallableBase):
    """Always take this transition.

    Useful for welcome message when the application starts.
    """

    def __call__(self, app_state):
        return True


class HasObjectClassWhileNotOthers(CallableBase):
    """Check if there are some object classes in the extracted information while some other classes are not.
    """

    @record_kwargs
    def __init__(self, has_classes=None, absent_classes=None):
        """Constructor.

        Args:
            existed_classes (list of strings, optional): Names of classes that
                need to exist. Defaults to None.
            absent_classes (list of strings, optional): Name of classes that
                need to be absent. Defaults to None.
        """
        super().__init__()
        self.has_classes = has_classes if has_classes is not None else []
        self.absent_classes = absent_classes if absent_classes is not None else []

    def __call__(self, app_state):
        return all(
            [class_name in app_state for class_name in self.has_classes]) and all(
                [class_name not in app_state for class_name in self.absent_classes]
        )


class Wait(CallableBase):
    """Wait for some time before turning true.
    """

    @record_kwargs
    def __init__(self, wait_time=None):
        """Constructor.

        Args:
            wait_time (int, optional): Wait time in seconds. Defaults to None.
        """
        super().__init__()
        self.wait_time = wait_time if wait_time is not None else 0
        # set when this predicate this first called
        # or returned True in the last call.
        self._start_time = None

    def __call__(self, app_state):
        if self._start_time is None:
            self._start_time = time.time()
        else:
            cur_time = time.time()
            if (cur_time - self._start_time) > self.wait_time:
                # reset
                self._start_time = None
                return True
        return False

# -*- coding: utf-8 -*-
"""Callable classes for Transition Predicates.

All the classes here should be a callable and return either True/False when
called (to indicate whether or not to take a transition). All classes should
inherit from CallableBase class and annoate their constructor (if there is one)
with the @record_kwargs decorator for proper serialization.
"""
import time

from gabrieltool.statemachine.callable_zoo import record_kwargs
from gabrieltool.statemachine.callable_zoo import CallableBase


class HasObjectClass(CallableBase):
    """Check if there is an object class in the extracted information of the sensor data.
    """

    @record_kwargs
    def __init__(self, class_name):
        """Constructor.

        Args:
            class_name (string): Class name or id.
        """
        super().__init__()
        self.class_name = class_name

    def __call__(self, app_state):
        return self.class_name in app_state


class Always(CallableBase):
    """Always take this transition.

    Useful for welcome message when the application starts.
    """

    def __call__(self, app_state):
        return True


class HasObjectClassWhileNotOthers(CallableBase):
    """Check if there are some object classes in the extracted information while some other classes are not.
    """

    @record_kwargs
    def __init__(self, has_classes=None, absent_classes=None):
        """Constructor.

        Args:
            existed_classes (list of strings, optional): Names of classes that
                need to exist. Defaults to None.
            absent_classes (list of strings, optional): Name of classes that
                need to be absent. Defaults to None.
        """
        super().__init__()
        self.has_classes = has_classes if has_classes is not None else []
        self.absent_classes = absent_classes if absent_classes is not None else []

    def __call__(self, app_state):
        return all(
            [class_name in app_state for class_name in self.has_classes]) and all(
                [class_name not in app_state for class_name in self.absent_classes]
        )


class Wait(CallableBase):
    """Wait for some time before turning true.
    """

    @record_kwargs
    def __init__(self, wait_time=None):
        """Constructor.

        Args:
            wait_time (int, optional): Wait time in seconds. Defaults to None.
        """
        super().__init__()
        self.wait_time = wait_time if wait_time is not None else 0
        # set when this predicate this first called
        # or returned True in the last call.
        self._start_time = None

    def __call__(self, app_state):
        if self._start_time is None:
            self._start_time = time.time()
        else:
            cur_time = time.time()
            if (cur_time - self._start_time) > self.wait_time:
                # reset
                self._start_time = None
                return True
        return False

# -*- coding: utf-8 -*- Callable classes for Transition Predicates.  All the classes here should be a callable and return either True/False when called (to indicate whether or not to take a transition). All classes should inherit from CallableBase class and annoate their constructor (if there is one) with the @record_kwargs decorator for proper serialization. Check if there is an object class in the extracted information of the sensor data. Constructor.          Args:             class_name (string): Class name or id. Always take this transition.      Useful for welcome message when the application starts. Check if there are some object classes in the extracted information while some other classes are not. Constructor.          Args:             existed_classes (list of strings, optional): Names of classes that                 need to exist. Defaults to None.             absent_classes (list of strings, optional): Name of classes that                 need to be absent. Defaults to None. Wait for some time before turning true. Constructor.          Args:             wait_time (int, optional): Wait time in seconds. Defaults to None. # set when this predicate this first called # or returned True in the last call. # reset