"""
Composition Statement
C |-> P
"""

from .Concept import Concept
from Narsese import Budget, Truth
from .Location import Location
from Model.Base.Item import Item, Mirror
from copy import copy

class Belief(Item):
    def __init__(self, concept: Concept, truth_event: Truth = None, truth_anticipation: Truth = None, budget_m: Budget = None, budget_c: Budget = None):
        super().__init__(budget_m, budget_c)
        self.concept = concept

        self.truth_event = truth_event if truth_event is not None \
            else Truth(0.0, 0.0)  # the truth of the event
        self.truth_anticipation = truth_anticipation if truth_anticipation is not None \
            else Truth(0.0, 0.0)  # the anticipated truth of the component
        
    def decay(self, ts_now: float, duration=20):
        self.budget_m.decay(ts_now - self.budget_m.ts_update)
        self.budget_m.ts_update = ts_now
        self.budget_c.decay(ts_now - self.budget_c.ts_update)
        self.budget_c.ts_update = ts_now

        self.truth_event.decay(
            Truth.get_decay_factor(duration),
            ts_now - self.truth_event.ts_update)
        self.truth_event.ts_update = ts_now

        self.truth_anticipation.decay(
            Truth.get_decay_factor(duration),
            ts_now - self.truth_event.ts_update)
        self.truth_anticipation.ts_update = ts_now

    def __repr__(self) -> str:
        return f"<Belief({str(hex(id(self.concept)))[-4:]}.{str(hex(id(self)))[-4:]}): {self.concept}. {self.truth_event}>"


class Composition(Concept):
    def __init__(self, part: Belief, whole: Concept, location: Location, truth: Truth=None, budget_m: Budget=None, budget_c: Budget=None) -> None:
        super().__init__(budget_m, budget_c)
        self.part = part
        self.whole = whole
        self.truth = truth if truth is not None else Truth(0.0, 0.0)
        self.location = location  # Relative location of part in whole

    def __repr__(self) -> str:
        return f"<{str(hex(id(self.part.concept)))[-4:]} |-> {self.whole}>. [({self.location.center[0]:.2f},{self.location.center[1]:.2f})] {self.truth}"


class CompositionMirror(Mirror):
    item: Composition
    def __init__(self, item: Composition, budget_m: Budget=None, budget_c: Budget=None) -> None:
        super().__init__(item, budget_m, budget_c)
        self.truth_event = copy(item.part.truth_event)
        self.truth_anticipation = copy(item.part.truth_anticipation)

    def decay(self, ts_now: float, duration=20):
        super().decay(ts_now, duration)
        self.truth_event.decay(
            Truth.get_decay_factor(duration),
            ts_now - self.truth_event.ts_update)
        self.truth_event.ts_update = ts_now

        self.truth_anticipation.decay(
            Truth.get_decay_factor(duration),
            ts_now - self.truth_event.ts_update)
        self.truth_anticipation.ts_update = ts_now

    def __repr__(self) -> str:
        return f"<CompositionMirror({str(hex(id(self.item.part.concept)))[-4:]}.{str(hex(id(self.item)))[-4:]}): {self.budget_c}>"