from direct.directnotify import DirectNotifyGlobal
from panda3d.core import *

import NametagGlobals


class ChatBalloon:
    notify = DirectNotifyGlobal.directNotify.newCategory('ChatBalloon')

    def __init__(self, node=None):
        if isinstance(node, NodePath):
            node = node.node()

        self.m_copy_node = None
        self.m_top_node = None
        self.m_top_mat = None
        self.m_middle_node = None
        self.m_middle_mat = None
        self.m_bottom_node = None
        self.m_bottom_mat = None

        self.m_hscale = 0
        self.m_text_height = 0
        self.m_text_frame = Vec4(0)

        self.scan(node)

    @staticmethod
    def find_geom_node(node):
        if node.isGeomNode():
            return node

        for i in xrange(node.getNumChildren()):
            n = ChatBalloon.find_geom_node(node.getChild(i))
            if n:
                return n

        return None

    @staticmethod
    def find_middle_geom(node):
        if not node.getNumChildren():
            return None

        child = None
        for i in xrange(node.getNumChildren()):
            child = node.getChild(i)
            if child.getName() == 'middle':
                return n

            n = ChatBalloon.find_middle_geom(child)
            if n:
                return n

        return ChatBalloon.find_geom_node(child)

    def scan(self, node):
        if node.getName() == 'chatBalloon':
            return self.scan_balloon(node)

        for i in xrange(node.getNumChildren()):
            if self.scan(node.getChild(i)):
                return True

        return False

    def scan_balloon(self, node):
        self.m_copy_node = node.copySubgraph()

        for i in xrange(node.getNumChildren()):
            child = node.getChild(i)
            if child.getName() == 'top':
                self.m_top_node = child
                self.m_top_mat = child.getTransform().getMat()

            elif child.getName() == 'middle':
                self.m_middle_node = child
                self.m_middle_mat = child.getTransform().getMat()

            elif child.getName() == 'bottom':
                self.m_bottom_node = child
                self.m_bottom_mat = child.getTransform().getMat()

        if self.m_top_node and self.m_middle_node and self.m_bottom_node:
            return True

        else:
            self.notify.warning('ChatBalloon geometry does not include top, middle, and bottom nodes.')
            return False

    def generate(self, text, font, wordwrap, text_color, balloon_color, for_3d,
                 has_draw_order, draw_order, page_button, space_for_button,
                 reversed, new_button):  # new_button is a pointer, let's use a list hack here
        chat_node = PandaNode('chat')
        chat_node.setAttrib(CullFaceAttrib.make(0))
        text_node = NametagGlobals.getTextNode()
        text_node.setFont(font)
        text_node.setWordwrap(wordwrap)
        text_node.setAlign(TextNode.ALeft)
        text_node.setText(text)

        v116 = NametagGlobals._balloon_text_origin[0]
        if reversed:
            v116 = v116 + 9.0

        v27 = (text_node.getRight() - text_node.getLeft()) * 0.11111111
        self.m_hscale = v27

        if v27 < 0.25:
            self.m_hscale = 0.25
            text_node.setAlign(TextNode.ACenter)

            v29 = v116
            if not reversed:
                v116 = v29 + 4.5

            else:
                v116 = v29 - 4.5

        elif reversed:
            self.m_hscale = -self.m_hscale

        self.m_text_frame = text_node.getCardActual()
        _space = 0.2 if space_for_button else 0.0
        num_rows = max(1, text_node.getNumRows())
        _num_rows = num_rows
        line_h = text_node.getFont().getLineHeight()

        num_rows_minus_1 = num_rows - 1
        subgraph_copy_mat = Mat4(self.m_hscale, 0, 0, 0,
                                 0, 1.0, 0, 0,
                                 0, 0, 1.0, 0,
                                 0, 0, 0, 1.0)
        text_h = _num_rows * line_h + _space
        self.m_text_height = text_h

        v132 = num_rows_minus_1 * line_h + _space

        middle_mat = Mat4(1, 0, 0, 0,
                          0, 1, 0, 0,
                          0, 0, text_h, 0,
                          0, 0, 0, 1) * self.m_middle_mat
        top_mat = Mat4(1, 0, 0, 0,
                       0, 1, 0, 0,
                       0, 0, 1, 0,
                       0, 0, text_h - 1.0, 1) * self.m_top_mat

        v137 = v116 * self.m_hscale
        v138 = 0.0
        v139 = NametagGlobals._balloon_text_origin[2] + v132 + 0.2

        self.m_text_frame += Vec4(v137, v137, v139, v139)

        '''
        Correct code:
        Python won't let us edit this transform, we'll have to copy it all

        if self.m_top_node:
            self.m_top_node.setTransform(TransformState.makeMat(top_mat))

        if self.m_middle_node:
            self.m_middle_node.setTransform(TransformState.makeMat(middle_mat))

        subgraph_copy = self.m_copy_node.copySubgraph()
        chat_node.addChild(subgraph_copy)
        subgraph_copy.setTransform(TransformState.makeMat(subgraph_copy_mat))
        '''

        # BEGIN PYTHON CODE
        subgraph_copy = self.m_copy_node.copySubgraph()
        NodePath.anyPath(subgraph_copy).find('**/top').node().setTransform(TransformState.makeMat(top_mat))
        NodePath.anyPath(subgraph_copy).find('**/middle').node().setTransform(TransformState.makeMat(middle_mat))

        chat_node.addChild(subgraph_copy)
        subgraph_copy.setTransform(TransformState.makeMat(subgraph_copy_mat))
        # END PYTHON CODE

        if has_draw_order:
            bin = config.GetString('nametag-fixed-bin', 'fixed')
            subgraph_copy.setAttrib(CullBinAttrib.make(bin, draw_order))

        subgraph_copy.setAttrib(ColorAttrib.makeFlat(balloon_color))
        if balloon_color[3] != 1.0:
            subgraph_copy.setAttrib(TransparencyAttrib.make(1))

        reducer = SceneGraphReducer()
        reducer.applyAttribs(subgraph_copy)
        reducer.flatten(chat_node, -1)

        generated_text = text_node.generate()
        if for_3d:
            v86 = ChatBalloon.find_middle_geom(chat_node)
            if not v86:
                v86 = ChatBalloon.find_geom_node(chat_node)

            v86.setEffect(DecalEffect.make())

        else:
            v86 = chat_node
            if has_draw_order:
                bin = config.GetString('nametag-fixed-bin', 'fixed')
                generated_text.setAttrib(CullBinAttrib.make(bin, draw_order + 1))

        np = NodePath.anyPath(v86)
        v144 = np.attachNewNode(generated_text)
        v144.setPos((v137, v138, v139))
        v144.setColor(text_color)
        v144.setY(-0.01)  # Panda3D 1.10 hack to prevent z-fighting.
        if text_color[3] != 1.0:
            v144.setTransparency(1)

        if page_button:
            v116 = ModelNode('button')
            new_button[0] = np.attachNewNode(v116)
            button_copy = page_button.copyTo(new_button[0])
            if reversed:
                button_copy.setPos(self.m_hscale * 1.7, 0, 1.8)

            else:
                button_copy.setPos(self.m_hscale * 9.0, 0, 1.8)

            button_copy.setScale(8.0, 8.0, 8.0)
            button_copy.setY(-0.01)  # Panda3D 1.10 hack to prevent z-fighting.

        reducer = SceneGraphReducer()
        reducer.applyAttribs(generated_text)
        reducer.flatten(chat_node, 1)

        return chat_node
