from pandac.PandaModules import *

class ChatBalloon:
    TEXT_SHIFT = (0.1, -0.05, 1.1)
    TEXT_SHIFT_REVERSED = -0.05
    TEXT_SHIFT_PROP = 0.08
    NATIVE_WIDTH = 10.0
    MIN_WIDTH = 2.5
    MIN_HEIGHT = 1
    BUBBLE_PADDING = 0.3
    BUBBLE_PADDING_PROP = 0.05
    BUTTON_SCALE = 6
    BUTTON_SHIFT = (-0.2, 0, 0.6)
    FRAME_SHIFT = (0.2, 1.4)

    def __init__(self, model):
        self.model = model

    def generate(self, text, font, textColor=(0,0,0,1), balloonColor=(1,1,1,1),
                 wordWrap = 10.0, button=None, reversed=False):
        root = NodePath('balloon')

        # Add balloon geometry:
        balloon = self.model.copyTo(root)
        top = balloon.find('**/top')
        middle = balloon.find('**/middle')
        bottom = balloon.find('**/bottom')

        balloon.setColor(balloonColor)
        if balloonColor[3] < 1.0:
            balloon.setTransparency(1)

        # Render the text into a TextNode, using the font:
        t = root.attachNewNode(TextNode('text'))
        t.node().setFont(font)
        t.node().setWordwrap(wordWrap)
        t.node().setText(text)
        t.node().setTextColor(textColor)

        width, height = t.node().getWidth(), t.node().getHeight()

        # Turn off depth write for the text: The place in the depth buffer is
        # held by the chat bubble anyway, and the text renders after the bubble
        # so there's no risk of the bubble overwriting the text's pixels.
        t.setAttrib(DepthWriteAttrib.make(0))
        t.setPos(self.TEXT_SHIFT)
        t.setX(t, self.TEXT_SHIFT_PROP*width)
        t.setZ(t, height)

        if reversed:
            # The nametag code wants the text on the left side of the axis,
            # rather than on the right side. Therefore, we move the text to the
            # opposite side:
            t.setX(self.TEXT_SHIFT_REVERSED - self.TEXT_SHIFT_PROP*width - width)

        # Give the chat bubble a button, if one is requested:
        if button:
            np = button.copyTo(root)
            np.setPos(t, width, 0, -height)
            np.setPos(np, self.BUTTON_SHIFT)
            np.setScale(self.BUTTON_SCALE)

        # Set a minimum width and height for short or empty messages
        if width < self.MIN_WIDTH:
            width = self.MIN_WIDTH
            if reversed:
                t.setX(t, -width/2.0)
            else:
                t.setX(t, width/2.0)
            t.node().setAlign(TextNode.ACenter)

        if height < self.MIN_HEIGHT:
            height = self.MIN_HEIGHT
            t.setX(t, height/2.0)
            t.node().setAlign(TextNode.ACenter)

        # Set the balloon's size:
        width *= 1+self.BUBBLE_PADDING_PROP
        width += self.BUBBLE_PADDING
        balloon.setSx(width/self.NATIVE_WIDTH)
        if reversed:
            balloon.setSx(-balloon.getSx())
            balloon.setTwoSided(True) # Render the backface of the balloon
        middle.setSz(height)
        top.setZ(top, height-1)

        # Calculate the frame occupied by the balloon:
        left, bottom = self.FRAME_SHIFT
        if reversed:
            left = -left - width
        frame = (left, left+width, bottom, bottom+height+1)

        return root, frame
