matejak/estimagus

View on GitHub
estimage/entities/model.py

Summary

Maintainability
A
0 mins
Test Coverage
A
92%
import typing

from .estimate import Estimate
from .task import TaskModel
from .composition import Composition
from .card import BaseCard


class EstiModel:
    name_result_map: typing.Mapping[str, TaskModel]
    name_composition_map: typing.Mapping[str, Composition]
    main_composition: Composition

    def __init__(self):
        self.main_composition = self._get_main_composition()
        self.name_result_map = dict()
        self.name_composition_map = dict()

    def use_composition(self, composition: Composition):
        if composition.name:
            self.main_composition = Composition("")
            self.main_composition.add_composition(composition)
        else:
            self.main_composition = composition
            self.main_composition.name = ""

        self.name_result_map = dict()
        self.name_composition_map = dict()
        self._reconstruct_entities_map(self.main_composition)

    def _reconstruct_entities_map(self, current_composition):
        for t in current_composition.elements:
            self.name_result_map[t.name] = t
        for c in current_composition.compositions:
            self._reconstruct_entities_map(c)
            self.name_composition_map[c.name] = c

    def get_all_task_models(self):
        return list(self.name_result_map.values())

    def _get_main_composition(self):
        return Composition("")

    def _get_new_element(self, name):
        return TaskModel(name)

    def new_element(self, name: str):
        e = self._get_new_element(name)
        self.add_element(e)

    def add_element(self, element):
        if (name := element.name) in self.name_result_map:
            raise RuntimeError(f"Already encountered element of name {name}")
        self.name_result_map[name] = element
        return self.main_composition.add_element(element)

    @property
    def nominal_point_estimate(self):
        return self.main_composition.nominal_point_estimate

    @property
    def remaining_point_estimate(self):
        return self.main_composition.remaining_point_estimate

    def nominal_point_estimate_of(self, name: str) -> Estimate:
        if name in self.name_result_map:
            return self.name_result_map[name].nominal_point_estimate
        elif name in self.name_composition_map:
            return self.name_composition_map[name].nominal_point_estimate
        else:
            msg = f"Entity '{name}' is not known."
            raise KeyError(msg)

    def remaining_point_estimate_of(self, name: str) -> Estimate:
        if name in self.name_result_map:
            return self.name_result_map[name].remaining_point_estimate
        elif name in self.name_composition_map:
            return self.name_composition_map[name].remaining_point_estimate
        else:
            msg = f"Entity '{name}' is not known."
            raise KeyError(msg)

    def time_estimate_of(self, name: str):
        return self.name_result_map[name].time_estimate

    def estimate_points_of(self, name, est_input):
        self.name_result_map[name].set_point_estimate(
            est_input.most_likely, est_input.optimistic, est_input.pessimistic
        )

    def estimate_time_of(self, name, est_input):
        self.name_result_map[name].set_time_estimate(
            est_input.most_likely, est_input.optimistic, est_input.pessimistic
        )

    def complete_element(self, name):
        element = self.name_result_map[name]
        element.nullify()

    def get_element(self, name):
        return self.name_result_map[name]

    def update_cards_with_values(self, cards: typing.Container[BaseCard]):
        for t in cards:
            self._update_card(t)

    def _update_card(self, card: BaseCard):
        for dep in card.children:
            self._update_card(dep)
        if card.name not in self.name_result_map:
            return
        element = self.name_result_map[card.name]
        card.point_cost = element.nominal_point_estimate.expected
        card.time_cost = element.nominal_time_estimate.expected

    def export_element(self, name: str) -> BaseCard:
        card = BaseCard(name)
        self._update_card(card)
        return card