from panda3d.core import *
from direct.gui.DirectGui import *
from direct.task import Task
from SCConstants import *
from SCObject import SCObject
from direct.showbase.PythonUtil import boolEqual
from otp.otpbase import OTPGlobals

class SCElement(SCObject, NodePath):
    font = OTPGlobals.getInterfaceFont()
    SerialNum = 0

    def __init__(self, parentMenu = None):
        SCObject.__init__(self)
        self.SerialNum = SCElement.SerialNum
        SCElement.SerialNum += 1
        node = hidden.attachNewNode('SCElement%s' % self.SerialNum)
        NodePath.__init__(self, node)
        self.FinalizeTaskName = 'SCElement%s_Finalize' % self.SerialNum
        self.parentMenu = parentMenu
        self.__active = 0
        self.__viewable = 1
        self.lastWidth = 0
        self.lastHeight = 0
        self.setDimensions(0, 0)
        self.padX = 0.25
        self.padZ = 0.1

    def destroy(self):
        if self.isActive():
            self.exitActive()
        SCObject.destroy(self)
        if hasattr(self, 'button'):
            self.button.destroy()
            del self.button
        self.parentMenu = None
        self.detachNode()
        return

    def setParentMenu(self, parentMenu):
        self.parentMenu = parentMenu

    def getParentMenu(self):
        return self.parentMenu

    def getDisplayText(self):
        self.notify.error('getDisplayText is pure virtual, derived class must override')

    def onMouseEnter(self, event):
        if self.parentMenu is not None:
            self.parentMenu.memberGainedInputFocus(self)
        return

    def onMouseLeave(self, event):
        if self.parentMenu is not None:
            self.parentMenu.memberLostInputFocus(self)
        return

    def onMouseClick(self, event):
        pass

    def enterActive(self):
        self.__active = 1

    def exitActive(self):
        self.__active = 0

    def isActive(self):
        return self.__active

    def hasStickyFocus(self):
        return 0

    def setViewable(self, viewable):
        if not boolEqual(self.__viewable, viewable):
            self.__viewable = viewable
            if self.parentMenu is not None:
                self.parentMenu.memberViewabilityChanged(self)
        return

    def isViewable(self):
        return self.__viewable

    def getMinDimensions(self):
        text = TextNode('SCTemp')
        text.setFont(SCElement.font)
        dText = self.getDisplayText()
        text.setText(dText)
        bounds = text.getCardActual()
        width = abs(bounds[1] - bounds[0]) + self.padX
        height = abs(bounds[3] - bounds[2]) + 2.0 * self.padZ
        return (width, height)

    def setDimensions(self, width, height):
        self.width = float(width)
        self.height = float(height)
        if (self.lastWidth, self.lastHeight) != (self.width, self.height):
            self.invalidate()

    def invalidate(self):
        SCObject.invalidate(self)
        parentMenu = self.getParentMenu()
        if parentMenu is not None:
            if not parentMenu.isFinalizing():
                parentMenu.invalidate()
        return

    def enterVisible(self):
        SCObject.enterVisible(self)
        self.privScheduleFinalize()

    def exitVisible(self):
        SCObject.exitVisible(self)
        self.privCancelFinalize()

    def privScheduleFinalize(self):

        def finalizeElement(task, self = self):
            if self.parentMenu is not None:
                if self.parentMenu.isDirty():
                    return Task.done
            self.finalize()
            return Task.done

        taskMgr.remove(self.FinalizeTaskName)
        taskMgr.add(finalizeElement, self.FinalizeTaskName, priority=SCElementFinalizePriority)

    def privCancelFinalize(self):
        taskMgr.remove(self.FinalizeTaskName)

    def finalize(self, dbArgs = {}):
        if not self.isDirty():
            return
        SCObject.finalize(self)
        if hasattr(self, 'button'):
            self.button.destroy()
            del self.button
        halfHeight = self.height / 2.0
        textX = 0
        if 'text_align' in dbArgs:
            if dbArgs['text_align'] == TextNode.ACenter:
                textX = self.width / 2.0
        args = {'text': self.getDisplayText(),
         'frameColor': (0, 0, 0, 0),
         'rolloverColor': self.getColorScheme().getRolloverColor() + (1,),
         'pressedColor': self.getColorScheme().getPressedColor() + (1,),
         'text_font': OTPGlobals.getInterfaceFont(),
         'text_align': TextNode.ALeft,
         'text_fg': self.getColorScheme().getTextColor() + (1,),
         'text_pos': (textX, -.25 - halfHeight, 0),
         'relief': DGG.FLAT,
         'pressEffect': 0}
        args.update(dbArgs)
        rolloverColor = args['rolloverColor']
        pressedColor = args['pressedColor']
        del args['rolloverColor']
        del args['pressedColor']
        btn = DirectButton(parent=self, frameSize=(0,
         self.width,
         -self.height,
         0), **args)
        btn.frameStyle[DGG.BUTTON_ROLLOVER_STATE].setColor(*rolloverColor)
        btn.frameStyle[DGG.BUTTON_DEPRESSED_STATE].setColor(*pressedColor)
        btn.updateFrameStyle()
        btn.bind(DGG.ENTER, self.onMouseEnter)
        btn.bind(DGG.EXIT, self.onMouseLeave)
        btn.bind(DGG.B1PRESS, self.onMouseClick)
        self.button = btn
        self.lastWidth = self.width
        self.lastHeight = self.height
        self.validate()

    def __str__(self):
        return '%s: %s' % (self.__class__.__name__, self.getDisplayText())
