"""
Prototype 
"""
from .FLPair import FLPair
from .Feature import Feature
from .Base.LSTM import LSTM
from .Base.Item import Item
from .Base.WorkingMemory import WorkingMemory
from Narsese import Budget
from Narsese import Truth
import numpy as np


class Component(Item):
    def __init__(self, flpair: FLPair, parent: 'Prototype') -> None:
        super().__init__()

        self.flpair = flpair
        self.parent = parent

        self.truth_partof = Truth(0.0, 0.0) # the truth of the "part-of" relation
        self.truth_event = Truth(0.0, 0.0) # the truth of the event

        self.truth_anticipation = Truth(0.0, 0.0) # the anticipated truth of the component

        

class Prototype(Item):
    def __init__(self, capacity: int=7, capacity_instances: int=None, budget_m: Budget=None, budget_c: Budget=None) -> None:
        Item.__init__(self, budget_m, budget_c)
        self.components_memory = LSTM[Component](capacity, capacity)
        self.components_workspace = WorkingMemory[Component](capacity*2)
        self.components = dict[FLPair, Component]()

        self.truth_event = Truth(0.0, 0.0)
        self.truth_anticipation = Truth(0.0, 0.0)
        
        self.loc_now = np.array([0.0, 0.0]) # 当前的观察点在prototype中的相对位置。 取值范围：[-1, 1]
        # self.instances = WorkingMemory[Instance](capacity_instances if capacity_instances is not None else capacity*5)

        self.scale = 11.0

    def new_component(self, flpair: FLPair):
        if flpair in self.components:
            return None
        component = Component(flpair, self)
        self.components_memory.insert(component)
        self.components_workspace.insert(component)

        self.components[flpair] = component

        return 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

        for component in self.components.values():
            component.budget_m.decay(ts_now - component.budget_m.ts_update)
            component.budget_m.ts_update = ts_now
            component.budget_c.decay(ts_now - component.budget_c.ts_update)
            component.budget_c.ts_update = ts_now

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

    def move(self, dx, dy):
        """
        移动
        """
        self.loc_now[0] += dx
        self.loc_now[1] += dy
        self.loc_now[0] = (self.loc_now[0]+1)%2-1
        self.loc_now[1] = (self.loc_now[1]+1)%2-1
        return self.loc_now
    
    def move_to(self, x, y):
        x = (x+1)%2-1
        y = (y+1)%2-1
        self.loc_now[:] = (x, y)
        return self.loc_now

    def __len__(self):
        return len(self.components_workspace)



if __name__ == "__main__":
    proto = Prototype()
