from abc import ABC, abstractmethod


class EffectiveTimeRange(ABC):
    """
    *Abstract class*

    A time range specification that is able to check
    if the values provided in a context are included
    or not in that time range.

    This class must be have specific implementations
    according to the time space.
    """

    @abstractmethod
    def is_active(
        self,
        evaluation_context: 'VideoEditorEvaluationContext',
        do_include_end: bool = False
    ) -> bool:
        """
        Check if the `evaluation_context` is included or not
        in this time range, including the `end` only if the
        `do_include_end` boolean flag is `True`.
        """
        pass

"""
Specific implementations below
"""
class LocalTimeNormalizedEffectiveTimeRange(EffectiveTimeRange):
    """
    An effective time range that is using a local time
    normalized space. The `start` and `end` values are
    normalized values in the `[0.0, 1.0]` range.
    """

    def __init__(
        self,
        start: float,
        end: float  
    ):
        self.start: float = start
        """
        The normalized local time moment in which the time range
        starts.
        """
        self.end: float = end
        """
        The normalized local time moment in which the time range
        ends.
        """

    def is_active(
        self,
        evaluation_context: 'VideoEditorEvaluationContext',
        do_include_end: bool = False
    ) -> bool:
        """
        Check if the `evaluation_context` is included or not
        in this time range, including the `end` only if the
        `do_include_end` boolean flag is `True`.

        This method will compare the `t_normalized` value of
        the `evaluation_context` provided.
        """
        return (
            self.start <= evaluation_context.t_normalized <= self.end
            if do_include_end else
            self.start <= evaluation_context.t_normalized < self.end
        )
    
class LocalTimeEffectiveTimeRange(EffectiveTimeRange):
    """
    An effective time range that is using a local time
    space. The `start` and `end` values are not normalized
    values.
    """

    def __init__(
        self,
        start: float,
        end: float  
    ):
        self.start: float = start
        """
        The not normalized local time moment in which the time range
        starts.
        """
        self.end: float = end
        """
        The not normalized local time moment in which the time range
        ends.
        """

    def is_active(
        self,
        evaluation_context: 'VideoEditorEvaluationContext',
        do_include_end: bool = False
    ) -> bool:
        """
        Check if the `evaluation_context` is included or not
        in this time range, including the `end` only if the
        `do_include_end` boolean flag is `True`.

        This method will compare the `t` value of the
        `evaluation_context` provided.
        """
        return (
            self.start <= evaluation_context.t <= self.end
            if do_include_end else
            self.start <= evaluation_context.t < self.end
        )
    
class LocalFrameIndexesEffectiveTimeRange(EffectiveTimeRange):
    """
    An effective time range that is using a frames time
    space. The `start` and `end` values are frame indexes.
    """

    def __init__(
        self,
        start: int,
        end: int  
    ):
        self.start: int = start
        """
        The frame index in which the time range starts.
        """
        self.end: int = end
        """
        The frame index in which the time range ends.
        """

    def is_active(
        self,
        evaluation_context: 'VideoEditorEvaluationContext',
        do_include_end: bool = False
    ) -> bool:
        """
        Check if the `evaluation_context` is included or not
        in this time range, including the `end` only if the
        `do_include_end` boolean flag is `True`.

        This method will compare the `frame_index` value of
        the `evaluation_context` provided.
        """
        return (
            self.start <= evaluation_context.frame_index <= self.end
            if do_include_end else
            self.start <= evaluation_context.frame_index < self.end
        )