# -*- coding: utf-8 -*- """ Composite Conditions - Kombiniert mehrere Conditions. """ from typing import Any from trixy_core.scheduler.condition.base import Condition class AndCondition(Condition): """ Prüft ob ALLE Sub-Conditions erfüllt sind. Beispiel: - AndCondition([TimeRangeCondition(...), DayOfWeekCondition(...)]) """ def __init__( self, conditions: list[Condition], name: str | None = None, invert: bool = False, ): """ Initialisiert die Condition. Args: conditions: Liste von Sub-Conditions name: Condition-Name invert: Ergebnis invertieren """ super().__init__(name, invert) if not conditions: raise ValueError("AndCondition benötigt mindestens eine Condition") self._conditions = list(conditions) @property def conditions(self) -> list[Condition]: """Sub-Conditions.""" return list(self._conditions) def add_condition(self, condition: Condition) -> None: """Fügt Condition hinzu.""" self._conditions.append(condition) def remove_condition(self, condition: Condition) -> bool: """Entfernt Condition.""" try: self._conditions.remove(condition) return True except ValueError: return False def _evaluate(self, context: dict) -> bool: """Prüft ob alle Conditions erfüllt sind.""" if not self._conditions: return True return all(c.evaluate(context) for c in self._conditions) @classmethod def display_name(cls) -> str: """Anzeigename fuer die TUI.""" return "UND-Bedingung" def to_dict(self) -> dict: """Konvertiert zu Dictionary.""" return { **self._base_dict(), "conditions": [c.to_dict() for c in self._conditions], } class OrCondition(Condition): """ Prüft ob MINDESTENS EINE Sub-Condition erfüllt ist. Beispiel: - OrCondition([StateCondition(...), BooleanCondition(...)]) """ def __init__( self, conditions: list[Condition], name: str | None = None, invert: bool = False, ): """ Initialisiert die Condition. Args: conditions: Liste von Sub-Conditions name: Condition-Name invert: Ergebnis invertieren """ super().__init__(name, invert) if not conditions: raise ValueError("OrCondition benötigt mindestens eine Condition") self._conditions = list(conditions) self._matched_condition: Condition | None = None @property def conditions(self) -> list[Condition]: """Sub-Conditions.""" return list(self._conditions) @property def matched_condition(self) -> Condition | None: """Zuletzt gematchte Condition.""" return self._matched_condition def add_condition(self, condition: Condition) -> None: """Fügt Condition hinzu.""" self._conditions.append(condition) def remove_condition(self, condition: Condition) -> bool: """Entfernt Condition.""" try: self._conditions.remove(condition) return True except ValueError: return False def _evaluate(self, context: dict) -> bool: """Prüft ob mindestens eine Condition erfüllt ist.""" if not self._conditions: return False for condition in self._conditions: if condition.evaluate(context): self._matched_condition = condition return True self._matched_condition = None return False @classmethod def display_name(cls) -> str: """Anzeigename fuer die TUI.""" return "ODER-Bedingung" def to_dict(self) -> dict: """Konvertiert zu Dictionary.""" return { **self._base_dict(), "conditions": [c.to_dict() for c in self._conditions], } class NotCondition(Condition): """ Invertiert eine Condition. Beispiel: - NotCondition(StateCondition("system_mode", "maintenance")) → Nur wenn NICHT im Wartungsmodus Hinweis: Kann auch über invert=True bei anderen Conditions erreicht werden. """ def __init__( self, condition: Condition, name: str | None = None, ): """ Initialisiert die Condition. Args: condition: Zu invertierende Condition name: Condition-Name """ # NOT Condition hat kein eigenes invert super().__init__(name, invert=False) self._condition = condition @property def condition(self) -> Condition: """Innere Condition.""" return self._condition def _evaluate(self, context: dict) -> bool: """Invertiert das Ergebnis der inneren Condition.""" return not self._condition.evaluate(context) @classmethod def display_name(cls) -> str: """Anzeigename fuer die TUI.""" return "NICHT-Bedingung" def to_dict(self) -> dict: """Konvertiert zu Dictionary.""" return { **self._base_dict(), "condition": self._condition.to_dict(), } class XorCondition(Condition): """ Prüft ob GENAU EINE Sub-Condition erfüllt ist. Beispiel: - XorCondition([ConditionA, ConditionB]) → Nur wenn A oder B, aber nicht beide """ def __init__( self, conditions: list[Condition], name: str | None = None, invert: bool = False, ): """ Initialisiert die Condition. Args: conditions: Liste von Sub-Conditions name: Condition-Name invert: Ergebnis invertieren """ super().__init__(name, invert) if len(conditions) < 2: raise ValueError("XorCondition benötigt mindestens zwei Conditions") self._conditions = list(conditions) @property def conditions(self) -> list[Condition]: """Sub-Conditions.""" return list(self._conditions) @classmethod def display_name(cls) -> str: """Anzeigename fuer die TUI.""" return "XOR-Bedingung" def _evaluate(self, context: dict) -> bool: """Prüft ob genau eine Condition erfüllt ist.""" results = [c.evaluate(context) for c in self._conditions] return sum(results) == 1 def to_dict(self) -> dict: """Konvertiert zu Dictionary.""" return { **self._base_dict(), "conditions": [c.to_dict() for c in self._conditions], }