from panda3d.core import *
from direct.gui.DirectGui import *
from direct.gui.DirectScrolledList import *
from toontown.toonbase import ToontownGlobals
from toontown.toontowngui import TTDialog
from toontown.friends import FriendHandle
import CatalogItem
import CatalogInvalidItem
import CatalogFurnitureItem
from toontown.toonbase import TTLocalizer
import CatalogItemPanel
import CatalogItemTypes
from direct.actor import Actor
import random
from toontown.toon import DistributedToon
from direct.directnotify import DirectNotifyGlobal
from otp.nametag.ChatBalloon import ChatBalloon
from otp.nametag import NametagGroup, NametagConstants

NUM_CATALOG_ROWS = 3
NUM_CATALOG_COLS = 2
CatalogPanelCenters = [[Point3(-0.95, 0, 0.91), Point3(-0.275, 0, 0.91)], [Point3(-0.95, 0, 0.275), Point3(-0.275, 0, 0.275)], [Point3(-0.95, 0, -0.4), Point3(-0.275, 0, -0.4)]]
CatalogPanelColors = {CatalogItemTypes.FURNITURE_ITEM: Vec4(0.733, 0.78, 0.933, 1.0),
 CatalogItemTypes.CHAT_ITEM: Vec4(0.922, 0.922, 0.753, 1.0),
 CatalogItemTypes.CLOTHING_ITEM: Vec4(0.918, 0.69, 0.69, 1.0),
 CatalogItemTypes.EMOTE_ITEM: Vec4(0.922, 0.922, 0.753, 1.0),
 CatalogItemTypes.WALLPAPER_ITEM: Vec4(0.749, 0.984, 0.608, 1.0),
 CatalogItemTypes.WINDOW_ITEM: Vec4(0.827, 0.91, 0.659, 1.0)}

class CatalogScreen(DirectFrame):
    notify = DirectNotifyGlobal.directNotify.newCategory('CatalogScreen')

    def __init__(self, parent = aspect2d, **kw):
        self.gifting = -1
        guiItems = loader.loadModel('phase_5.5/models/gui/catalog_gui')
        background = guiItems.find('**/catalog_background')
        background.setBin("background", 10)
        guiButton = loader.loadModel('phase_3/models/gui/quit_button')
        guiBack = loader.loadModel('phase_5.5/models/gui/package_delivery_panel')
        optiondefs = (('scale', 0.667, None),
         ('pos', (0, 1, 0.025), None),
         ('phone', None, None),
         ('doneEvent', None, None),
         ('image', background, None),
         ('relief', None, None))
        self.defineoptions(kw, optiondefs)
        DirectFrame.__init__(self, parent)
        self.friend = None
        self.friendAvId = None
        self.friendName = None
        self.friendList = []
        self.friends = []
        self.load(guiItems, guiButton, guiBack)
        self.initialiseoptions(CatalogScreen)
        self.enableBackorderCatalogButton()
        self.setMaxPageIndex(self.numNewPages)
        self.setPageIndex(-1)
        self.showPageItems()
        self.hide()
        self.clarabelleChatNP = None
        self.clarabelleChatBalloon = None
        self.createdGiftGui = None
        self.viewing = None

    def show(self):
        self.accept('CatalogItemPurchaseRequest', self.__handlePurchaseRequest)
        self.accept('CatalogItemGiftPurchaseRequest', self.__handleGiftPurchaseRequest)
        self.accept(localAvatar.uniqueName('moneyChange'), self.__moneyChange)
        self.accept(localAvatar.uniqueName('bankMoneyChange'), self.__bankMoneyChange)
        self.accept(localAvatar.uniqueName('emblemsChange'), self.__emblemChange)
        deliveryText = 'setDeliverySchedule-%s' % base.localAvatar.doId
        self.accept(deliveryText, self.remoteUpdate)
        base.setBackgroundColor(Vec4(0.529, 0.290, 0.286, 1))
        render.hide()
        DirectFrame.show(self)

        def clarabelleGreeting(task):
            self.setClarabelleChat(TTLocalizer.CatalogGreeting, type='greeting')

        def clarabelleHelpText1(task):
            self.setClarabelleChat(TTLocalizer.CatalogHelpText1)

        taskMgr.doMethodLater(1.0, clarabelleGreeting, 'clarabelleGreeting')
        taskMgr.doMethodLater(12.0, clarabelleHelpText1, 'clarabelleHelpText1')

    def hide(self):
        self.ignore('CatalogItemPurchaseRequest')
        self.ignore('CatalogItemGiftPurchaseRequest')
        self.ignore(localAvatar.uniqueName('moneyChange'))
        self.ignore(localAvatar.uniqueName('bankMoneyChange'))
        self.ignore(localAvatar.uniqueName('emblemsChange'))
        deliveryText = 'setDeliverySchedule-%s' % base.localAvatar.doId
        self.ignore(deliveryText)
        base.setBackgroundColor(ToontownGlobals.DefaultBackgroundColor)
        render.show()
        DirectFrame.hide(self)

    def setNumNewPages(self, numNewPages):
        self.numNewPages = numNewPages

    def setNumBackPages(self, numBackPages):
        self.numBackPages = numBackPages

    def setNumSpecialPages(self, numSpecialPages):
        self.numSpecialPages = numSpecialPages

    def setNumEmblemPages(self, numEmblemPages):
        self.numEmblemPages = numEmblemPages

    def setPageIndex(self, index):
        self.pageIndex = index

    def setMaxPageIndex(self, numPages):
        self.maxPageIndex = max(numPages - 1, -1)

    def enableBackorderCatalogButton(self):
        self.backCatalogButton['state'] = DGG.NORMAL
        self.newCatalogButton['state'] = DGG.DISABLED
        self.specialCatalogButton['state'] = DGG.DISABLED
        self.emblemCatalogButton['state'] = DGG.DISABLED

    def enableNewCatalogButton(self):
        self.backCatalogButton['state'] = DGG.DISABLED
        self.newCatalogButton['state'] = DGG.NORMAL
        self.specialCatalogButton['state'] = DGG.DISABLED
        self.emblemCatalogButton['state'] = DGG.DISABLED

    def enableSpecialCatalogButton(self):
        self.backCatalogButton['state'] = DGG.DISABLED
        self.newCatalogButton['state'] = DGG.DISABLED
        self.specialCatalogButton['state'] = DGG.NORMAL
        self.emblemCatalogButton['state'] = DGG.DISABLED

    def enableEmblemCatalogButton(self):
        self.backCatalogButton['state'] = DGG.DISABLED
        self.newCatalogButton['state'] = DGG.DISABLED
        self.specialCatalogButton['state'] = DGG.DISABLED
        self.emblemCatalogButton['state'] = DGG.NORMAL

    def modeBackorderCatalog(self):
        self.backCatalogButton['state'] = DGG.DISABLED
        self.newCatalogButton['state'] = DGG.NORMAL
        self.specialCatalogButton['state'] = DGG.NORMAL
        self.emblemCatalogButton['state'] = DGG.NORMAL

    def modeNewCatalog(self):
        self.backCatalogButton['state'] = DGG.NORMAL
        self.newCatalogButton['state'] = DGG.DISABLED
        self.specialCatalogButton['state'] = DGG.NORMAL
        self.emblemCatalogButton['state'] = DGG.NORMAL

    def modeSpecialCatalog(self):
        self.backCatalogButton['state'] = DGG.NORMAL
        self.newCatalogButton['state'] = DGG.NORMAL
        self.specialCatalogButton['state'] = DGG.DISABLED
        self.emblemCatalogButton['state'] = DGG.NORMAL

    def modeEmblemCatalog(self):
        self.backCatalogButton['state'] = DGG.NORMAL
        self.newCatalogButton['state'] = DGG.NORMAL
        self.specialCatalogButton['state'] = DGG.NORMAL
        self.emblemCatalogButton['state'] = DGG.DISABLED

    def showNewItems(self, index = None):
        if config.GetBool('want-qa-regression', 0):
            self.notify.info('QA-REGRESSION: CATALOG: New item')
        taskMgr.remove('clarabelleHelpText1')
        messenger.send('wakeup')
        self.viewing = 'New'
        self.modeNewCatalog()
        self.setMaxPageIndex(self.numNewPages)
        if self.numNewPages == 0:
            self.setPageIndex(-1)
        elif index is not None:
            self.setPageIndex(index)
        else:
            self.setPageIndex(0)
        self.showPageItems()
        return

    def showBackorderItems(self, index = None):
        if config.GetBool('want-qa-regression', 0):
            self.notify.info('QA-REGRESSION: CATALOG: Backorder item')
        taskMgr.remove('clarabelleHelpText1')
        messenger.send('wakeup')
        self.viewing = 'Backorder'
        self.modeBackorderCatalog()
        self.setMaxPageIndex(self.numBackPages)
        if self.numBackPages == 0:
            self.setPageIndex(-1)
        elif index is not None:
            self.setPageIndex(index)
        else:
            self.setPageIndex(0)
        self.showPageItems()
        return

    def showSpecialItems(self, index = None):
        if config.GetBool('want-qa-regression', 0):
            self.notify.info('QA-REGRESSION: CATALOG: Special item')
        taskMgr.remove('clarabelleHelpText1')
        messenger.send('wakeup')
        self.viewing = 'Special'
        self.modeSpecialCatalog()
        self.setMaxPageIndex(self.numSpecialPages)
        if self.numSpecialPages == 0:
            self.setPageIndex(-1)
        elif index is not None:
            self.setPageIndex(index)
        else:
            self.setPageIndex(0)
        self.showPageItems()
        return

    def showEmblemItems(self, index = None):
        if config.GetBool('want-qa-regression', 0):
            self.notify.info('QA-REGRESSION: CATALOG: Emblem item')
        taskMgr.remove('clarabelleHelpText1')
        messenger.send('wakeup')
        self.viewing = 'Emblem'
        self.modeEmblemCatalog()
        self.setMaxPageIndex(self.numEmblemPages)
        if self.numEmblemPages == 0:
            self.setPageIndex(-1)
        elif index is not None:
            self.setPageIndex(index)
        else:
            self.setPageIndex(0)
        self.showPageItems()
        return

    def showNextPage(self):
        taskMgr.remove('clarabelleHelpText1')
        messenger.send('wakeup')
        self.pageIndex = self.pageIndex + 1
        if self.viewing == None:
            self.modeNewCatalog()
            self.viewing == 'New'
        if self.viewing == 'New' and self.pageIndex > self.maxPageIndex and self.numBackPages > 0:
            self.showBackorderItems()
        if self.viewing == 'New' and self.pageIndex > self.maxPageIndex and self.numSpecialPages > 0:
            self.showSpecialItems()
        elif self.viewing == 'Backorder' and self.pageIndex > self.maxPageIndex and self.numSpecialPages > 0:
            self.showSpecialItems()
        elif self.viewing == 'Special' and self.pageIndex > self.maxPageIndex and self.numEmblemPages > 0:
            self.showEmblemItems()
        else:
            self.pageIndex = min(self.pageIndex, self.maxPageIndex)
            self.showPageItems()
        return

    def showBackPage(self):
        taskMgr.remove('clarabelleHelpText1')
        messenger.send('wakeup')
        self.pageIndex = self.pageIndex - 1
        if self.viewing == 'Backorder' and self.pageIndex < 0 and self.numNewPages > 0:
            self.showNewItems(self.numNewPages - 1)
        elif self.viewing == 'Special' and self.pageIndex < 0 and self.numBackPages > 0:
            self.showBackorderItems(self.numBackPages - 1)
        elif self.viewing == 'Emblem' and self.pageIndex < 0 and self.numSpecialPages > 0:
            self.showSpecialItems(self.numSpecialPages - 1)
        else:
            self.pageIndex = max(self.pageIndex, -1)
            self.showPageItems()

    def showPageItems(self):
        self.hidePages()
        if self.viewing == None:
            self.viewing = 'New'
        if self.pageIndex < 0:
            self.closeCover()
        else:
            if self.pageIndex == 0:
                self.openCover()
            if self.viewing == 'New':
                page = self.pageList[self.pageIndex]
                newOrBackOrSpecial = 0
            elif self.viewing == 'Backorder':
                page = self.backPageList[self.pageIndex]
                newOrBackOrSpecial = 1
            elif self.viewing == 'Special':
                page = self.specialPageList[self.pageIndex]
                newOrBackOrSpecial = 2
            elif self.viewing == 'Emblem':
                page = self.emblemPageList[self.pageIndex]
                newOrBackOrSpecial = 3
            page.show()
            for panel in self.panelDict[page.get_key()]:
                panel.load()
                if panel.ival:
                    panel.ival.loop()
                self.visiblePanels.append(panel)

            pIndex = 0
            randGen = random.Random()
            randGen.seed(base.localAvatar.catalogScheduleCurrentWeek + (self.pageIndex << 8) + (newOrBackOrSpecial << 16))
            for i in xrange(NUM_CATALOG_ROWS):
                for j in xrange(NUM_CATALOG_COLS):
                    if pIndex < len(self.visiblePanels):
                        type = self.visiblePanels[pIndex]['item'].getTypeCode()
                        self.squares[i][j].setColor(CatalogPanelColors.values()[randGen.randint(0, len(CatalogPanelColors) - 1)])
                        cs = 0.7 + 0.3 * randGen.random()
                        self.squares[i][j].setColorScale(0.7 + 0.3 * randGen.random(), 0.7 + 0.3 * randGen.random(), 0.7 + 0.3 * randGen.random(), 1)
                    else:
                        self.squares[i][j].setColor(CatalogPanelColors[CatalogItemTypes.CHAT_ITEM])
                        self.squares[i][j].clearColorScale()
                    pIndex += 1

            if self.viewing == 'New':
                text = TTLocalizer.CatalogNew
            elif self.viewing == 'Special':
                text = TTLocalizer.CatalogSpecial
            elif self.viewing == 'Backorder':
                text = TTLocalizer.CatalogBackorder
            elif self.viewing == 'Emblem':
                text = TTLocalizer.CatalogEmblem
            self.pageLabel['text'] = text + ' - %d' % (self.pageIndex + 1)
            if self.pageIndex < self.maxPageIndex:
                self.nextPageButton.show()
            elif self.viewing == 'New' and self.numBackPages == 0 and self.numSpecialPages == 0:
                self.nextPageButton.hide()
            elif self.viewing == 'Backorder' and self.numSpecialPages == 0:
                self.nextPageButton.hide()
            elif self.viewing == 'Special' and self.numEmblemPages == 0:
                self.nextPageButton.hide()
            elif self.viewing == 'Special' and self.numEmblemPages > 0:
                self.nextPageButton.show()
            elif self.viewing == 'Emblem':
                self.nextPageButton.hide()
            self.adjustForSound()
            self.update()
        return

    def adjustForSound(self):
        numEmoteItems = 0
        emotePanels = []
        for visIndex in xrange(len(self.visiblePanels)):
            panel = self.visiblePanels[visIndex]
            item = panel['item']
            catalogType = item.getTypeCode()
            if catalogType == CatalogItemTypes.EMOTE_ITEM:
                numEmoteItems += 1
                emotePanels.append(panel)
            else:
                panel.soundOnButton.hide()
                panel.soundOffButton.hide()

        if numEmoteItems == 1:
            emotePanels[0].handleSoundOnButton()
        elif numEmoteItems > 1:
            for panel in emotePanels:
                panel.handleSoundOffButton()

    def hidePages(self):
        for page in self.pageList:
            page.hide()

        for page in self.backPageList:
            page.hide()

        for page in self.specialPageList:
            page.hide()

        for page in self.emblemPageList:
            page.hide()

        for panel in self.visiblePanels:
            if panel.ival:
                panel.ival.finish()

        self.visiblePanels = []

    def openCover(self):
        self.cover.hide()
        self.hideDummyTabs()
        self.backPageButton.show()
        self.pageLabel.show()

    def closeCover(self):
        self.cover.show()
        self.showDummyTabs()
        self.nextPageButton.show()
        self.backPageButton.hide()
        self.pageLabel.hide()
        self.hidePages()

    def showDummyTabs(self):
        if self.numNewPages > 0:
            self.newCatalogButton2.show()
        if self.numBackPages > 0:
            self.backCatalogButton2.show()
        if self.numSpecialPages > 0:
            self.specialCatalogButton2.show()
        if self.numEmblemPages > 0:
            self.emblemCatalogButton2.show()
        self.newCatalogButton.hide()
        self.backCatalogButton.hide()
        self.specialCatalogButton.hide()
        self.emblemCatalogButton.hide()

    def hideDummyTabs(self):
        self.newCatalogButton2.hide()
        self.backCatalogButton2.hide()
        self.specialCatalogButton2.hide()
        self.emblemCatalogButton2.hide()
        if self.numNewPages > 0:
            self.newCatalogButton.show()
        if self.numBackPages > 0:
            self.backCatalogButton.show()
        if self.numSpecialPages > 0:
            self.specialCatalogButton.show()
        if self.numEmblemPages > 0:
            self.emblemCatalogButton.show()

    def packPages(self, panelList, pageList, prefix):
        i = 0
        j = 0
        numPages = 0
        pageName = prefix + '_page%d' % numPages
        for item in panelList:
            if i == 0 and j == 0:
                numPages += 1
                pageName = prefix + '_page%d' % numPages
                page = self.base.attachNewNode(pageName)
                pageList.append(page)
            item.reparentTo(page)
            item.setPos(CatalogPanelCenters[i][j])
            itemList = self.panelDict.get(page.get_key(), [])
            itemList.append(item)
            self.panelDict[page.get_key()] = itemList
            j += 1
            if j == NUM_CATALOG_COLS:
                j = 0
                i += 1
            if i == NUM_CATALOG_ROWS:
                i = 0

        return numPages

    def load(self, guiItems, guiButton, guiBack):
        self.pageIndex = -1
        self.maxPageIndex = 0
        self.numNewPages = 0
        self.numBackPages = 5
        self.numSpecialPages = 0
        self.viewing = 'New'
        self.panelList = []
        self.backPanelList = []
        self.pageList = []
        self.backPageList = []
        self.specialPanelList = []
        self.specialPageList = []
        self.emblemPanelList = []
        self.emblemPageList = []
        self.panelDict = {}
        self.visiblePanels = []
        self.responseDialog = None
        catalogBase = guiItems.find('**/catalog_base')
        self.base = DirectLabel(self, relief=None, image=catalogBase)
        newDown = guiItems.find('**/new1')
        newUp = guiItems.find('**/new2')
        backDown = guiItems.find('**/previous2')
        backUp = guiItems.find('**/previous1')
        giftToggleUp = guiItems.find('**/giftButtonUp')
        giftToggleDown = guiItems.find('**/giftButtonDown')
        giftFriends = guiItems.find('**/gift_names')
        oldLift = 0.4
        lift = 0.4
        liftDiff = lift - oldLift
        lift2 = 0.05
        smash = 0.75
        priceScale = 0.15
        emblemIcon = loader.loadModel('phase_3.5/models/gui/tt_m_gui_gen_emblemIcons')
        silverModel = emblemIcon.find('**/tt_t_gui_gen_emblemSilver')
        goldModel = emblemIcon.find('**/tt_t_gui_gen_emblemGold')
        self.silverLabel = DirectLabel(parent=self, relief=None, pos=(1.05, 0, -0.6), scale=priceScale, image=silverModel, image_pos=(-0.4, 0, 0.4), text=str(localAvatar.emblems[ToontownGlobals.EmblemTypes.Silver]), text_fg=(0.95, 0.95, 0, 1), text_shadow=(0, 0, 0, 1), text_font=ToontownGlobals.getSignFont(), text_align=TextNode.ALeft)
        base.silverLabel = self.silverLabel
        self.goldLabel = DirectLabel(parent=self, relief=None, pos=(1.05, 0, -0.8), scale=priceScale, image=goldModel, image_pos=(-0.4, 0, 0.4), text=str(localAvatar.emblems[ToontownGlobals.EmblemTypes.Gold]), text_fg=(0.95, 0.95, 0, 1), text_shadow=(0, 0, 0, 1), text_font=ToontownGlobals.getSignFont(), text_align=TextNode.ALeft)
        base.goldLabel = self.goldLabel
        if not base.cr.wantEmblems:
            self.hideEmblems()
        self.newCatalogButton = DirectButton(self.base, relief=None, pos=(0, 0, 0.17), frameSize=(-0.2,
         0.25,
         0.45,
         1.2), image=[newDown,
         newDown,
         newDown,
         newUp], image_scale=(1.0, 1.0, smash), image_pos=(0.0, 0.0, lift), pressEffect=0, command=self.showNewItems, text=TTLocalizer.CatalogNew, text_font=ToontownGlobals.getSignFont(), text_pos=(-0.4 - lift, 0.13), text3_pos=(-0.4 - lift, 0.1), text_scale=0.08, text_fg=(0.353, 0.627, 0.627, 1.0), text2_fg=(0.353, 0.427, 0.427, 1.0))
        self.newCatalogButton.hide()
        self.newCatalogButton2 = DirectButton(self.base, relief=None, pos=(0, 0, 0.17), frameSize=(-0.2,
         0.25,
         0.45,
         1.2), image=newDown, image_scale=(1.0, 1.0, smash), image_pos=(0.0, 0.0, lift), pressEffect=0, command=self.showNewItems, text=TTLocalizer.CatalogNew, text_font=ToontownGlobals.getSignFont(), text_pos=(-0.4 - lift, 0.13), text_scale=0.08, text_fg=(0.353, 0.627, 0.627, 1.0), text2_fg=(0.353, 0.427, 0.427, 1.0))
        self.newCatalogButton2.hide()
        self.backCatalogButton = DirectButton(self.base, relief=None, pos=(0, 0, 0.269), frameSize=(-0.2,
         0.25,
         -0.2,
         0.4), image=[backDown,
         backDown,
         backDown,
         backUp], image_scale=(1.0, 1.0, smash), image_pos=(0.0, 0.0, lift), pressEffect=0, command=self.showBackorderItems, text=TTLocalizer.CatalogBackorder, text_font=ToontownGlobals.getSignFont(), text_pos=(0.25 - lift, 0.132), text3_pos=(0.25 - lift, 0.112), text_scale=TTLocalizer.CSbackCatalogButton, text_fg=(0.392, 0.549, 0.627, 1.0), text2_fg=(0.392, 0.349, 0.427, 1.0))
        self.backCatalogButton.hide()
        self.backCatalogButton2 = DirectButton(self.base, relief=None, pos=(0, 0, 0.269), frameSize=(-0.2,
         0.25,
         -0.2,
         0.4), image_scale=(1.0, 1.0, smash), image_pos=(0.0, 0.0, lift), image=backDown, pressEffect=0, command=self.showBackorderItems, text=TTLocalizer.CatalogBackorder, text_font=ToontownGlobals.getSignFont(), text_pos=(0.25 - lift, 0.132), text_scale=TTLocalizer.CSbackCatalogButton, text_fg=(0.392, 0.549, 0.627, 1.0), text2_fg=(0.392, 0.349, 0.427, 1.0))
        self.backCatalogButton2.hide()
        self.specialCatalogButton = DirectButton(self.base, relief=None, pos=(0, 0, 0.469), frameSize=(-0.2,
         0.25,
         -0.85,
         -0.3), image=[newDown,
         newDown,
         newDown,
         newUp], image_scale=(1.0, 1.0, smash), image_pos=(0.0, 0.0, -1.4 + lift), pressEffect=0, command=self.showSpecialItems, text=TTLocalizer.CatalogSpecial, text_font=ToontownGlobals.getSignFont(), text_pos=(1.0 - lift, 0.132), text3_pos=(1.0 - lift, 0.112), text_scale=0.065, text_fg=(0.353, 0.627, 0.627, 1.0), text2_fg=(0.353, 0.427, 0.427, 1.0))
        self.specialCatalogButton.hide()
        self.specialCatalogButton2 = DirectButton(self.base, relief=None, pos=(0, 0, 0.469), frameSize=(-0.2,
         0.25,
         -0.85,
         -0.3), image_scale=(1.0, 1.0, smash), image_pos=(0.0, 0.0, -1.4 + lift), image=newDown, pressEffect=0, command=self.showSpecialItems, text=TTLocalizer.CatalogSpecial, text_font=ToontownGlobals.getSignFont(), text_pos=(1.0 - lift, 0.132), text_scale=0.065, text_fg=(0.353, 0.627, 0.627, 1.0), text2_fg=(0.353, 0.427, 0.427, 1.0))
        self.specialCatalogButton2.hide()
        self.emblemCatalogButton = DirectButton(self.base, relief=None, pos=(0, 0, 1.05), frameSize=(-0.2,
         0.25,
         -2.0,
         -1.45), image=[backDown,
         backDown,
         backDown,
         backUp], image_scale=(1.0, 1.0, smash), image_pos=(0.0, 0.0, -1.9 + lift), pressEffect=0, command=self.showEmblemItems, text=TTLocalizer.CatalogEmblem, text_font=ToontownGlobals.getSignFont(), text_pos=(1.75, 0.132), text3_pos=(1.75, 0.112), text_scale=0.065, text_fg=(0.353, 0.627, 0.627, 1.0), text2_fg=(0.353, 0.427, 0.427, 1.0))
        self.emblemCatalogButton.hide()
        self.emblemCatalogButton2 = DirectButton(self.base, relief=None, pos=(0, 0, 1.05), frameSize=(-0.2,
         0.25,
         -2.0,
         -1.45), image_scale=(1.0, 1.0, smash), image_pos=(0.0, 0.0, -1.9 + lift), image=backDown, pressEffect=0, command=self.showEmblemItems, text=TTLocalizer.CatalogEmblem, text_font=ToontownGlobals.getSignFont(), text_pos=(1.75, 0.132), text_scale=0.065, text_fg=(0.353, 0.627, 0.627, 1.0), text2_fg=(0.353, 0.427, 0.427, 1.0))
        self.emblemCatalogButton2.hide()
        self.__makeFriendList()
        if len(self.friendList) > 0:
            if config.GetBool('want-gifting', True):
                self.giftToggle = DirectButton(self.base, relief=None, pressEffect=0, image=(giftToggleUp, giftToggleDown, giftToggleUp), image_scale=(1.0, 1, 0.7), command=self.__giftToggle, text=TTLocalizer.CatalogGiftToggleOff, text_font=ToontownGlobals.getSignFont(), text_pos=TTLocalizer.CSgiftTogglePos, text_scale=TTLocalizer.CSgiftToggle, text_fg=(0.353, 0.627, 0.627, 1.0), text3_fg=(0.15, 0.3, 0.3, 1.0), text2_fg=(0.353, 0.427, 0.427, 1.0), image_color=Vec4(1.0, 1.0, 0.2, 1.0), image1_color=Vec4(0.9, 0.85, 0.2, 1.0), image2_color=Vec4(0.9, 0.85, 0.2, 1.0), image3_color=Vec4(0.5, 0.45, 0.2, 1.0))
                self.giftToggle.setPos(0.0, 0, -0.035)
            self.giftLabel = DirectLabel(self.base, relief=None, image=giftFriends, image_scale=(1.15, 1, 1.14), text=' ', text_font=ToontownGlobals.getSignFont(), text_pos=(1.2, -0.97), text_scale=0.07, text_fg=(0.392, 0.549, 0.627, 1.0), sortOrder=100, textMayChange=1)
            self.giftLabel.setPos(-0.15, 0, 0.08)
            self.giftLabel.hide()
            self.friendLabel = DirectLabel(self.base, relief=None, text=TTLocalizer.CatalogGiftChoose, text_font=ToontownGlobals.getSignFont(), text_pos=(-0.25, 0.132), text_scale=0.068, text_align=TextNode.ALeft, text_fg=(0.992, 0.949, 0.327, 1.0), sortOrder=100, textMayChange=1)
            self.friendLabel.setPos(0.5, 0, -0.42)
            self.friendLabel.hide()
            gui = loader.loadModel('phase_3.5/models/gui/friendslist_gui')
            self.scrollList = DirectScrolledList(parent=self, relief=None, incButton_image=(gui.find('**/FndsLst_ScrollUp'),
             gui.find('**/FndsLst_ScrollDN'),
             gui.find('**/FndsLst_ScrollUp_Rllvr'),
             gui.find('**/FndsLst_ScrollUp')), incButton_relief=None, incButton_pos=(0.0, 0.0, -0.316), incButton_image1_color=Vec4(1.0, 0.9, 0.4, 1.0), incButton_image3_color=Vec4(1.0, 1.0, 0.6, 0.5), incButton_scale=(1.0, 1.0, -1.0), decButton_image=(gui.find('**/FndsLst_ScrollUp'),
             gui.find('**/FndsLst_ScrollDN'),
             gui.find('**/FndsLst_ScrollUp_Rllvr'),
             gui.find('**/FndsLst_ScrollUp')), decButton_relief=None, decButton_pos=(0.0, 0.0, 0.117), decButton_image1_color=Vec4(1.0, 1.0, 0.6, 1.0), decButton_image3_color=Vec4(1.0, 1.0, 0.6, 0.6), itemFrame_pos=(-0.17, 0.0, 0.06), itemFrame_relief=None, numItemsVisible=8, items=[])
            self.scrollList.setPos(1.2, 0, -0.58)
            self.scrollList.setScale(1.5)
            self.scrollList.hide()
            clipper = PlaneNode('clipper')
            clipper.setPlane(Plane(Vec3(-1, 0, 0), Point3(0.17, 0, 0)))
            clipNP = self.scrollList.attachNewNode(clipper)
            self.scrollList.setClipPlane(clipNP)
            self.__makeScrollList()
            self.createdGiftGui = 1
        for i in xrange(4):
            self.newCatalogButton.component('text%d' % i).setR(90)
            self.newCatalogButton2.component('text%d' % i).setR(90)
            self.backCatalogButton.component('text%d' % i).setR(90)
            self.backCatalogButton2.component('text%d' % i).setR(90)
            self.specialCatalogButton.component('text%d' % i).setR(90)
            self.specialCatalogButton2.component('text%d' % i).setR(90)
            self.emblemCatalogButton.component('text%d' % i).setR(90)
            self.emblemCatalogButton2.component('text%d' % i).setR(90)

        self.squares = [[],
         [],
         [],
         []]
        for i in xrange(NUM_CATALOG_ROWS):
            for j in xrange(NUM_CATALOG_COLS):
                square = guiItems.find('**/square%d%db' % (i + 1, j + 1))
                label = DirectLabel(self.base, image=square, relief=None, state='normal')
                self.squares[i].append(label)

        def priceSort(a, b, type):
            priceA = a.getPrice(type)
            priceB = b.getPrice(type)
            return priceB - priceA

        itemList = base.localAvatar.monthlyCatalog + base.localAvatar.weeklyCatalog
        itemList.sort(lambda a, b: priceSort(a, b, CatalogItem.CatalogTypeWeekly))
        itemList.reverse()
        allClosetItems = CatalogFurnitureItem.getAllClosets()
        allBankItems = CatalogFurnitureItem.getAllBanks()
        isMaxClosetOfferred = False
        isMaxBankOffered = False
        for item in itemList:
            if item in allClosetItems and item.furnitureType in CatalogFurnitureItem.MaxClosetIds:
                isMaxClosetOfferred = True
                break

        for item in itemList:
            if item in allBankItems and item.furnitureType == CatalogFurnitureItem.MaxBankId:
                isMaxBankOffered = True
                break

        for item in itemList:
            if isinstance(item, CatalogInvalidItem.CatalogInvalidItem):
                self.notify.warning('skipping catalog invalid item %s' % item)
                continue
            if isMaxClosetOfferred and item in allClosetItems and item.furnitureType not in CatalogFurnitureItem.MaxClosetIds:
                continue
            if isMaxBankOffered and item in allBankItems and item.furnitureType != CatalogFurnitureItem.MaxBankId:
                continue
            if item.getIsSpecial():
                self.specialPanelList.append(CatalogItemPanel.CatalogItemPanel(parent=hidden, item=item, type=CatalogItem.CatalogTypeSpecial, parentCatalogScreen=self))
            elif item.getEmblemPrices():
                self.emblemPanelList.append(CatalogItemPanel.CatalogItemPanel(parent=hidden, item=item, type=CatalogItem.CatalogTypeWeekly, parentCatalogScreen=self))
            else:
                self.panelList.append(CatalogItemPanel.CatalogItemPanel(parent=hidden, item=item, type=CatalogItem.CatalogTypeWeekly, parentCatalogScreen=self))

        itemList = base.localAvatar.backCatalog
        itemList.sort(lambda a, b: priceSort(a, b, CatalogItem.CatalogTypeBackorder))
        itemList.reverse()
        for item in itemList:
            if isinstance(item, CatalogInvalidItem.CatalogInvalidItem):
                self.notify.warning('skipping catalog invalid item %s' % item)
                continue
            if isMaxClosetOfferred and item in allClosetItems and item.furnitureType not in CatalogFurnitureItem.MaxClosetIds:
                continue
            if isMaxBankOffered and item in allBankItems and item.furnitureType != CatalogFurnitureItem.MaxBankId:
                continue
            if item.getIsSpecial():
                self.specialPanelList.append(CatalogItemPanel.CatalogItemPanel(parent=hidden, item=item, type=CatalogItem.CatalogTypeSpecial, parentCatalogScreen=self))
            elif item.getEmblemPrices():
                self.emblemPanelList.append(CatalogItemPanel.CatalogItemPanel(parent=hidden, item=item, type=CatalogItem.CatalogTypeBackorder, parentCatalogScreen=self))
            else:
                self.backPanelList.append(CatalogItemPanel.CatalogItemPanel(parent=hidden, item=item, type=CatalogItem.CatalogTypeBackorder, parentCatalogScreen=self))

        numPages = self.packPages(self.panelList, self.pageList, 'new')
        self.setNumNewPages(numPages)
        numPages = self.packPages(self.backPanelList, self.backPageList, 'back')
        self.setNumBackPages(numPages)
        numPages = self.packPages(self.specialPanelList, self.specialPageList, 'special')
        self.setNumSpecialPages(numPages)
        numPages = self.packPages(self.emblemPanelList, self.emblemPageList, 'emblem')
        self.setNumEmblemPages(numPages)
        currentWeek = base.localAvatar.catalogScheduleCurrentWeek - 1
        if currentWeek < 57:
            seriesNumber = currentWeek / ToontownGlobals.CatalogNumWeeksPerSeries + 1
            weekNumber = currentWeek % ToontownGlobals.CatalogNumWeeksPerSeries + 1
        elif currentWeek < 65:
            seriesNumber = 6
            weekNumber = currentWeek - 56
        else:
            seriesNumber = currentWeek / ToontownGlobals.CatalogNumWeeksPerSeries + 2
            weekNumber = currentWeek % ToontownGlobals.CatalogNumWeeksPerSeries + 1
        geom = NodePath('cover')
        cover = guiItems.find('**/cover')
        maxSeries = ToontownGlobals.CatalogNumWeeks / ToontownGlobals.CatalogNumWeeksPerSeries + 1
        coverSeries = (seriesNumber - 1) % maxSeries + 1
        coverPicture = cover.find('**/cover_picture%s' % coverSeries)
        if not coverPicture.isEmpty():
            coverPicture.reparentTo(geom)
        bottomSquare = cover.find('**/cover_bottom')
        topSquare = guiItems.find('**/square12b2')
        if seriesNumber == 1:
            topSquare.setColor(0.651, 0.404, 0.322, 1.0)
            bottomSquare.setColor(0.655, 0.522, 0.263, 1.0)
        else:
            topSquare.setColor(0.651, 0.404, 0.322, 1.0)
            bottomSquare.setColor(0.655, 0.522, 0.263, 1.0)
        bottomSquare.reparentTo(geom)
        topSquare.reparentTo(geom)
        cover.find('**/clarabelle_text').reparentTo(geom)
        cover.find('**/blue_circle').reparentTo(geom)
        cover.find('**/clarabelle').reparentTo(geom)
        cover.find('**/circle_green').reparentTo(geom)
        self.cover = DirectLabel(self.base, relief=None, geom=geom)
        self.catalogNumber = DirectLabel(self.cover, relief=None, scale=0.2, pos=(-0.22, 0, -0.33), text='#%d' % weekNumber, text_fg=(0.95, 0.95, 0, 1), text_shadow=(0, 0, 0, 1), text_font=ToontownGlobals.getInterfaceFont())
        self.catalogSeries = DirectLabel(self.cover, relief=None, scale=(0.22, 1, 0.18), pos=(-0.76, 0, -0.9), text=TTLocalizer.CatalogSeriesLabel % seriesNumber, text_fg=(0.9, 0.9, 0.4, 1), text_shadow=(0, 0, 0, 1), text_font=ToontownGlobals.getInterfaceFont())
        self.catalogSeries.setShxz(0.4)
        self.rings = DirectLabel(self.base, relief=None, geom=guiItems.find('**/rings'))
        self.clarabelleFrame = DirectLabel(self, relief=None, image=guiItems.find('**/clarabelle_frame'))
        hangupGui = guiItems.find('**/hangup')
        hangupRolloverGui = guiItems.find('**/hangup_rollover')
        self.hangup = DirectButton(self, relief=None, pos=(-0.158, 0, 0.14), scale=(0.7, 0.7, 0.7), image=[hangupGui,
         hangupRolloverGui,
         hangupRolloverGui,
         hangupGui], text=['', TTLocalizer.CatalogHangUp, TTLocalizer.CatalogHangUp], text_fg=Vec4(1), text_scale=0.07, text_pos=(0.0, 0.14), command=self.hangUp)
        self.hangup.reparentTo(base.a2dBottomRight)
        self.beanBank = DirectLabel(self, relief=None, image=guiItems.find('**/bean_bank'), text=str(base.localAvatar.getMoney() + base.localAvatar.getBankMoney()), text_align=TextNode.ARight, text_scale=0.11, text_fg=(0.95, 0.95, 0, 1), text_shadow=(0, 0, 0, 1), text_pos=(0.75, -0.81), text_font=ToontownGlobals.getSignFont())
        nextUp = guiItems.find('**/arrow_up')
        nextRollover = guiItems.find('**/arrow_Rollover')
        nextDown = guiItems.find('**/arrow_Down')
        prevUp = guiItems.find('**/arrowUp')
        prevDown = guiItems.find('**/arrowDown1')
        prevRollover = guiItems.find('**/arrowRollover')
        self.nextPageButton = DirectButton(self, relief=None, pos=(-0.1, 0, -0.9), image=[nextUp,
         nextDown,
         nextRollover,
         nextUp], image_color=(0.9, 0.9, 0.9, 1), image2_color=(1, 1, 1, 1), command=self.showNextPage)
        self.backPageButton = DirectButton(self, relief=None, pos=(-0.1, 0, -0.9), image=[prevUp,
         prevDown,
         prevRollover,
         prevUp], image_color=(0.9, 0.9, 0.9, 1), image2_color=(1, 1, 1, 1), command=self.showBackPage)
        self.backPageButton.hide()
        self.pageLabel = DirectLabel(self.base, relief=None, pos=(-1.33, 0, -0.9), scale=0.06, text=TTLocalizer.CatalogPagePrefix, text_fg=(0.95, 0.95, 0, 1), text_shadow=(0, 0, 0, 1), text_font=ToontownGlobals.getSignFont(), text_align=TextNode.ALeft)
        self.loadClarabelle()
        return

    def loadClarabelle(self):
        self.cRender = NodePath('cRender')
        self.cCamera = self.cRender.attachNewNode('cCamera')
        self.cCamNode = Camera('cCam')
        self.cLens = PerspectiveLens()
        self.cLens.setFov(40, 40)
        self.cLens.setNear(0.1)
        self.cLens.setFar(100.0)
        self.cCamNode.setLens(self.cLens)
        self.cCamNode.setScene(self.cRender)
        self.cCam = self.cCamera.attachNewNode(self.cCamNode)
        self.cDr = base.win.makeDisplayRegion(0.56, 0.81, 0.52, 0.85)
        self.cDr.setSort(1)
        self.cDr.setClearDepthActive(1)
        self.cDr.setClearColorActive(1)
        self.cDr.setClearColor(Vec4(0.3, 0.3, 0.3, 1))
        self.cDr.setCamera(self.cCam)
        self.clarabelle = Actor.Actor('phase_5.5/models/char/Clarabelle-zero', {'listen': 'phase_5.5/models/char/Clarabelle-listens'})
        self.clarabelle.loop('listen')
        self.clarabelle.find('**/eyes').setBin('fixed', 0)
        self.clarabelle.find('**/pupilL').setBin('fixed', 1)
        self.clarabelle.find('**/pupilR').setBin('fixed', 1)
        self.clarabelle.find('**/glassL').setBin('fixed', 2)
        self.clarabelle.find('**/glassR').setBin('fixed', 2)
        switchboard = loader.loadModel('phase_5.5/models/estate/switchboard')
        switchboard.reparentTo(self.clarabelle)
        switchboard.setPos(1, -1.6, 0)
        switchboard.setH(30)
        room = loader.loadModel('phase_3/models/makeatoon/tt_m_ara_mat_room.bam')
        room.reparentTo(self.clarabelle)
        room.find('**/genderProps').removeNode()
        room.find('**/bodyWalls').removeNode()
        room.find('**/bodyProps').removeNode()
        room.find('**/colorWalls').removeNode()
        room.find('**/colorProps').removeNode()
        room.find('**/clothWalls').removeNode()
        room.find('**/nameWalls').removeNode()
        room.find('**/nameProps').removeNode()
        room.find('**/spotlight').removeNode()
        room.setPos(5.5, 1.25, 0)
        room.setH(330)
        self.clarabelle.reparentTo(self.cRender)
        self.clarabelle.setPosHprScale(-0.52, 6.13, -3.81, 85, 0.0, 0.0, 1.0, 1.0, 1.0)
        self.clarabelleFrame.setPosHprScale(-0.01, 0.0, -0.01, 0.0, 0.0, 0.0, 1.02, 1.0, 1.02)

    def reload(self):
        for panel in self.panelList + self.backPanelList + self.specialPanelList + self.emblemPanelList:
            panel.destroy()

        def priceSort(a, b, type):
            priceA = a.getPrice(type)
            priceB = b.getPrice(type)
            return priceB - priceA

        self.pageIndex = -1
        self.maxPageIndex = 0
        self.numNewPages = 0
        self.numBackPages = 5
        self.numSpecialPages = 0
        self.viewing = 'New'
        self.panelList = []
        self.backPanelList = []
        self.specialList = []
        self.pageList = []
        self.backPageList = []
        self.specialPanelList = []
        self.specialPageList = []
        self.panelDict = {}
        self.visiblePanels = []
        itemList = base.localAvatar.monthlyCatalog + base.localAvatar.weeklyCatalog
        itemList.sort(lambda a, b: priceSort(a, b, CatalogItem.CatalogTypeWeekly))
        itemList.reverse()
        for item in itemList:
            if item.getIsSpecial():
                self.specialPanelList.append(CatalogItemPanel.CatalogItemPanel(parent=hidden, item=item, type=CatalogItem.CatalogTypeSpecial, parentCatalogScreen=self))
            else:
                self.panelList.append(CatalogItemPanel.CatalogItemPanel(parent=hidden, item=item, type=CatalogItem.CatalogTypeWeekly))

        itemList = base.localAvatar.backCatalog
        itemList.sort(lambda a, b: priceSort(a, b, CatalogItem.CatalogTypeBackorder))
        itemList.reverse()
        for item in itemList:
            if item.getIsSpecial():
                self.specialPanelList.append(CatalogItemPanel.CatalogItemPanel(parent=hidden, item=item, type=CatalogItem.CatalogTypeSpecial, parentCatalogScreen=self))
            else:
                self.backPanelList.append(CatalogItemPanel.CatalogItemPanel(parent=hidden, item=item, type=CatalogItem.CatalogTypeBackorder))

        numPages = self.packPages(self.panelList, self.pageList, 'new')
        self.setNumNewPages(numPages)
        numPages = self.packPages(self.backPanelList, self.backPageList, 'back')
        self.setNumBackPages(numPages)
        numPages = self.packPages(self.specialPanelList, self.specialPageList, 'special')
        self.setNumSpecialPages(numPages)
        seriesNumber = (base.localAvatar.catalogScheduleCurrentWeek - 1) / ToontownGlobals.CatalogNumWeeksPerSeries + 1
        self.catalogSeries['text'] = Localizer.CatalogSeriesLabel % seriesNumber
        weekNumber = (base.localAvatar.catalogScheduleCurrentWeek - 1) % ToontownGlobals.CatalogNumWeeksPerSeries + 1
        self.catalogNumber['text'] = '#%d' % weekNumber
        self.enableBackorderCatalogButton()
        self.setMaxPageIndex(self.numNewPages)
        self.setPageIndex(-1)
        self.showPageItems()

    def unload(self):
        taskMgr.remove('clearClarabelleChat')
        taskMgr.remove('postGoodbyeHangUp')
        taskMgr.remove('clarabelleGreeting')
        taskMgr.remove('clarabelleHelpText1')
        taskMgr.remove('clarabelleAskAnythingElse')
        taskMgr.remove('friendButtonsReady')
        self.hide()
        self.hangup.hide()
        self.destroy()
        del self.base
        del self.squares
        for panel in self.panelList + self.backPanelList + self.specialPanelList + self.emblemPanelList:
            panel.destroy()

        del self.panelList
        del self.backPanelList
        del self.cover
        del self.rings
        del self.clarabelleFrame
        del self.hangup
        del self.beanBank
        del self.silverLabel
        del self.goldLabel
        del self.nextPageButton
        del self.backPageButton
        del self.newCatalogButton
        del self.newCatalogButton2
        del self.backCatalogButton
        del self.backCatalogButton2
        del self.specialCatalogButton
        del self.specialCatalogButton2
        del self.pageLabel
        if self.createdGiftGui:
            del self.giftToggle
            del self.giftLabel
            del self.friendLabel
            del self.scrollList
            del self.friend
            del self.friends
        self.unloadClarabelle()
        if self.responseDialog:
            self.responseDialog.cleanup()
            self.responseDialog = None

    def unloadClarabelle(self):
        base.win.removeDisplayRegion(self.cDr)
        del self.cRender
        del self.cCamera
        del self.cCamNode
        del self.cLens
        del self.cCam
        del self.cDr
        self.clarabelle.cleanup()
        del self.clarabelle

        if self.clarabelleChatBalloon:
            self.clarabelleChatBalloon.removeNode()
            del self.clarabelleChatBalloon

    def hangUp(self):
        self.setClarabelleChat(random.choice(TTLocalizer.CatalogGoodbyeList), type='goodbye')
        self.setPageIndex(-1)
        self.showPageItems()
        self.nextPageButton.hide()
        self.backPageButton.hide()
        self.newCatalogButton.hide()
        self.newCatalogButton2.hide()
        self.backCatalogButton.hide()
        self.backCatalogButton2.hide()
        self.specialCatalogButton.hide()
        self.specialCatalogButton2.hide()
        self.emblemCatalogButton.hide()
        self.emblemCatalogButton2.hide()
        self.hangup.hide()
        taskMgr.remove('clarabelleGreeting')
        taskMgr.remove('clarabelleHelpText1')
        taskMgr.remove('clarabelleAskAnythingElse')

        def postGoodbyeHangUp(task):
            messenger.send(self['doneEvent'])
            self.unload()

        taskMgr.doMethodLater(1.5, postGoodbyeHangUp, 'postGoodbyeHangUp')

    def remoteUpdate(self):
        self.update()

    def update(self, task = None):
        if (not self.friend) and self.gifting == 1:
            self.__giftToggle()
        if hasattr(self, 'beanBank'):
            self.beanBank['text'] = str(base.localAvatar.getTotalMoney())
            for item in self.panelList + self.backPanelList + self.specialPanelList + self.emblemPanelList:
                if type(item) != type(''):
                    item.updateButtons(self.gifting)

    def __handlePurchaseRequest(self, item):
        item.requestPurchase(self['phone'], self.__handlePurchaseResponse)
        taskMgr.remove('clarabelleAskAnythingElse')

    def __handleGiftPurchaseRequest(self, item):
        item.requestGiftPurchase(self['phone'], self.friendAvId, self.__handleGiftPurchaseResponse)
        taskMgr.remove('clarabelleAskAnythingElse')

    def __handlePurchaseResponse(self, retCode, item):
        if retCode == ToontownGlobals.P_UserCancelled:
            self.update()
            return

        if hasattr(item, 'houseId') and retCode == ToontownGlobals.P_ItemAvailable:
            localAvatar.houseType = item.houseId

        taskMgr.doMethodLater(0.5, self.update, 'purchaseUpdate')
        self.setClarabelleChat(item.getRequestPurchaseErrorText(retCode), item.getRequestPurchaseErrorTextTimeout())

    def __handleGiftPurchaseResponse(self, retCode, item):
        if retCode == ToontownGlobals.P_UserCancelled:
            return
        if self.isEmpty() or self.isHidden():
            return
        self.setClarabelleChat(item.getRequestGiftPurchaseErrorText(retCode) % self.friendName)
        self.__loadFriend()

        def askAnythingElse(task):
            self.setClarabelleChat(TTLocalizer.CatalogAnythingElse)

        if retCode >= 0:
            taskMgr.doMethodLater(8, askAnythingElse, 'clarabelleAskAnythingElse')

    def __clearDialog(self, event):
        self.responseDialog.cleanup()
        self.responseDialog = None
        return

    def setClarabelleChat(self, str, timeout = 6, type = None):
        self.clearClarabelleChat()

        if not self.clarabelleChatBalloon:
            self.clarabelleChatBalloon = loader.loadModel('phase_3/models/props/chatbox')

        self.clarabelleChat = ChatBalloon(self.clarabelleChatBalloon)
        chatNode = self.clarabelleChat.generate(str, ToontownGlobals.getInterfaceFont())[0]
        self.clarabelleChatNP = self.attachNewNode(chatNode.node(), 1000)
        self.clarabelleChatNP.setScale(0.08)
        self.clarabelleChatNP.setPos(0.7, 0, 0.6)

        if timeout:
            taskMgr.doMethodLater(timeout, self.clearClarabelleChat, 'clearClarabelleChat')

    def clearClarabelleChat(self, task = None):
        taskMgr.remove('clearClarabelleChat')
        if self.clarabelleChatNP:
            self.clarabelleChatNP.removeNode()
            self.clarabelleChatNP = None
            del self.clarabelleChat
        return

    def __moneyChange(self, money):
        self.update()

    def __bankMoneyChange(self, bankMoney):
        self.update()

    def __emblemChange(self, newEmblems):
        self.silverLabel['text'] = str(newEmblems[0])
        self.goldLabel['text'] = str(newEmblems[1])

    def showEmblems(self):
        if base.cr.wantEmblems:
            self.silverLabel.show()
            self.goldLabel.show()

    def hideEmblems(self):
        self.silverLabel.hide()
        self.goldLabel.hide()

    def __makeFriendList(self):
        for av in base.cr.avList:
            if av.id != base.localAvatar.doId:
                self.friendList.append((av.id, av.name, NametagGroup.CCNonPlayer))
                
        for id, handle in base.cr.friendsMap.items():
            if isinstance(handle, FriendHandle.FriendHandle):
                self.friendList.append((id, handle.getName(), NametagConstants.getFriendColor(handle)))

    def __makeScrollList(self):
        for friend in self.friendList:
            button = self.makeFriendButton(*friend)
            self.scrollList.addItem(button, refresh=0)
            self.friends.append(button)

        self.scrollList.refresh()

    def makeFriendButton(self, avId, name, colorCode):
        color = NametagConstants.NAMETAG_COLORS[colorCode]

        return DirectButton(relief=None, text=name, text_scale=0.04, text_align=TextNode.ALeft, text_fg=color[0][0], text1_bg=(1, 1, 0, 1),
                            text2_bg=(0.5, 0.9, 1, 1), text3_fg=(0.4, 0.8, 0.4, 1), command=self.__chooseFriend, extraArgs=[avId, name])

    def __chooseFriend(self, avId, name):
        messenger.send('wakeup')
        
        if self.friendAvId == avId:
            return

        self.friendAvId = avId
        self.friendName = name
        self.__loadFriend()

    def __loadFriend(self):
        if not self.friendAvId:
            return

        for friendButton in self.friends:
            friendButton['state'] = DGG.DISABLED

        self.friend = None
        self.friendLabel['text'] = TTLocalizer.CatalogGiftUpdating
        taskMgr.remove('friendButtonsReady')
        self['phone'].requestGiftAvatar(self.friendAvId)
    
    def setFriendReady(self, friend):
        self.friend = friend
        self.friendLabel['text'] = TTLocalizer.CatalogGiftTo % self.friendName
        taskMgr.doMethodLater(1.5, self.setFriendButtonsReady, 'friendButtonsReady')
        self.update()
    
    def setFriendButtonsReady(self, task=None):
        for friendButton in self.friends:
            friendButton['state'] = DGG.NORMAL

    def __giftToggle(self):
        messenger.send('wakeup')
        if self.gifting == -1:
            self.gifting = 1
            self.giftLabel.show()
            self.friendLabel.show()
            self.scrollList.show()
            self.hideEmblems()
            self.giftToggle['text'] = TTLocalizer.CatalogGiftToggleOn
            self.friendLabel['text'] = TTLocalizer.CatalogGiftChoose
            self.__loadFriend()
        else:
            self.friend = None
            self.friendAvId = 0
            self.friendName = None
            self.gifting = -1
            self.giftLabel.hide()
            self.friendLabel.hide()
            self.scrollList.hide()
            self.showEmblems()
            self.giftToggle['text'] = TTLocalizer.CatalogGiftToggleOff
            self.update()