import os
import time
from datetime import datetime
from pandac.PandaModules import *
from direct.distributed.MsgTypes import *
from direct.gui.DirectGui import *
from direct.fsm import StateData
from direct.fsm import ClassicFSM
from direct.fsm import State
from direct.directnotify import DirectNotifyGlobal
from direct.task import Task
from otp.otpgui import OTPDialog
from otp.otpbase import OTPLocalizer
from otp.otpbase import OTPGlobals
from otp.uberdog.AccountDetailRecord import AccountDetailRecord, SubDetailRecord
import TTAccount
import GuiScreen

class LoginScreen(StateData.StateData, GuiScreen.GuiScreen):
    AutoLoginName = base.config.GetString('%s-auto-login%s' % (game.name, os.getenv('otp_client', '')), '')
    AutoLoginPassword = base.config.GetString('%s-auto-password%s' % (game.name, os.getenv('otp_client', '')), '')
    notify = DirectNotifyGlobal.directNotify.newCategory('LoginScreen')
    ActiveEntryColor = Vec4(1, 1, 1, 1)
    InactiveEntryColor = Vec4(0.8, 0.8, 0.8, 1)

    def __init__(self, cr, doneEvent):
        self.notify.debug('__init__')
        StateData.StateData.__init__(self, doneEvent)
        GuiScreen.GuiScreen.__init__(self)
        self.cr = cr
        self.loginInterface = self.cr.loginInterface
        self.userName = ''
        self.password = ''
        self.fsm = ClassicFSM.ClassicFSM('LoginScreen', [
         State.State('off', self.enterOff, self.exitOff, [
          'login', 'waitForLoginResponse']),
         State.State('login', self.enterLogin, self.exitLogin, [
          'waitForLoginResponse', 'login', 'showLoginFailDialog']),
         State.State('showLoginFailDialog', self.enterShowLoginFailDialog, self.exitShowLoginFailDialog, [
          'login', 'showLoginFailDialog']),
         State.State('waitForLoginResponse', self.enterWaitForLoginResponse, self.exitWaitForLoginResponse, [
          'login', 'showLoginFailDialog', 'showConnectionProblemDialog']),
         State.State('showConnectionProblemDialog', self.enterShowConnectionProblemDialog, self.exitShowConnectionProblemDialog, [
          'login'])], 'off', 'off')
        self.fsm.enterInitialState()

    def load(self):
        self.notify.debug('load')
        masterScale = 0.8
        textScale = 0.1 * masterScale
        entryScale = 0.08 * masterScale
        lineHeight = 0.21 * masterScale
        buttonScale = 1.15 * masterScale
        buttonLineHeight = 0.14 * masterScale
        self.frame = DirectFrame(parent=aspect2d, relief=None, sortOrder=20)
        self.frame.hide()
        linePos = -0.26
        self.nameLabel = DirectLabel(parent=self.frame, relief=None, pos=(-0.21, 0, linePos), text=OTPLocalizer.LoginScreenUserName, text_scale=textScale, text_align=TextNode.ARight)
        self.nameEntry = DirectEntry(parent=self.frame, relief=DGG.SUNKEN, borderWidth=(0.1,
                                                                                        0.1), scale=entryScale, pos=(-0.125, 0.0, linePos), width=OTPGlobals.maxLoginWidth, numLines=1, focus=0, cursorKeys=1)
        linePos -= lineHeight
        self.passwordLabel = DirectLabel(parent=self.frame, relief=None, pos=(-0.21, 0, linePos), text=OTPLocalizer.LoginScreenPassword, text_scale=textScale, text_align=TextNode.ARight)
        self.passwordEntry = DirectEntry(parent=self.frame, relief=DGG.SUNKEN, borderWidth=(0.1,
                                                                                            0.1), scale=entryScale, pos=(-0.125, 0.0, linePos), width=OTPGlobals.maxLoginWidth, numLines=1, focus=0, cursorKeys=1, obscured=1, command=self.__handleLoginPassword)
        linePos -= lineHeight
        buttonImageScale = (1.7, 1.1, 1.1)
        self.loginButton = DirectButton(parent=self.frame, relief=DGG.RAISED, borderWidth=(0.01,
                                                                                           0.01), pos=(0, 0, linePos), scale=buttonScale, text=OTPLocalizer.LoginScreenLogin, text_scale=0.06, text_pos=(0, -0.02), command=self.__handleLoginButton)
        linePos -= buttonLineHeight
        self.createAccountButton = DirectButton(parent=self.frame, relief=DGG.RAISED, borderWidth=(0.01,
                                                                                                   0.01), pos=(0, 0, linePos), scale=buttonScale, text=OTPLocalizer.LoginScreenCreateAccount, text_scale=0.06, text_pos=(0, -0.02), command=self.__handleCreateAccount)
        linePos -= buttonLineHeight
        self.quitButton = DirectButton(parent=self.frame, relief=DGG.RAISED, borderWidth=(0.01,
                                                                                          0.01), pos=(0, 0, linePos), scale=buttonScale, text=OTPLocalizer.LoginScreenQuit, text_scale=0.06, text_pos=(0, -0.02), command=self.__handleQuit)
        linePos -= buttonLineHeight
        self.dialogDoneEvent = 'loginDialogAck'
        dialogClass = OTPGlobals.getGlobalDialogClass()
        self.dialog = dialogClass(dialogName='loginDialog', doneEvent=self.dialogDoneEvent, message='', style=OTPDialog.Acknowledge, sortOrder=NO_FADE_SORT_INDEX + 100)
        self.dialog.hide()
        self.failDialog = DirectFrame(parent=aspect2dp, relief=DGG.RAISED, borderWidth=(0.01,
                                                                                        0.01), pos=(0,
                                                                                                    0.1,
                                                                                                    0), text='', text_scale=0.08, text_pos=(0.0,
                                                                                                                                            0.3), text_wordwrap=15, sortOrder=NO_FADE_SORT_INDEX)
        linePos = -0.05
        self.failTryAgainButton = DirectButton(parent=self.failDialog, relief=DGG.RAISED, borderWidth=(0.01,
                                                                                                       0.01), pos=(0, 0, linePos), scale=0.9, text=OTPLocalizer.LoginScreenTryAgain, text_scale=0.06, text_pos=(0,
                                                                                                                                                                                                                -0.02), command=self.__handleFailTryAgain)
        linePos -= buttonLineHeight
        self.failCreateAccountButton = DirectButton(parent=self.failDialog, relief=DGG.RAISED, borderWidth=(0.01,
                                                                                                            0.01), pos=(0, 0, linePos), scale=0.9, text=OTPLocalizer.LoginScreenCreateAccount, text_scale=0.06, text_pos=(0,
                                                                                                                                                                                                                          -0.02), command=self.__handleFailCreateAccount)
        linePos -= buttonLineHeight
        self.failDialog.hide()
        self.connectionProblemDialogDoneEvent = 'loginConnectionProblemDlgAck'
        dialogClass = OTPGlobals.getGlobalDialogClass()
        self.connectionProblemDialog = dialogClass(dialogName='connectionProblemDialog', doneEvent=self.connectionProblemDialogDoneEvent, message='', style=OTPDialog.Acknowledge, sortOrder=NO_FADE_SORT_INDEX + 100)
        self.connectionProblemDialog.hide()
        return

    def unload(self):
        self.notify.debug('unload')
        self.nameEntry.destroy()
        self.passwordEntry.destroy()
        self.failTryAgainButton.destroy()
        self.failCreateAccountButton.destroy()
        self.createAccountButton.destroy()
        self.loginButton.destroy()
        self.quitButton.destroy()
        self.dialog.cleanup()
        del self.dialog
        self.failDialog.destroy()
        del self.failDialog
        self.connectionProblemDialog.cleanup()
        del self.connectionProblemDialog
        self.frame.destroy()
        del self.fsm
        del self.loginInterface
        del self.cr

    def enter(self):
        if self.cr.blue:
            self.userName = 'blue'
            self.password = self.cr.blue
            self.fsm.request('waitForLoginResponse')
        elif self.cr.playToken:
            self.userName = '*'
            self.password = self.cr.playToken
            self.fsm.request('waitForLoginResponse')
        elif hasattr(self.cr, 'DISLToken') and self.cr.DISLToken:
            self.userName = '*'
            self.password = self.cr.DISLToken
            self.fsm.request('waitForLoginResponse')
        elif self.AutoLoginName:
            self.userName = self.AutoLoginName
            self.password = self.AutoLoginPassword
            self.fsm.request('waitForLoginResponse')
        else:
            self.fsm.request('login')

    def exit(self):
        self.frame.hide()
        self.ignore(self.dialogDoneEvent)
        self.fsm.requestFinalState()

    def enterOff(self):
        pass

    def exitOff(self):
        pass

    def enterLogin(self):
        self.cr.resetPeriodTimer(None)
        self.userName = ''
        self.password = ''
        self.userName = launcher.getLastLogin()
        if self.userName and self.nameEntry.get():
            if self.userName != self.nameEntry.get():
                self.userName = ''
        self.frame.show()
        self.nameEntry.enterText(self.userName)
        self.passwordEntry.enterText(self.password)
        self.focusList = [
         self.nameEntry, self.passwordEntry]
        focusIndex = 0
        if self.userName:
            focusIndex = 1
        self.startFocusMgmt(startFocus=focusIndex)
        return

    def exitLogin(self):
        self.stopFocusMgmt()

    def enterShowLoginFailDialog(self, msg):
        base.transitions.fadeScreen(0.5)
        self.failDialog['text'] = msg
        self.failDialog.show()

    def __handleFailTryAgain(self):
        self.fsm.request('login')

    def __handleFailCreateAccount(self):
        messenger.send(self.doneEvent, [{'mode': 'createAccount'}])

    def __handleFailNoNewAccountsAck(self):
        self.dialog.hide()
        self.fsm.request('showLoginFailDialog', [self.failDialog['text']])

    def exitShowLoginFailDialog(self):
        base.transitions.noTransitions()
        self.failDialog.hide()

    def __handleLoginPassword(self, password):
        if password != '':
            if self.nameEntry.get() != '':
                self.__handleLoginButton()

    def __handleLoginButton(self):
        self.removeFocus()
        self.userName = self.nameEntry.get()
        self.password = self.passwordEntry.get()
        if self.userName == '':
            self.dialog.setMessage(OTPLocalizer.LoginScreenLoginPrompt)
            self.dialog.show()
            self.acceptOnce(self.dialogDoneEvent, self.__handleEnterLoginAck)
        else:
            self.fsm.request('waitForLoginResponse')

    def __handleQuit(self):
        self.removeFocus()
        messenger.send(self.doneEvent, [{'mode': 'quit'}])

    def __handleCreateAccount(self):
        self.removeFocus()
        messenger.send(self.doneEvent, [{'mode': 'createAccount'}])

    def enterWaitForLoginResponse(self):
        self.cr.handler = self.handleWaitForLoginResponse
        self.cr.userName = self.userName
        self.cr.password = self.password
        try:
            error = self.loginInterface.authorize(self.userName, self.password)
        except TTAccount.TTAccountException, e:
            self.fsm.request('showConnectionProblemDialog', [str(e)])
            return

        if error:
            self.notify.info(error)
            freeTimeExpired = self.loginInterface.getErrorCode() == 10
            if freeTimeExpired:
                self.cr.logAccountInfo()
                messenger.send(self.doneEvent, [{'mode': 'freeTimeExpired'}])
            else:
                self.fsm.request('showLoginFailDialog', [error])
        else:
            self.loginInterface.sendLoginMsg()
            self.waitForDatabaseTimeout(requestName='WaitForLoginResponse')

    def exitWaitForLoginResponse(self):
        self.cleanupWaitingForDatabase()
        self.cr.handler = None
        return

    def enterShowConnectionProblemDialog(self, msg):
        self.connectionProblemDialog.setMessage(msg)
        self.connectionProblemDialog.show()
        self.acceptOnce(self.connectionProblemDialogDoneEvent, self.__handleConnectionProblemAck)

    def __handleConnectionProblemAck(self):
        self.connectionProblemDialog.hide()
        self.fsm.request('login')

    def exitShowConnectionProblemDialog(self):
        pass

    def handleWaitForLoginResponse(self, msgType, di):
        if msgType == CLIENT_LOGIN_2_RESP:
            self.handleLoginResponseMsg2(di)
        elif msgType == CLIENT_LOGIN_RESP:
            self.handleLoginResponseMsg(di)
        elif msgType == CLIENT_LOGIN_3_RESP:
            self.handleLoginResponseMsg3(di)
        elif msgType == CLIENT_LOGIN_TOONTOWN_RESP:
            self.handleLoginToontownResponse(di)
        else:
            self.cr.handleMessageType(msgType, di)

    def getExtendedErrorMsg(self, errorString):
        prefix = 'Bad DC Version Compare'
        if len(errorString) < len(prefix):
            return errorString
        if errorString[:len(prefix)] == prefix:
            return '%s%s' % (errorString, ', address=%s' % base.cr.getServerAddress())
        return errorString

    def handleLoginResponseMsg3(self, di):
        now = time.time()
        returnCode = di.getInt8()
        errorString = self.getExtendedErrorMsg(di.getString())
        self.notify.info('Login response return code %s' % returnCode)
        if returnCode != 0:
            self.notify.info('Login failed: %s' % errorString)
            messenger.send(self.doneEvent, [{'mode': 'reject'}])
            return
        accountDetailRecord = AccountDetailRecord()
        accountDetailRecord.openChatEnabled = di.getString() == 'YES'
        accountDetailRecord.createFriendsWithChat = di.getString() == 'YES'
        chatCodeCreation = di.getString()
        accountDetailRecord.chatCodeCreation = chatCodeCreation == 'YES'
        parentControlledChat = chatCodeCreation == 'PARENT'
        access = di.getString()
        if access == 'VELVET':
            access = OTPGlobals.AccessVelvetRope
        else:
            if access == 'FULL':
                access = OTPGlobals.AccessFull
            else:
                self.notify.warning('Unknown access: %s' % access)
                access = OTPGlobals.AccessUnknown
            accountDetailRecord.piratesAccess = access
            accountDetailRecord.familyAccountId = di.getInt32()
            accountDetailRecord.playerAccountId = di.getInt32()
            accountDetailRecord.playerName = di.getString()
            accountDetailRecord.playerNameApproved = di.getInt8()
            accountDetailRecord.maxAvatars = di.getInt32()
            self.cr.openChatAllowed = accountDetailRecord.openChatEnabled
            self.cr.secretChatAllowed = accountDetailRecord.chatCodeCreation or parentControlledChat
            self.cr.setIsPaid(accountDetailRecord.piratesAccess)
            self.userName = accountDetailRecord.playerName
            self.cr.userName = accountDetailRecord.playerName
            accountDetailRecord.numSubs = di.getUint16()
            for i in range(accountDetailRecord.numSubs):
                subDetailRecord = SubDetailRecord()
                subDetailRecord.subId = di.getUint32()
                subDetailRecord.subOwnerId = di.getUint32()
                subDetailRecord.subName = di.getString()
                subDetailRecord.subActive = di.getString()
                access = di.getString()
                if access == 'VELVET':
                    access = OTPGlobals.AccessVelvetRope
                elif access == 'FULL':
                    access = OTPGlobals.AccessFull
                else:
                    access = OTPGlobals.AccessUnknown
                subDetailRecord.subAccess = access
                subDetailRecord.subLevel = di.getUint8()
                subDetailRecord.subNumAvatars = di.getUint8()
                subDetailRecord.subNumConcur = di.getUint8()
                subDetailRecord.subFounder = di.getString() == 'YES'
                accountDetailRecord.subDetails[subDetailRecord.subId] = subDetailRecord

            accountDetailRecord.WLChatEnabled = di.getString() == 'YES'
            if accountDetailRecord.WLChatEnabled:
                self.cr.whiteListChatEnabled = 1
            self.cr.whiteListChatEnabled = 0
        self.notify.info('End of DISL token parse')
        self.notify.info('accountDetailRecord: %s' % accountDetailRecord)
        self.cr.accountDetailRecord = accountDetailRecord
        self.__handleLoginSuccess()

    def handleLoginResponseMsg2(self, di):
        self.notify.debug('handleLoginResponseMsg2')
        if self.notify.getDebug():
            dgram = di.getDatagram()
            dgram.dumpHex(ostream)
        now = time.time()
        returnCode = di.getUint8()
        errorString = self.getExtendedErrorMsg(di.getString())
        self.userName = di.getString()
        self.cr.userName = self.userName
        accountDetailRecord = AccountDetailRecord()
        self.cr.accountDetailRecord = accountDetailRecord
        canChat = di.getUint8()
        self.cr.secretChatAllowed = canChat
        self.notify.info('Chat from game server login: %s' % canChat)
        sec = di.getUint32()
        usec = di.getUint32()
        serverTime = sec + usec / 1000000.0
        self.cr.serverTimeUponLogin = serverTime
        self.cr.clientTimeUponLogin = now
        self.cr.globalClockRealTimeUponLogin = globalClock.getRealTime()
        if hasattr(self.cr, 'toontownTimeManager'):
            self.cr.toontownTimeManager.updateLoginTimes(serverTime, now, self.cr.globalClockRealTimeUponLogin)
        serverDelta = serverTime - now
        self.cr.setServerDelta(serverDelta)
        self.notify.setServerDelta(serverDelta, 28800)
        self.isPaid = di.getUint8()
        self.cr.setIsPaid(self.isPaid)
        if self.isPaid:
            launcher.setPaidUserLoggedIn()
        self.notify.info('Paid from game server login: %s' % self.isPaid)
        self.cr.resetPeriodTimer(None)
        if di.getRemainingSize() >= 4:
            minutesRemaining = di.getInt32()
            self.notify.info('Minutes remaining from server %s' % minutesRemaining)
            if minutesRemaining >= 0:
                self.notify.info('Spawning period timer')
                self.cr.resetPeriodTimer(minutesRemaining * 60)
            elif self.isPaid:
                self.notify.warning('Negative minutes remaining for paid user (?)')
            else:
                self.notify.warning('Not paid, but also negative minutes remaining (?)')
        else:
            self.notify.info('Minutes remaining not returned from server; not spawning period timer')
        familyStr = di.getString()
        WhiteListResponse = di.getString()
        if WhiteListResponse == 'YES':
            self.cr.whiteListChatEnabled = 1
        else:
            self.cr.whiteListChatEnabled = 0
        if di.getRemainingSize() > 0:
            self.cr.accountDays = self.parseAccountDays(di.getInt32())
        else:
            self.cr.accountDays = 100000
        if di.getRemainingSize() > 0:
            self.lastLoggedInStr = di.getString()
            self.notify.info('last logged in = %s' % self.lastLoggedInStr)
        else:
            self.lastLoggedInStr = ''
        self.cr.lastLoggedIn = datetime.now()
        if hasattr(self.cr, 'toontownTimeManager'):
            self.cr.lastLoggedIn = self.cr.toontownTimeManager.convertStrToToontownTime(self.lastLoggedInStr)
        self.cr.withParentAccount = False
        self.notify.info('Login response return code %s' % returnCode)
        if returnCode == 0:
            self.__handleLoginSuccess()
        elif returnCode == -13:
            self.notify.info('Period Time Expired')
            self.fsm.request('showLoginFailDialog', [
             OTPLocalizer.LoginScreenPeriodTimeExpired])
        else:
            self.notify.info('Login failed: %s' % errorString)
            messenger.send(self.doneEvent, [{'mode': 'reject'}])
        return

    def handleLoginResponseMsg(self, di):
        self.notify.debug('handleLoginResponseMsg1')
        if self.notify.getDebug():
            dgram = di.getDatagram()
            dgram.dumpHex(ostream)
        now = time.time()
        accountDetailRecord = AccountDetailRecord()
        self.cr.accountDetailRecord = accountDetailRecord
        returnCode = di.getUint8()
        accountCode = di.getUint32()
        errorString = self.getExtendedErrorMsg(di.getString())
        sec = di.getUint32()
        usec = di.getUint32()
        serverTime = sec + usec / 1000000.0
        serverDelta = serverTime - now
        self.cr.serverTimeUponLogin = serverTime
        self.cr.clientTimeUponLogin = now
        self.cr.globalClockRealTimeUponLogin = globalClock.getRealTime()
        if hasattr(self.cr, 'toontownTimeManager'):
            self.cr.toontownTimeManager.updateLoginTimes(serverTime, now, self.cr.globalClockRealTimeUponLogin)
        self.cr.setServerDelta(serverDelta)
        self.notify.setServerDelta(serverDelta, 28800)
        if di.getRemainingSize() > 0:
            self.cr.accountDays = self.parseAccountDays(di.getInt32())
        else:
            self.cr.accountDays = 100000
        if di.getRemainingSize() > 0:
            WhiteListResponse = di.getString()
        else:
            WhiteListResponse = 'NO'
        if WhiteListResponse == 'YES':
            self.cr.whiteListChatEnabled = 1
        else:
            self.cr.whiteListChatEnabled = 0
        self.lastLoggedInStr = base.config.GetString('last-logged-in', '')
        self.cr.lastLoggedIn = datetime.now()
        if hasattr(self.cr, 'toontownTimeManager'):
            self.cr.lastLoggedIn = self.cr.toontownTimeManager.convertStrToToontownTime(self.lastLoggedInStr)
        self.cr.withParentAccount = base.config.GetBool('dev-with-parent-account', 0)
        self.notify.info('Login response return code %s' % returnCode)
        if returnCode == 0:
            self.__handleLoginSuccess()
        elif returnCode == 12:
            self.notify.info('Bad password')
            self.fsm.request('showLoginFailDialog', [
             OTPLocalizer.LoginScreenBadPassword])
        elif returnCode == 14:
            self.notify.info('Bad word in user name')
            self.fsm.request('showLoginFailDialog', [
             OTPLocalizer.LoginScreenInvalidUserName])
        elif returnCode == 129:
            self.notify.info('Username not found')
            self.fsm.request('showLoginFailDialog', [
             OTPLocalizer.LoginScreenUserNameNotFound])
        else:
            self.notify.info('Login failed: %s' % errorString)
            messenger.send(self.doneEvent, [{'mode': 'reject'}])

    def __handleLoginSuccess(self):
        self.cr.logAccountInfo()
        launcher.setGoUserName(self.userName)
        launcher.setLastLogin(self.userName)
        launcher.setUserLoggedIn()
        if self.loginInterface.freeTimeExpires == -1:
            launcher.setPaidUserLoggedIn()
        if self.loginInterface.needToSetParentPassword():
            messenger.send(self.doneEvent, [{'mode': 'getChatPassword'}])
        else:
            messenger.send(self.doneEvent, [{'mode': 'success'}])

    def __handleEnterLoginAck(self):
        self.dialog.hide()
        self.fsm.request('login')

    def __handleNoNewAccountsAck(self):
        self.dialog.hide()
        self.fsm.request('login')

    def parseAccountDays(self, accountDays):
        result = 100000
        if accountDays >= 0:
            result = accountDays
        else:
            self.notify.warning('account days is negative %s' % accountDays)
        self.notify.debug('result=%s' % result)
        return result

    def handleLoginToontownResponse(self, di):
        self.notify.debug('handleLoginToontownResponse')
        dgram = di.getDatagram()
        dgram.dumpHex(ostream)
        now = time.time()
        returnCode = di.getUint8()
        respString = di.getString()
        errorString = self.getExtendedErrorMsg(respString)
        self.accountNumber = di.getUint32()
        self.cr.DISLIdFromLogin = self.accountNumber
        self.accountName = di.getString()
        self.accountNameApproved = di.getUint8()
        accountDetailRecord = AccountDetailRecord()
        self.cr.accountDetailRecord = accountDetailRecord
        self.openChatEnabled = di.getString() == 'YES'
        createFriendsWithChat = di.getString()
        canChat = createFriendsWithChat == 'YES' or createFriendsWithChat == 'CODE'
        self.cr.secretChatAllowed = canChat
        self.notify.info('CREATE_FRIENDS_WITH_CHAT from game server login: %s %s' % (createFriendsWithChat, canChat))
        self.chatCodeCreationRule = di.getString()
        self.cr.chatChatCodeCreationRule = self.chatCodeCreationRule
        self.notify.info('Chat code creation rule = %s' % self.chatCodeCreationRule)
        self.cr.secretChatNeedsParentPassword = self.chatCodeCreationRule == 'PARENT'
        sec = di.getUint32()
        usec = di.getUint32()
        serverTime = sec + usec / 1000000.0
        self.cr.serverTimeUponLogin = serverTime
        self.cr.clientTimeUponLogin = now
        self.cr.globalClockRealTimeUponLogin = globalClock.getRealTime()
        if hasattr(self.cr, 'toontownTimeManager'):
            self.cr.toontownTimeManager.updateLoginTimes(serverTime, now, self.cr.globalClockRealTimeUponLogin)
        serverDelta = serverTime - now
        self.cr.setServerDelta(serverDelta)
        self.notify.setServerDelta(serverDelta, 28800)
        access = di.getString()
        self.isPaid = access == 'FULL'
        self.cr.parentPasswordSet = self.isPaid
        self.cr.setIsPaid(self.isPaid)
        if self.isPaid:
            launcher.setPaidUserLoggedIn()
        self.notify.info('Paid from game server login: %s' % self.isPaid)
        WhiteListResponse = di.getString()
        if WhiteListResponse == 'YES':
            self.cr.whiteListChatEnabled = 1
        else:
            self.cr.whiteListChatEnabled = 0
        self.lastLoggedInStr = di.getString()
        self.cr.lastLoggedIn = datetime.now()
        if hasattr(self.cr, 'toontownTimeManager'):
            self.cr.lastLoggedIn = self.cr.toontownTimeManager.convertStrToToontownTime(self.lastLoggedInStr)
        if di.getRemainingSize() > 0:
            self.cr.accountDays = self.parseAccountDays(di.getInt32())
        else:
            self.cr.accountDays = 100000
        self.toonAccountType = di.getString()
        if self.toonAccountType == 'WITH_PARENT_ACCOUNT':
            self.cr.withParentAccount = True
        else:
            if self.toonAccountType == 'NO_PARENT_ACCOUNT':
                self.cr.withParentAccount = False
            else:
                self.notify.error('unknown toon account type %s' % self.toonAccountType)
            self.notify.info('toonAccountType=%s' % self.toonAccountType)
            self.userName = di.getString()
            self.cr.userName = self.userName
            self.notify.info('Login response return code %s' % returnCode)
            if returnCode == 0:
                self.__handleLoginSuccess()
            else:
                if returnCode == -13:
                    self.notify.info('Period Time Expired')
                    self.fsm.request('showLoginFailDialog', [
                     OTPLocalizer.LoginScreenPeriodTimeExpired])
                self.notify.info('Login failed: %s' % errorString)
                messenger.send(self.doneEvent, [{'mode': 'reject'}])