from direct.task.Task import Task
import math
from panda3d.core import PGButton, VBase4, DepthWriteAttrib, Point3

from toontown.chat.ChatBalloon import ChatBalloon
from toontown.margins import MarginGlobals
from toontown.margins.MarginVisible import MarginVisible
from toontown.nametag import NametagGlobals
from toontown.nametag.Nametag import Nametag
from toontown.toontowngui.Clickable2d import Clickable2d


class Nametag2d(Nametag, Clickable2d, MarginVisible):
    CONTENTS_SCALE = 0.25

    CHAT_TEXT_MAX_ROWS = 6
    CHAT_TEXT_WORD_WRAP = 8

    CHAT_BALLOON_ALPHA = 0.4

    ARROW_OFFSET = -1.0
    ARROW_SCALE = 1.5

    def __init__(self):
        Nametag.__init__(self)
        Clickable2d.__init__(self, 'Nametag2d')
        MarginVisible.__init__(self)

        self.actualChatText = ''

        self.arrow = None
        self.textNodePath = None

        self.contents.setScale(self.CONTENTS_SCALE)
        self.hideThought()

        self.accept('MarginVisible-update', self.update)

    def destroy(self):
        self.ignoreAll()

        Nametag.destroy(self)

        if self.textNodePath is not None:
            self.textNodePath.removeNode()
            self.textNodePath = None

        if self.arrow is not None:
            self.arrow.removeNode()
            self.arrow = None

        Clickable2d.destroy(self)

    def getUniqueName(self):
        return 'Nametag2d-' + str(id(self))

    def getChatBalloonModel(self):
        return NametagGlobals.chatBalloon2dModel

    def getChatBalloonWidth(self):
        return NametagGlobals.chatBalloon2dWidth

    def getChatBalloonHeight(self):
        return NametagGlobals.chatBalloon2dHeight

    def setChatText(self, chatText):
        self.actualChatText = chatText

        Nametag.setChatText(self, chatText)

    def updateClickRegion(self):
        if self.chatBalloon is not None:
            right = self.chatBalloon.width / 2.0
            left = -right
            top = self.chatBalloon.height / 2.0
            bottom = -top

            self.setClickRegionFrame(left, right, bottom, top)
            self.region.setActive(True)
        elif self.panel is not None:
            centerX = (self.textNode.getLeft()+self.textNode.getRight()) / 2.0
            centerY = (self.textNode.getBottom()+self.textNode.getTop()) / 2.0

            left = centerX - (self.panelWidth/2.0)
            right = centerX + (self.panelWidth/2.0)
            bottom = centerY - (self.panelHeight/2.0)
            top = centerY + (self.panelHeight/2.0)

            self.setClickRegionFrame(left, right, bottom, top)
            self.region.setActive(True)
        else:
            if self.region is not None:
                self.region.setActive(False)

    def isClickable(self):
        if self.getChatText() and self.hasChatButton():
            return True
        return NametagGlobals.wantActiveNametags and Clickable2d.isClickable(self)

    def setClickState(self, clickState):
        if self.isClickable():
            self.applyClickState(clickState)
        else:
            self.applyClickState(PGButton.SInactive)

        Clickable2d.setClickState(self, clickState)

    def enterDepressed(self):
        if self.isClickable():
            base.playSfx(NametagGlobals.clickSound)

    def enterRollover(self):
        if self.isClickable() and (self.lastClickState != PGButton.SDepressed):
            base.playSfx(NametagGlobals.rolloverSound)

    def update(self):
        self.contents.node().removeAllChildren()

        Nametag.update(self)

        if self.cell is not None:
            # We're in the margin display. Reposition our content, and update
            # the click region:
            self.reposition()
            self.updateClickRegion()
        else:
            # We aren't in the margin display. Disable the click region if one
            # is present:
            if self.region is not None:
                self.region.setActive(False)

    def tick(self, task):
        if (self.avatar is None) or self.avatar.isEmpty():
            return Task.cont

        if (self.cell is None) or (self.arrow is None):
            return Task.cont

        location = self.avatar.getPos(NametagGlobals.me)
        rotation = NametagGlobals.me.getQuat(base.cam)
        camSpacePos = rotation.xform(location)

        arrowRadians = math.atan2(camSpacePos[0], camSpacePos[1])
        arrowDegrees = (arrowRadians/math.pi) * 180
        self.arrow.setR(arrowDegrees - 90)

        return Task.cont

    def drawChatBalloon(self, model, modelWidth, modelHeight):
        if self.chatFont is None:
            # We can't draw this without a font.
            return

        # Prefix the nametag text:
        self.chatTextNode.setText(self.getText() + ': ' + self.actualChatText)

        # Set our priority in the margin system:
        self.setPriority(MarginGlobals.MP_normal)

        if self.textNodePath is not None:
            self.textNodePath.removeNode()
            self.textNodePath = None

        if self.arrow is not None:
            self.arrow.removeNode()
            self.arrow = None

        if self.isClickable():
            foreground, background = self.chatColor[self.clickState]
        else:
            foreground, background = self.chatColor[PGButton.SInactive]
        if self.chatType == NametagGlobals.SPEEDCHAT:
            background = self.speedChatColor
        if background[3] > self.CHAT_BALLOON_ALPHA:
            background = VBase4(
                background[0], background[1], background[2],
                self.CHAT_BALLOON_ALPHA)
        self.chatBalloon = ChatBalloon(
            model, modelWidth, modelHeight, self.chatTextNode,
            foreground=foreground, background=background,
            reversed=self.chatReversed,
            button=self.chatButton[self.clickState])
        self.chatBalloon.reparentTo(self.contents)

        # Calculate the center of the TextNode:
        left, right, bottom, top = self.chatTextNode.getFrameActual()
        center = self.contents.getRelativePoint(
            self.chatBalloon.textNodePath,
            ((left+right) / 2.0, 0, (bottom+top) / 2.0))

        # Translate the chat balloon along the inverse:
        self.chatBalloon.setPos(self.chatBalloon, -center)

    def drawNametag(self):
        # Set our priority in the margin system:
        self.setPriority(MarginGlobals.MP_low)

        if self.textNodePath is not None:
            self.textNodePath.removeNode()
            self.textNodePath = None

        if self.arrow is not None:
            self.arrow.removeNode()
            self.arrow = None

        if self.font is None:
            # We can't draw this without a font.
            return

        # Attach the icon:
        if self.icon is not None:
            self.contents.attachNewNode(self.icon)

        if self.isClickable():
            foreground, background = self.nametagColor[self.clickState]
        else:
            foreground, background = self.nametagColor[PGButton.SInactive]

        # Set the color of the TextNode:
        self.textNode.setTextColor(foreground)

        # Attach the TextNode:
        self.textNodePath = self.contents.attachNewNode(self.textNode, 1)
        self.textNodePath.setTransparency(foreground[3] < 1)
        self.textNodePath.setAttrib(DepthWriteAttrib.make(0))
        self.textNodePath.setY(self.TEXT_Y_OFFSET)

        # Attach a panel behind the TextNode:
        self.panel = NametagGlobals.cardModel.copyTo(self.contents, 0)
        self.panel.setColor(background)
        self.panel.setTransparency(background[3] < 1)

        # Reposition the panel:
        x = (self.textNode.getLeft()+self.textNode.getRight()) / 2.0
        z = (self.textNode.getBottom()+self.textNode.getTop()) / 2.0
        self.panel.setPos(x, 0, z)

        # Resize the panel:
        self.panelWidth = self.textNode.getWidth() + self.PANEL_X_PADDING
        self.panelHeight = self.textNode.getHeight() + self.PANEL_Z_PADDING
        self.panel.setScale(self.panelWidth, 1, self.panelHeight)
        
        # Add an arrow:
        self.arrow = NametagGlobals.arrowModel.copyTo(self.contents)
        self.arrow.setZ(self.ARROW_OFFSET + self.textNode.getBottom())
        self.arrow.setScale(self.ARROW_SCALE)
        self.arrow.setColor(self.nametagColor[4] if len(self.nametagColor) >= 5 else self.nametagColor[0][0])

    def marginVisibilityChanged(self):
        if self.cell is not None:
            # We're in the margin display. Reposition our content, and update
            # the click region:
            self.reposition()
            self.updateClickRegion()
        else:
            # We aren't in the margin display. Disable the click region if one
            # is present:
            if self.region is not None:
                self.region.setActive(False)

    def reposition(self):
        if self.contents is None:
            return

        origin = Point3()

        self.contents.setPos(origin)

        if self.chatBalloon is not None:
            self.chatBalloon.removeNode()
            self.chatBalloon = None

            self.contents.node().removeAllChildren()

            if (self.cell in base.leftCells) or (self.cell in base.rightCells):
                text = self.getChatText().replace('\x01WLDisplay\x01', '').replace('\x02', '')
                textWidth = self.chatTextNode.calcWidth(text)
                if (textWidth / self.CHAT_TEXT_WORD_WRAP) > self.CHAT_TEXT_MAX_ROWS:
                    self.chatTextNode.setWordwrap(textWidth / (self.CHAT_TEXT_MAX_ROWS-0.5))
            else:
                self.chatTextNode.setWordwrap(self.CHAT_TEXT_WORD_WRAP)

            model = self.getChatBalloonModel()
            modelWidth = self.getChatBalloonWidth()
            modelHeight = self.getChatBalloonHeight()
            self.drawChatBalloon(model, modelWidth, modelHeight)

            nodePath = self.chatBalloon.textNodePath

            left, right, bottom, top = self.chatTextNode.getFrameActual()
            left -= self.chatBalloon.BALLOON_X_PADDING
            right += self.chatBalloon.BALLOON_X_PADDING
            bottom -= self.chatBalloon.BALLOON_Z_PADDING
            top += self.chatBalloon.BALLOON_Z_PADDING
        elif self.panel is not None:
            nodePath = self.textNodePath

            left, right, bottom, top = self.textNode.getFrameActual()
            left -= self.PANEL_X_PADDING
            right += self.PANEL_X_PADDING
            bottom -= self.PANEL_Z_PADDING
            top += self.PANEL_Z_PADDING

            # Compensate for the arrow:
            bottom -= self.ARROW_SCALE
        else:
            return

        if self.cell in base.bottomCells:
            # Move the origin to the bottom center of the node path:
            origin = self.contents.getRelativePoint(
                nodePath, ((left+right) / 2.0, 0, bottom))
        elif self.cell in base.leftCells:
            # Move the origin to the left center of the node path:
            origin = self.contents.getRelativePoint(
                nodePath, (left, 0, (bottom+top) / 2.0))
        elif self.cell in base.rightCells:
            # Move the origin to the right center of the node path:
            origin = self.contents.getRelativePoint(
                nodePath, (right, 0, (bottom+top) / 2.0))

        self.contents.setPos(self.contents, -origin)