from direct.fsm.FSM import FSM
from direct.showbase.DirectObject import DirectObject
from panda3d.core import PandaNode, PGButton, NodePath, MouseWatcherRegion


class Clickable(FSM, PandaNode, DirectObject):
    def __init__(self, name):
        FSM.__init__(self, name)
        PandaNode.__init__(self, name)
        DirectObject.__init__(self)

        self.active = True

        self.lastClickState = PGButton.SReady
        self.clickState = PGButton.SReady

        self.__hovering = False

        self.clickEvent = ''
        self.clickExtraArgs = []

        self.contents = NodePath.anyPath(self).attachNewNode('contents')

        # Create a MouseWatcherRegion:
        self.regionName = self.getUniqueName() + '-region'
        self.region = MouseWatcherRegion(self.regionName, 0, 0, 0, 0)
        base.mouseWatcherNode.addRegion(self.region)

        # Accept the mouse events:
        enterPattern = base.mouseWatcherNode.getEnterPattern()
        leavePattern = base.mouseWatcherNode.getLeavePattern()
        buttonDownPattern = base.mouseWatcherNode.getButtonDownPattern()
        buttonUpPattern = base.mouseWatcherNode.getButtonUpPattern()
        self.accept(enterPattern.replace('%r', self.regionName), self.__handleMouseEnter)
        self.accept(leavePattern.replace('%r', self.regionName), self.__handleMouseLeave)
        self.accept(buttonDownPattern.replace('%r', self.regionName), self.__handleMouseDown)
        self.accept(buttonUpPattern.replace('%r', self.regionName), self.__handleMouseUp)

    def destroy(self):
        self.ignoreAll()

        if self.region is not None:
            base.mouseWatcherNode.removeRegion(self.region)
            self.region = None

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

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

    def setActive(self, active):
        self.active = active

    def getActive(self):
        return self.active

    def isClickable(self):
        return self.active

    def isHovering(self):
        return self.__hovering

    def setClickState(self, clickState):
        self.lastClickState = self.clickState
        self.clickState = clickState

        if self.clickState == PGButton.SReady:
            self.request('Ready')
        elif self.clickState == PGButton.SDepressed:
            self.request('Depressed')
        elif self.clickState == PGButton.SRollover:
            self.request('Rollover')
        elif self.clickState == PGButton.SInactive:
            self.request('Inactive')

    def getClickState(self):
        return self.clickState

    def enterReady(self):
        pass

    def enterDepressed(self):
        pass

    def exitDepressed(self):
        if self.isClickable():
            messenger.send(self.clickEvent, self.clickExtraArgs)

    def enterRollover(self):
        pass

    def enterInactive(self):
        pass

    def setClickEvent(self, event, extraArgs=[]):
        self.clickEvent = event
        self.clickExtraArgs = extraArgs

    def setClickRegionFrame(self, left, right, bottom, top):
        self.region.setFrame(left, right, bottom, top)

    def __handleMouseEnter(self, region, button):
        self.__hovering = True
        self.setClickState(PGButton.SRollover)

    def __handleMouseLeave(self, region, button):
        self.__hovering = False
        if self.clickState != PGButton.SDepressed:
            self.setClickState(PGButton.SReady)

    def __handleMouseDown(self, region, button):
        self.setClickState(PGButton.SDepressed)

    def __handleMouseUp(self, region, button):
        if self.__hovering:
            self.setClickState(PGButton.SRollover)
        else:
            self.setClickState(PGButton.SReady)