from toontown.toonbase.ToonBaseGlobal import *
from otp.otpbase import OTPGlobals
from direct.interval.IntervalGlobal import *
import ArrowKeys
from direct.task.Task import Task

class TwoDDrive:
    notify = DirectNotifyGlobal.directNotify.newCategory('TwoDDrive')
    TASK_NAME = 'TwoDDriveTask'
    SET_ATREST_HEADING_TASK = 'setAtRestHeadingTask'

    def __init__(self, game, speed, maxFrameMove = None, customCollisionCallback = None, priority = 0, setHeading = 1, upHeading = 0):
        self.game = game
        self.speed = speed
        self.maxFrameMove = maxFrameMove
        self.customCollisionCallback = customCollisionCallback
        self.priority = priority
        self.setHeading = setHeading
        self.upHeading = upHeading
        self.arrowKeys = ArrowKeys.ArrowKeys()
        self.wasUpReleased = True
        self.lt = base.localAvatar
        base.localAvatar.useTwoDControls()
        base.localAvatar.controlManager.currentControls.avatarControlJumpForce = 30.0
        self.ONE_JUMP_PER_UP_PRESSED = True
        self.lastAction = None
        self.isMovingX = False
        return

    def destroy(self):
        self.game = None
        base.localAvatar.controlManager.currentControls.avatarControlJumpForce = 24.0
        base.localAvatar.useWalkControls()
        self.arrowKeys.destroy()
        del self.arrowKeys
        del self.customCollisionCallback
        self.lastAction = None
        return

    def start(self):
        self.notify.debug('start')
        self.__placeToonHOG(self.lt.getPos())
        base.localAvatar.enableAvatarControls()
        taskMgr.remove(TwoDDrive.TASK_NAME)
        taskMgr.add(self.__update, TwoDDrive.TASK_NAME, priority=self.priority)

    def __placeToonHOG(self, pos, h = None):
        if h == None:
            h = self.lt.getH()
        self.lt.setPos(pos)
        self.lt.setH(h)
        self.lastPos = pos
        self.atRestHeading = h
        self.oldAtRestHeading = h
        self.lastXVel = 0
        self.lastYVel = 0
        return

    def stop(self):
        self.notify.debug('stop')
        base.localAvatar.disableAvatarControls()
        taskMgr.remove(TwoDDrive.TASK_NAME)
        taskMgr.remove(TwoDDrive.SET_ATREST_HEADING_TASK)
        if hasattr(self, 'turnLocalToonIval'):
            if self.turnLocalToonIval.isPlaying():
                self.turnLocalToonIval.pause()
            del self.turnLocalToonIval
        base.localAvatar.setSpeed(0, 0)
        base.localAvatar.stopSound()

    def __update(self, task):
        vel = Vec3(0, 0, 0)
        xVel = 0
        yVel = 0
        if self.ONE_JUMP_PER_UP_PRESSED:
            if not self.arrowKeys.upPressed():
                self.wasUpReleased = True
            elif self.arrowKeys.upPressed() and self.wasUpReleased:
                self.wasUpReleased = False
                if not self.game.isHeadInFloor:
                    if localAvatar.controlManager.currentControls == localAvatar.controlManager.get('twoD'):
                        base.localAvatar.controlManager.currentControls.jumpPressed()
        elif self.arrowKeys.upPressed():
            if not self.game.isHeadInFloor:
                if localAvatar.controlManager.currentControls == localAvatar.controlManager.get('twoD'):
                    base.localAvatar.controlManager.currentControls.jumpPressed()
        if self.arrowKeys.leftPressed():
            xVel -= 1
        if self.arrowKeys.rightPressed():
            xVel += 1
        vel.setX(xVel)
        vel.setY(yVel)
        vel.normalize()
        vel *= self.speed
        if abs(xVel) > 0:
            if not self.isMovingX:
                self.isMovingX = True
                messenger.send('avatarMovingX')
        elif self.isMovingX:
            self.isMovingX = False
            messenger.send('avatarStoppedX')
        speed = vel.length()
        action = self.lt.setSpeed(speed, 0)
        if action != self.lastAction:
            self.lastAction = action
            if action == OTPGlobals.RUN_INDEX:
                base.localAvatar.runSound()
            else:
                base.localAvatar.stopSound()
        if self.setHeading:
            self.__handleHeading(xVel, yVel)
        toonPos = self.lt.getPos()
        dt = globalClock.getDt()
        posOffset = vel * dt
        if self.customCollisionCallback:
            toonPos = self.customCollisionCallback(toonPos, toonPos + posOffset)
        else:
            toonPos += posOffset
        self.lt.setPos(toonPos)
        self.lastPos = toonPos
        return Task.cont

    def __handleHeading(self, xVel, yVel):
        def getHeading(xVel, yVel):
            angTab = [[None, 0, 180], [-90, -45, -135], [90, 45, 135]]
            return angTab[xVel][yVel] + self.upHeading

        def orientToon(angle, self = self):
            startAngle = self.lt.getH()
            startAngle = fitSrcAngle2Dest(startAngle, angle)
            dur = 0.1 * abs(startAngle - angle) / 90
            self.turnLocalToonIval = LerpHprInterval(self.lt, dur, Point3(angle, 0, 0), startHpr=Point3(startAngle, 0, 0), name='TwoDDriveLerpHpr')
            self.turnLocalToonIval.start()
            if self.atRestHeading != self.oldAtRestHeading:
                self.oldAtRestHeading = self.atRestHeading
                messenger.send('avatarOrientationChanged', [self.atRestHeading])

        if xVel != self.lastXVel or yVel != self.lastYVel:
            taskMgr.remove(TwoDDrive.SET_ATREST_HEADING_TASK)
            if not (xVel or yVel):
                orientToon(self.atRestHeading)
            else:
                curHeading = getHeading(xVel, yVel)
                if ((self.lastXVel and self.lastYVel) and not (xVel and yVel)):
                    def setAtRestHeading(task, self = self, angle = curHeading):
                        self.atRestHeading = angle
                        return Task.done

                    taskMgr.doMethodLater(0.05, setAtRestHeading, TwoDDrive.SET_ATREST_HEADING_TASK)
                else:
                    self.atRestHeading = curHeading
                orientToon(curHeading)
        self.lastXVel = xVel
        self.lastYVel = yVel