from .. import constants, logger
from . import base_classes, api


class Object(base_classes.BaseNode):
    """Class that wraps an object node"""
    def __init__(self, node, parent=None, type=None):
        logger.debug("Object().__init__(%s)", node)
        base_classes.BaseNode.__init__(self, node, parent=parent, type=type)

        if self.node:
            self._node_setup()
        else:
            self._root_setup()

    @property
    def data(self):
        """

        :return: returns the data block of the node

        """
        return api.data(self.node)


    def _init_camera(self):
        """Initialize camera attributes"""
        logger.debug("Object()._init_camera()")
        self[constants.FAR] = api.camera.far(self.data)
        self[constants.NEAR] = api.camera.near(self.data)

        if self[constants.TYPE] == constants.PERSPECTIVE_CAMERA:
            self[constants.ASPECT] = api.camera.aspect(self.data)
            self[constants.FOV] = api.camera.fov(self.data)
        elif self[constants.TYPE] == constants.ORTHOGRAPHIC_CAMERA:
            self[constants.LEFT] = api.camera.left(self.data)
            self[constants.RIGHT] = api.camera.right(self.data)
            self[constants.TOP] = api.camera.top(self.data)
            self[constants.BOTTOM] = api.camera.bottom(self.data)

    #@TODO: need more light attributes. Some may have to come from
    #       custom blender attributes.
    def _init_light(self):
        """Initialize light attributes"""
        logger.debug("Object()._init_light()")
        self[constants.COLOR] = api.light.color(self.data)
        self[constants.INTENSITY] = api.light.intensity(self.data)

        # Commented out because Blender's distance is not a cutoff value.
        #if self[constants.TYPE] != constants.DIRECTIONAL_LIGHT:
        #    self[constants.DISTANCE] = api.light.distance(self.data)
        self[constants.DISTANCE] = 0;

        lightType = self[constants.TYPE]
        if lightType == constants.SPOT_LIGHT:
            self[constants.ANGLE] = api.light.angle(self.data)
            self[constants.DECAY] = api.light.falloff(self.data)
        elif lightType == constants.POINT_LIGHT:
            self[constants.DECAY] = api.light.falloff(self.data)

    def _init_mesh(self):
        """Initialize mesh attributes"""
        logger.debug("Object()._init_mesh()")
        mesh = api.object.mesh(self.node, self.options)
        node = self.scene.geometry(mesh)
        if node:
            self[constants.GEOMETRY] = node[constants.UUID]
        else:
            msg = "Could not find Geometry() node for %s"
            logger.error(msg, self.node)

    def _node_setup(self):
        """Parse common node attributes of all objects"""
        logger.debug("Object()._node_setup()")
        self[constants.NAME] = api.object.name(self.node)

        transform = api.object.matrix(self.node, self.options)
        matrix = []
        for col in range(0, 4):
            for row in range(0, 4):
                matrix.append(transform[row][col])

        self[constants.MATRIX] = matrix

        self[constants.VISIBLE] = api.object.visible(self.node)

        self[constants.TYPE] = api.object.node_type(self.node)

        if self.options.get(constants.MATERIALS):
            logger.info("Parsing materials for %s", self.node)
            material_name = api.object.material(self.node)
            if material_name:
                logger.info("Material found %s", material_name)
                material_inst = self.scene.material(material_name)
                self[constants.MATERIAL] = material_inst[constants.UUID]
            else:
                logger.info("%s has no materials", self.node)

        casts_shadow = (constants.MESH,
                        constants.DIRECTIONAL_LIGHT,
                        constants.SPOT_LIGHT)

        if self[constants.TYPE] in casts_shadow:
            logger.info("Querying shadow casting for %s", self.node)
            self[constants.CAST_SHADOW] = \
                api.object.cast_shadow(self.node)

        if self[constants.TYPE] == constants.MESH:
            logger.info("Querying shadow receive for %s", self.node)
            self[constants.RECEIVE_SHADOW] = \
                api.object.receive_shadow(self.node)

        camera = (constants.PERSPECTIVE_CAMERA,
                  constants.ORTHOGRAPHIC_CAMERA)

        lights = (constants.AMBIENT_LIGHT,
                  constants.DIRECTIONAL_LIGHT,
                  constants.POINT_LIGHT,
                  constants.SPOT_LIGHT, constants.HEMISPHERE_LIGHT)

        if self[constants.TYPE] == constants.MESH:
            self._init_mesh()
        elif self[constants.TYPE] in camera:
            self._init_camera()
        elif self[constants.TYPE] in lights:
            self._init_light()

        no_anim = (None, False, constants.OFF)
        if self.options.get(constants.KEYFRAMES) not in no_anim:
            logger.info("Export Transform Animation for %s", self.node)
            if self._scene:
                # only when exporting scene
                tracks = api.object.animated_xform(self.node, self.options)
                merge = self._scene[constants.ANIMATION][0][constants.KEYFRAMES]
                for track in tracks:
                    merge.append(track)

        if self.options.get(constants.HIERARCHY, False):
            for child in api.object.children(self.node, self.scene.valid_types):
                if not self.get(constants.CHILDREN):
                    self[constants.CHILDREN] = [Object(child, parent=self)]
                else:
                    self[constants.CHILDREN].append(Object(child, parent=self))

        if self.options.get(constants.CUSTOM_PROPERTIES, False):
            self[constants.USER_DATA] = api.object.custom_properties(self.node)

    def _root_setup(self):
        """Applies to a root/scene object"""
        logger.debug("Object()._root_setup()")
        self[constants.MATRIX] = [1, 0, 0, 0, 0, 1, 0, 0, 0, 0,
                                  1, 0, 0, 0, 0, 1]
