"""A module providing a class to represent the objects that contain a feature of 
CAD geometry. In most CAD applications this may be the same as the CAD file, but 
some applications have subgroups, folders, and bodies (bodies that are not a 
feature by themselves, but just contain other geometry, like Bodies and Parts in 
FreeCAD). Separating the software owner of a feature from the geometry 
dependencies and children should allow these concepts to be translated 
between applications.
"""
from __future__ import annotations

from typing import TYPE_CHECKING

from pancad.abstract import AbstractFeature
from pancad.geometry.system import FeatureSystem
from pancad.geometry.coordinate_system import Pose
from pancad.geometry.unique_lists import FeatureGeometryList
from pancad.utils.initialize import get_pancad_config

if TYPE_CHECKING:
    from typing import Sequence, Self

DEFAULT_NAME = get_pancad_config()["features"]["default_names"] \
                                  ["feature_container"]

class FeatureContainer(AbstractFeature):
    """A class representing a grouping of features in CAD applications. Commonly
    called a 'Containment Tree' or 'Feature Tree' in CAD GUIs.

    :param pose: The position and orientation of the container. If None is
        provided, initializes as unrotated at the origin.
    :param name: The name of the feature displayed to the users in CAD.
    :param uid: The unique id of the FeatureContainer. Autogenerated when not
        provided.
    :param system: The system the pose of the container is defined by.
    """
    def __init__(self, pose: Pose=None, feature_system=None, *,
                 name: str=DEFAULT_NAME,
                 system: FeatureSystem=None,
                 uid: str=None) -> None:
        super().__init__(system, name)
        self.uid = uid
        if pose is None:
            pose = Pose.from_yaw_pitch_roll((0, 0, 0), 0, 0, 0)
        if feature_system is None:
            feature_system = FeatureSystem()
        self._pose = pose
        self._feature_system = feature_system
        self._feature_geometry = FeatureGeometryList(
            self, [self.pose, self.feature_system]
        )

    # Properties
    @property
    def feature_system(self) -> FeatureSystem:
        """The system of features owned by this container. Read-only."""
        return self._feature_system

    @property
    def feature_geometry(self) -> FeatureGeometryList:
        """The geometry directly owned by this container. Usually its Pose and 
        FeatureSystem.
        """
        return self._feature_geometry

    @property
    def pose(self) -> Pose:
        """The location and orientation of the container."""
        return self._pose
    @pose.setter
    def pose(self, value: Pose) -> None:
        self._pose.update(value)

    # Python Dunders #
    def __contains__(self, item: object) -> bool:
        return item is self or item in self.feature_system or item is self.pose

    def __repr__(self) -> str:
        return super().__repr__().format(details=f"'{self.name}'")
