<gh_stars>1-10
"""
compound attribute object library
"""

# imports third-parties
import maya.cmds
import cgp_generic_utils.constants

# imports local
import cgp_maya_utils.constants
from . import _generic


# BASE OBJECT #


class CompoundAttribute(_generic.Attribute):
    """attribute object that manipulates any kind of compound attribute
    """

    # ATTRIBUTES #

    _attributeType = cgp_maya_utils.constants.AttributeType.COMPOUND
    _attributeSubType = NotImplemented

    # OBJECT COMMANDS #

    @classmethod
    def create(cls, node, name, components=None, value=None, connections=None, **__):
        """create a compound attribute

        :param node: node on which to create the attribute
        :type node: str

        :param name: name of the attribute to create
        :type name: str

        :param components: components used to create the attribute - default is Axis.ALL
        :type components: any

        :param value: value to set on the attribute
        :type value: list[any]

        :param connections: connection to build on the attribute - {'source': obj.attr, 'destinations': [obj.attr ...]}
        :type connections: dict

        :return: the created attribute
        :rtype: :class:`cgp_maya_utils.scene.CompoundAttribute`
        """

        # init
        components = components or cgp_generic_utils.constants.Axis.ALL

        # execute
        maya.cmds.addAttr(node, longName=name, attributeType=cls._attributeType)

        for component in components:
            maya.cmds.addAttr(node, longName=component, attributeType=cls._attributeSubType, parent=name)

        # get attribute object
        attrObject = cls('{0}.{1}'.format(node, name))

        # set if value specified
        if value:
            attrObject.setValue(value)

        # connect attribute if specified
        if connections:
            attrObject.connect(source=connections['source'], destinations=connections['destinations'])

        # return
        return attrObject

    # COMMANDS #

    def components(self):
        """the components of the compound attribute

        :return: the components of the compound attribute
        :rtype: list[:class:`cgp_maya_utils.sceneAttribute`]
        """

        # get components
        components = maya.cmds.attributeQuery(self.name(), node=self.node().name(), listChildren=True)

        # return
        return [self.node().attribute(component) for component in components]

    def data(self, skipConversionNodes=True):
        """data necessary to store the compound attribute on disk and/or recreate it from scratch

        :param skipConversionNodes: ``True`` : conversion nodes are skipped - ``False`` conversion nodes are not skipped
        :type skipConversionNodes: bool

        :return: the data of the compound attribute
        :rtype: dict
        """

        # init
        data = super(CompoundAttribute, self).data(skipConversionNodes=skipConversionNodes)

        # update data
        data['components'] = [component.name() for component in self.components()]

        # return
        return data

    def setValue(self, value):
        """set the value of the compound attribute

        :param value: value to set on the compound attribute
        :type value: list[any]
        """

        # execute
        maya.cmds.setAttr(self.fullName(), type=self.attributeType(), *value)

    def subType(self):
        """the subType of the compound attribute

        :return: the subType of the compound attribute
        :rtype: str
        """

        # return
        return self._attributeSubType

    def value(self):
        """the value of the compound attribute

        :return: the value of the compound attribute
        :rtype: any
        """

        # return
        return maya.cmds.getAttr(self.fullName())[0]


# COMPOUND ATTRIBUTES #


class Double3Attribute(CompoundAttribute):
    """attribute object that manipulates ``double3`` attribute
    """

    # ATTRIBUTES #

    _attributeType = cgp_maya_utils.constants.AttributeType.DOUBLE3
    _attributeSubType = cgp_maya_utils.constants.AttributeType.DOUBLE


class Float3Attribute(CompoundAttribute):
    """attribute object that manipulates ``float3`` attribute
    """

    # ATTRIBUTES #

    _attributeType = cgp_maya_utils.constants.AttributeType.FLOAT3
    _attributeSubType = cgp_maya_utils.constants.AttributeType.FLOAT


class TDataCompoundAttribute(CompoundAttribute):
    """attribute object that manipulates ``TDataCompound`` attribute
    """

    # ATTRIBUTES #

    _attributeType = cgp_maya_utils.constants.AttributeType.TDATACOMPOUND
    _attributeSubType = None

    # OBJECT COMMANDS #

    @classmethod
    def create(cls, *_, **__):
        """create a TDataCompound attribute
        """

        # errors
        raise UserWarning('{0} attribute can\'t be created by API'.format(cls._attributeType))

    # COMMANDS #

    def setValue(self, value):
        """set the value of the TDataCompound attribute

        :param value: value to set to the TDataCompound attribute
        :type value: dict
        """

        # execute
        for attribute, attributeValue in value.items():
            self.node().attribute(attribute).setValue(attributeValue)

    def value(self):
        """the value of the TDataCompound attribute

        :return: the value of the TDataCompound attribute
        :rtype: dict
        """

        # init
        value = {}

        # execute
        for component in self.components():
            value[component.name()] = component.value()

        # return
        return value
