from direct.directnotify import DirectNotifyGlobal
from direct.distributed import DistributedObject
from direct.gui.DirectGui import *
from direct.interval.IntervalGlobal import *
from pandac.PandaModules import *

import BoardingGroupShow
from toontown.building import BoardingPartyBase
from toontown.chat.ChatGlobals import *
from toontown.chat.WhisperPopup import *
from toontown.hood import ZoneUtil
from toontown.toon import BoardingGroupInviterPanels
from toontown.toon import GroupInvitee
from toontown.toon import GroupPanel
from toontown.toonbase import TTLocalizer
from toontown.toonbase import ToontownGlobals
from toontown.toontowngui import TTDialog


class DistributedBoardingParty(DistributedObject.DistributedObject, BoardingPartyBase.BoardingPartyBase):
    notify = DirectNotifyGlobal.directNotify.newCategory('DistributedBoardingParty')
    InvitationFailedTimeout = 60.0

    def __init__(self, cr):
        DistributedObject.DistributedObject.__init__(self, cr)
        BoardingPartyBase.BoardingPartyBase.__init__(self)
        self.groupInviteePanel = None
        self.groupPanel = None
        self.inviterPanels = BoardingGroupInviterPanels.BoardingGroupInviterPanels()
        self.lastInvitationFailedMessage = {}
        self.goToPreShowTrack = None
        self.goToShowTrack = None
        return

    def generate(self):
        self.load()
        DistributedObject.DistributedObject.generate(self)
        localAvatar.boardingParty = self

    def announceGenerate(self):
        canonicalZoneId = ZoneUtil.getCanonicalZoneId(self.zoneId)
        self.notify.debug('canonicalZoneId = %s' % canonicalZoneId)
        localAvatar.chatMgr.chatInputSpeedChat.addBoardingGroupMenu(canonicalZoneId)

    def delete(self):
        DistributedObject.DistributedObject.delete(self)

    def disable(self):
        self.finishGoToPreShowTrack()
        self.finishGoToShowTrack()
        self.forceCleanupInviteePanel()
        self.forceCleanupInviterPanels()
        self.inviterPanels = None
        if self.groupPanel:
            self.groupPanel.cleanup()
        self.groupPanel = None
        DistributedObject.DistributedObject.disable(self)
        BoardingPartyBase.BoardingPartyBase.cleanup(self)
        localAvatar.boardingParty = None
        localAvatar.chatMgr.chatInputSpeedChat.removeBoardingGroupMenu()
        self.lastInvitationFailedMessage = {}
        return

    def getElevatorIdList(self):
        return self.elevatorIdList

    def setElevatorIdList(self, elevatorIdList):
        self.notify.debug('setElevatorIdList')
        self.elevatorIdList = elevatorIdList

    def load(self):
        pass

    # this is a pretty brute force group check that will see if a toon
    # (in the same zone) is already in a group.   This might introduce
    # lag in a very crowded district with hundreds of active groups
    # (if we should be so lucky)
    def isInGroup(self, avId):
        if avId in self.groupListDict:
            return True
        for leader in self.groupListDict:
            group = self.groupListDict.get(leader)
            for member in group[0]:
                if member == avId:
                    return True
        return False

    def countInGroup(self, avId):
        if avId in self.groupListDict:
            group = self.groupListDict.get(avId)
            return len(group[0])
        for leader in self.groupListDict:
            group = self.groupListDict.get(leader)
            for member in group[0]:
                if member == avId:
                    return len(group[0])
        return 0

    def postGroupInfo(self, leaderId, memberList, inviteeList, kickedList):
        self.notify.debug('postgroupInfo')
        isMyGroup = 0
        removedMemberIdList = []
        if leaderId in self.groupListDict:
            oldGroupEntry = self.groupListDict[leaderId]
        else:
            oldGroupEntry = [[], [], []]
        oldMemberList = oldGroupEntry[0]
        newGroupEntry = [memberList, inviteeList, kickedList]
        self.groupListDict[leaderId] = newGroupEntry
        if not len(oldMemberList) == len(memberList):
            for oldMember in oldMemberList:
                if oldMember not in memberList:
                    if oldMember in self.avIdDict:
                        if self.avIdDict[oldMember] == leaderId:
                            self.avIdDict.pop(oldMember)
                            removedMemberIdList.append(oldMember)

        self.avIdDict[leaderId] = leaderId
        if leaderId == localAvatar.doId:
            isMyGroup = 1
        for memberId in memberList:
            self.avIdDict[memberId] = leaderId
            if memberId == localAvatar.doId:
                isMyGroup = 1

        if newGroupEntry[0] == [0] or not newGroupEntry[0]:
            dgroup = self.groupListDict.pop(leaderId)
            for memberId in dgroup[0]:
                if memberId in self.avIdDict:
                    self.avIdDict.pop(memberId)

        if isMyGroup:
            self.notify.debug('new info posted on my group')
            # update the leaderId in case it has changed (group merge)
            if self.groupPanel and self.groupPanel.leaderId == localAvatar.doId and leaderId != localAvatar.doId:
                self.groupPanel.cleanup()
                self.groupPanel = None
            if not self.groupPanel:
                self.groupPanel = GroupPanel.GroupPanel(self)
            messenger.send('updateGroupStatus')
            for removedMemberId in removedMemberIdList:
                removedMember = base.cr.doId2do.get(removedMemberId)
                if not removedMember:
                    removedMember = base.cr.identifyFriend(removedMemberId)
                if removedMember:
                    removedMemberName = removedMember.name
                    messageText = TTLocalizer.BoardingMessageLeftGroup % removedMemberName
                    localAvatar.setSystemMessage(0, messageText, WTToontownBoardingGroup)

        elif localAvatar.doId in oldMemberList and localAvatar.doId not in memberList:
            messenger.send('updateGroupStatus')
            if self.groupPanel:
                self.groupPanel.cleanup()
            self.groupPanel = None
        else:
            self.notify.debug('new info posted on some other group')
        return

    def postInvite(self, leaderId, inviterId, merger):
        self.notify.debug('post Invite')
        if not base.localAvatar.isIgnored(inviterId):
            inviter = base.cr.doId2do.get(inviterId)
            if inviter:
                if self.inviterPanels.isInvitingPanelUp() or self.inviterPanels.isInvitationRejectedPanelUp():
                    self.inviterPanels.forceCleanup()
                self.groupInviteePanel = GroupInvitee.GroupInvitee()
                self.groupInviteePanel.make(self, inviter, leaderId, merger)
                if base.config.GetBool('reject-boarding-group-invites', 0):
                    self.groupInviteePanel.forceCleanup()
                    self.groupInviteePanel = None
        return

    def postKick(self, leaderId):
        self.notify.debug('%s was kicked out of the Boarding Group by %s' % (localAvatar.doId, leaderId))
        localAvatar.setSystemMessage(0, TTLocalizer.BoardingMessageKickedOut, WTToontownBoardingGroup)

    def postSizeReject(self, leaderId, inviterId, inviteeId):
        self.notify.debug('%s was not invited because the group is full' % inviteeId)

    def postKickReject(self, leaderId, inviterId, inviteeId):
        self.notify.debug('%s was not invited because %s has kicked them from the group' % (inviteeId, leaderId))

    def postInviteDelcined(self, inviteeId):
        self.notify.debug("%s delinced %s's Boarding Group invitation." % (inviteeId, localAvatar.doId))
        invitee = base.cr.doId2do.get(inviteeId)
        if invitee:
            self.inviterPanels.createInvitationRejectedPanel(self, inviteeId)

    def postInviteAccepted(self, inviteeId):
        self.notify.debug("%s accepted %s's Boarding Group invitation." % (inviteeId, localAvatar.doId))
        if self.inviterPanels.isInvitingPanelIdCorrect(inviteeId):
            self.inviterPanels.destroyInvitingPanel()

    def postInviteCanceled(self):
        self.notify.debug('The invitation to the Boarding Group was cancelled')
        if self.isInviteePanelUp():
            self.groupInviteePanel.cleanup()
            self.groupInviteePanel = None
        return

    def postInviteNotQualify(self, avId, reason, elevatorId):
        messenger.send('updateGroupStatus')
        rejectText = ''
        minLaff = TTLocalizer.BoardingMore
        if elevatorId:
            elevator = base.cr.doId2do.get(elevatorId)
            if elevator:
                minLaff = elevator.minLaff
        if avId == localAvatar.doId:
            if reason == BoardingPartyBase.BOARDCODE_MINLAFF:
                rejectText = TTLocalizer.BoardingInviteMinLaffInviter % minLaff
            if reason == BoardingPartyBase.BOARDCODE_PROMOTION:
                rejectText = TTLocalizer.BoardingInvitePromotionInviter
        else:
            avatar = base.cr.doId2do.get(avId)
            if avatar:
                avatarNameText = avatar.name
            else:
                avatarNameText = ''
            if reason == BoardingPartyBase.BOARDCODE_MINLAFF:
                rejectText = TTLocalizer.BoardingInviteMinLaffInvitee % (avatarNameText, minLaff)
            if reason == BoardingPartyBase.BOARDCODE_PROMOTION:
                rejectText = TTLocalizer.BoardingInvitePromotionInvitee % avatarNameText
            if reason == BoardingPartyBase.BOARDCODE_BATTLE:
                rejectText = TTLocalizer.TeleportPanelNotAvailable % avatarNameText
            if reason == BoardingPartyBase.BOARDCODE_DIFF_GROUP:
                rejectText = TTLocalizer.BoardingInviteeInDiffGroup % avatarNameText
            if reason == BoardingPartyBase.BOARDCODE_PENDING_INVITE:
                rejectText = TTLocalizer.BoardingInviteePendingIvite % avatarNameText
            if reason == BoardingPartyBase.BOARDCODE_IN_ELEVATOR:
                rejectText = TTLocalizer.BoardingInviteeInElevator % avatarNameText
            if reason == BoardingPartyBase.BOARDCODE_GROUPS_TO_LARGE: # JBS
                rejectText = TTLocalizer.BoardingGroupsToLarge % avatarNameText
        if self.inviterPanels.isInvitingPanelIdCorrect(avId) or avId == localAvatar.doId:
            self.inviterPanels.destroyInvitingPanel()
        self.showMe(rejectText)

    def postAlreadyInGroup(self):
        self.showMe(TTLocalizer.BoardingAlreadyInGroup)

    def postGroupAlreadyFull(self):
        self.showMe(TTLocalizer.BoardingGroupAlreadyFull)

    def postSomethingMissing(self):
        self.showMe(TTLocalizer.BoardcodeMissing)

    def postRejectBoard(self, elevatorId, reason, avatarsFailingRequirements, avatarsInBattle):
        self.showRejectMessage(elevatorId, reason, avatarsFailingRequirements, avatarsInBattle)
        self.enableGoButton()

    def postRejectGoto(self, elevatorId, reason, avatarsFailingRequirements, avatarsInBattle):
        self.showRejectMessage(elevatorId, reason, avatarsFailingRequirements, avatarsInBattle)

    def postMessageInvited(self, inviteeId, inviterId):
        inviterName = ''
        inviteeName = ''
        inviter = base.cr.doId2do.get(inviterId)
        if inviter:
            inviterName = inviter.name
        invitee = base.cr.doId2do.get(inviteeId)
        if invitee:
            inviteeName = invitee.name
        messageText = TTLocalizer.BoardingMessageInvited % (inviterName, inviteeName)
        localAvatar.setSystemMessage(0, messageText, WTToontownBoardingGroup)

    def postMessageInvitationFailed(self, inviterId):
        inviterName = ''
        inviter = base.cr.doId2do.get(inviterId)
        if inviter:
            inviterName = inviter.name
        if self.invitationFailedMessageOk(inviterId):
            messageText = TTLocalizer.BoardingMessageInvitationFailed % inviterName
            localAvatar.setSystemMessage(0, messageText, WTToontownBoardingGroup)

    def postMessageAcceptanceFailed(self, inviteeId, reason):
        inviteeName = ''
        messageText = ''
        invitee = base.cr.doId2do.get(inviteeId)
        if invitee:
            inviteeName = invitee.name
        if reason == BoardingPartyBase.INVITE_ACCEPT_FAIL_GROUP_FULL:
            messageText = TTLocalizer.BoardingMessageGroupFull % inviteeName
        localAvatar.setSystemMessage(0, messageText, WTToontownBoardingGroup)
        if self.inviterPanels.isInvitingPanelIdCorrect(inviteeId):
            self.inviterPanels.destroyInvitingPanel()

    def invitationFailedMessageOk(self, inviterId):
        now = globalClock.getFrameTime()
        lastTime = self.lastInvitationFailedMessage.get(inviterId, None)
        if lastTime:
            elapsedTime = now - lastTime
            if elapsedTime < self.InvitationFailedTimeout:
                return False
        self.lastInvitationFailedMessage[inviterId] = now
        return True

    def showRejectMessage(self, elevatorId, reason, avatarsFailingRequirements, avatarsInBattle):
        leaderId = localAvatar.doId
        rejectText = ''

        def getAvatarText(avIdList):
            avatarText = ''
            nameList = []
            for avId in avIdList:
                avatar = base.cr.doId2do.get(avId)
                if avatar:
                    nameList.append(avatar.name)

            if len(nameList) > 0:
                lastName = nameList.pop()
                avatarText = lastName
                if len(nameList) > 0:
                    secondLastName = nameList.pop()
                    for name in nameList:
                        avatarText = name + ', '

                    avatarText += secondLastName + ' ' + TTLocalizer.And + ' ' + lastName
            return avatarText

        if reason == BoardingPartyBase.BOARDCODE_MINLAFF:
            self.notify.debug("%s 's group cannot board because it does not have enough laff points." % leaderId)
            elevator = base.cr.doId2do.get(elevatorId)
            if elevator:
                minLaffPoints = elevator.minLaff
            else:
                minLaffPoints = TTLocalizer.BoardingMore
            if leaderId in avatarsFailingRequirements:
                rejectText = TTLocalizer.BoardcodeMinLaffLeader % minLaffPoints
            else:
                avatarNameText = getAvatarText(avatarsFailingRequirements)
                if len(avatarsFailingRequirements) == 1:
                    rejectText = TTLocalizer.BoardcodeMinLaffNonLeaderSingular % (avatarNameText, minLaffPoints)
                else:
                    rejectText = TTLocalizer.BoardcodeMinLaffNonLeaderPlural % (avatarNameText, minLaffPoints)
        elif reason == BoardingPartyBase.BOARDCODE_PROMOTION:
            self.notify.debug("%s 's group cannot board because it does not have enough promotion merits." % leaderId)
            if leaderId in avatarsFailingRequirements:
                rejectText = TTLocalizer.BoardcodePromotionLeader
            else:
                avatarNameText = getAvatarText(avatarsFailingRequirements)
                if len(avatarsFailingRequirements) == 1:
                    rejectText = TTLocalizer.BoardcodePromotionNonLeaderSingular % avatarNameText
                else:
                    rejectText = TTLocalizer.BoardcodePromotionNonLeaderPlural % avatarNameText
        elif reason == BoardingPartyBase.BOARDCODE_BATTLE:
            self.notify.debug("%s 's group cannot board because it is in a battle" % leaderId)
            if leaderId in avatarsInBattle:
                rejectText = TTLocalizer.BoardcodeBattleLeader
            else:
                avatarNameText = getAvatarText(avatarsInBattle)
                if len(avatarsInBattle) == 1:
                    rejectText = TTLocalizer.BoardcodeBattleNonLeaderSingular % avatarNameText
                else:
                    rejectText = TTLocalizer.BoardcodeBattleNonLeaderPlural % avatarNameText
        elif reason == BoardingPartyBase.BOARDCODE_SPACE:
            self.notify.debug("%s 's group cannot board there was not enough room" % leaderId)
            rejectText = TTLocalizer.BoardcodeSpace
        elif reason == BoardingPartyBase.BOARDCODE_MISSING:
            self.notify.debug("%s 's group cannot board because something was missing" % leaderId)
            rejectText = TTLocalizer.BoardcodeMissing
        base.localAvatar.elevatorNotifier.showMe(rejectText)

    def postGroupDissolve(self, quitterId, leaderId, memberList, kick):
        self.notify.debug('%s group has dissolved' % leaderId)
        isMyGroup = 0
        if localAvatar.doId == quitterId or localAvatar.doId == leaderId:
            isMyGroup = 1
        if leaderId in self.groupListDict:
            if leaderId == localAvatar.doId:
                isMyGroup = 1
                if leaderId in self.avIdDict:
                    self.avIdDict.pop(leaderId)
            dgroup = self.groupListDict.pop(leaderId)
            for memberId in memberList:
                if memberId == localAvatar.doId:
                    isMyGroup = 1
                if memberId in self.avIdDict:
                    self.avIdDict.pop(memberId)

        if isMyGroup:
            self.notify.debug('new info posted on my group')
            messenger.send('updateGroupStatus')
            groupFormed = False
            if self.groupPanel:
                groupFormed = True
                self.groupPanel.cleanup()
            self.groupPanel = None
            if groupFormed:
                if leaderId == quitterId:
                    if not localAvatar.doId == leaderId:
                        localAvatar.setSystemMessage(0, TTLocalizer.BoardingMessageGroupDissolved, WTToontownBoardingGroup)
                elif not kick:
                    if not localAvatar.doId == quitterId:
                        quitter = base.cr.doId2do.get(quitterId)
                        if quitter:
                            quitterName = quitter.name
                            messageText = TTLocalizer.BoardingMessageLeftGroup % quitterName
                            localAvatar.setSystemMessage(0, messageText, WTToontownBoardingGroup)
                        else:
                            messageText = TTLocalizer.BoardingMessageGroupDisbandedGeneric
                            localAvatar.setSystemMessage(0, messageText, WTToontownBoardingGroup)
        return

    def requestInvite(self, inviteeId):
        self.notify.debug('requestInvite %s' % inviteeId)
        elevator = base.cr.doId2do.get(self.getElevatorIdList()[0])
        if elevator:
            if inviteeId in self.getGroupKickList(localAvatar.doId):
                if not self.isGroupLeader(localAvatar.doId):
                    avatar = base.cr.doId2do.get(inviteeId)
                    if avatar:
                        avatarNameText = avatar.name
                    else:
                        avatarNameText = ''
                    rejectText = TTLocalizer.BoardingInviteeInKickOutList % avatarNameText
                    self.showMe(rejectText)
                    return
            if self.inviterPanels.isInvitingPanelUp():
                self.showMe(TTLocalizer.BoardingPendingInvite, pos=(0, 0, 0))
            elif len(self.getGroupMemberList(localAvatar.doId)) >= self.maxSize:
                self.showMe(TTLocalizer.BoardingInviteGroupFull)
            else:
                invitee = base.cr.doId2do.get(inviteeId)
                if invitee:
                    self.inviterPanels.createInvitingPanel(self, inviteeId)
                    self.sendUpdate('requestInvite', [inviteeId])

    def requestCancelInvite(self, inviteeId):
        self.sendUpdate('requestCancelInvite', [inviteeId])

    def requestAcceptInvite(self, leaderId, inviterId):
        self.notify.debug('requestAcceptInvite %s %s' % (leaderId, inviterId))
        self.sendUpdate('requestAcceptInvite', [leaderId, inviterId])

    def requestRejectInvite(self, leaderId, inviterId):
        self.sendUpdate('requestRejectInvite', [leaderId, inviterId])

    def requestKick(self, kickId):
        self.sendUpdate('requestKick', [kickId])

    def requestLeave(self):
        if self.goToShowTrack and self.goToShowTrack.isPlaying():
            return
        place = base.cr.playGame.getPlace()
        if place:
            if not place.getState() == 'elevator':
                if localAvatar.doId in self.avIdDict:
                    leaderId = self.avIdDict[localAvatar.doId]
                    self.sendUpdate('requestLeave', [leaderId])

    def handleEnterElevator(self, elevator):
        if self.getGroupLeader(localAvatar.doId) == localAvatar.doId:
            if base.localAvatar.hp > 0:
                self.cr.playGame.getPlace().detectedElevatorCollision(elevator)
                self.sendUpdate('requestBoard', [elevator.doId])
                elevatorId = elevator.doId
                if elevatorId in self.elevatorIdList:
                    offset = self.elevatorIdList.index(elevatorId)
                    if self.groupPanel:
                        self.groupPanel.scrollToDestination(offset)
                    self.informDestChange(offset)
                self.disableGoButton()

    def informDestChange(self, offset):
        self.sendUpdate('informDestinationInfo', [offset])

    def postDestinationInfo(self, offset):
        if self.groupPanel:
            self.groupPanel.changeDestination(offset)

    def enableGoButton(self):
        if self.groupPanel:
            self.groupPanel.enableGoButton()
            self.groupPanel.enableDestinationScrolledList()

    def disableGoButton(self):
        if self.groupPanel:
            self.groupPanel.disableGoButton()
            self.groupPanel.disableDestinationScrolledList()

    def isInviteePanelUp(self):
        if self.groupInviteePanel:
            if not self.groupInviteePanel.isEmpty():
                return True
            self.groupInviteePanel = None
        return False

    def requestGoToFirstTime(self, elevatorId):
        self.waitingForFirstResponse = True
        self.firstRequestAccepted = False
        self.sendUpdate('requestGoToFirstTime', [elevatorId])
        self.startGoToPreShow(elevatorId)

    def acceptGoToFirstTime(self, elevatorId):
        self.waitingForFirstResponse = False
        self.firstRequestAccepted = True

    def requestGoToSecondTime(self, elevatorId):
        if not self.waitingForFirstResponse:
            if self.firstRequestAccepted:
                self.firstRequestAccepted = False
                self.disableGoButton()
                self.sendUpdate('requestGoToSecondTime', [elevatorId])
        else:
            self.postRejectGoto(elevatorId, BoardingPartyBase.BOARDCODE_MISSING, [], [])
            self.cancelGoToElvatorDest()

    def acceptGoToSecondTime(self, elevatorId):
        self.startGoToShow(elevatorId)

    def rejectGoToRequest(self, elevatorId, reason, avatarsFailingRequirements, avatarsInBattle):
        self.firstRequestAccepted = False
        self.waitingForFirstResponse = False
        self.cancelGoToElvatorDest()
        self.postRejectGoto(elevatorId, reason, avatarsFailingRequirements, avatarsInBattle)

    def startGoToPreShow(self, elevatorId):
        self.notify.debug('Starting Go Pre Show.')
        place = base.cr.playGame.getPlace()
        if place:
            place.setState('stopped')
        goButtonPreShow = BoardingGroupShow.BoardingGroupShow(localAvatar)
        goButtonPreShowTrack = goButtonPreShow.getGoButtonPreShow()
        if self.groupPanel:
            self.groupPanel.changeGoToCancel()
            self.groupPanel.disableQuitButton()
            self.groupPanel.disableDestinationScrolledList()
        self.finishGoToPreShowTrack()
        self.goToPreShowTrack = Sequence()
        self.goToPreShowTrack.append(goButtonPreShowTrack)
        self.goToPreShowTrack.append(Func(self.requestGoToSecondTime, elevatorId))
        self.goToPreShowTrack.start()

    def finishGoToPreShowTrack(self):
        if self.goToPreShowTrack:
            self.goToPreShowTrack.finish()
            self.goToPreShowTrack = None
        return

    def startGoToShow(self, elevatorId):
        self.notify.debug('Starting Go Show.')
        localAvatar.boardingParty.forceCleanupInviterPanels()
        elevatorName = self.__getDestName(elevatorId)
        if self.groupPanel:
            self.groupPanel.disableQuitButton()
        goButtonShow = BoardingGroupShow.BoardingGroupShow(localAvatar)
        place = base.cr.playGame.getPlace()
        if place:
            place.setState('stopped')
        self.goToShowTrack = goButtonShow.getGoButtonShow(elevatorName)
        self.goToShowTrack.start()

    def finishGoToShowTrack(self):
        if self.goToShowTrack:
            self.goToShowTrack.finish()
            self.goToShowTrack = None
        return

    def cancelGoToElvatorDest(self):
        self.notify.debug('%s cancelled the GoTo Button.' % localAvatar.doId)
        self.firstRequestAccepted = False
        self.waitingForFirstResponse = False
        self.finishGoToPreShowTrack()
        place = base.cr.playGame.getPlace()
        if place:
            place.setState('walk')
        if self.groupPanel:
            self.groupPanel.changeCancelToGo()
            self.groupPanel.enableGoButton()
            self.groupPanel.enableQuitButton()
            self.groupPanel.enableDestinationScrolledList()

    def __getDestName(self, elevatorId):
        elevator = base.cr.doId2do.get(elevatorId)
        destName = ''
        if elevator:
            destName = elevator.getDestName()
        return destName

    def showMe(self, message, pos = None):
        base.localAvatar.elevatorNotifier.showMeWithoutStopping(message, pos)

    def forceCleanupInviteePanel(self):
        if self.isInviteePanelUp():
            self.groupInviteePanel.forceCleanup()
            self.groupInviteePanel = None
        return

    def forceCleanupInviterPanels(self):
        if self.inviterPanels:
            self.inviterPanels.forceCleanup()