from panda3d.core import *
from direct.interval.IntervalGlobal import *
from direct.task.TaskManagerGlobal import *
from direct.distributed.ClockDelta import *
from direct.directnotify import DirectNotifyGlobal
import GoonGlobals
from direct.task.Task import Task
from toontown.toonbase import ToontownGlobals
from otp.otpbase import OTPGlobals
from toontown.coghq import DistributedCashbotBossObject
from direct.showbase import PythonUtil
import DistributedGoon

class DistributedCashbotBossGoon(DistributedGoon.DistributedGoon, DistributedCashbotBossObject.DistributedCashbotBossObject):
    notify = DirectNotifyGlobal.directNotify.newCategory('DistributedCashbotBossGoon')
    walkGrabZ = -3.6
    stunGrabZ = -2.2
    wiggleFreeTime = 2
    craneFrictionCoef = 0.15
    craneSlideSpeed = 10
    craneRotateSpeed = 20

    def __init__(self, cr):
        DistributedCashbotBossObject.DistributedCashbotBossObject.__init__(self, cr)
        DistributedGoon.DistributedGoon.__init__(self, cr)
        self.target = None
        self.arrivalTime = None
        self.flyToMagnetSfx = loader.loadSfx('phase_5/audio/sfx/TL_rake_throw_only.ogg')
        self.hitMagnetSfx = loader.loadSfx('phase_4/audio/sfx/AA_drop_anvil_miss.ogg')
        self.toMagnetSoundInterval = Sequence(SoundInterval(self.flyToMagnetSfx, duration=ToontownGlobals.CashbotBossToMagnetTime, node=self), SoundInterval(self.hitMagnetSfx, node=self))
        self.hitFloorSfx = loader.loadSfx('phase_5/audio/sfx/AA_drop_flowerpot.ogg')
        self.hitFloorSoundInterval = SoundInterval(self.hitFloorSfx, duration=1.0, node=self)
        self.wiggleSfx = loader.loadSfx('phase_5/audio/sfx/SA_finger_wag.ogg')
        return

    def generate(self):
        DistributedCashbotBossObject.DistributedCashbotBossObject.generate(self)
        DistributedGoon.DistributedGoon.generate(self)

    def announceGenerate(self):
        DistributedCashbotBossObject.DistributedCashbotBossObject.announceGenerate(self)
        self.setupPhysics('goon')
        DistributedGoon.DistributedGoon.announceGenerate(self)
        self.name = 'goon-%s' % self.doId
        self.setName(self.name)
        self.setTag('doId', str(self.doId))
        self.collisionNode.setName('goon')
        cs = CollisionSphere(0, 0, 4, 4)
        self.collisionNode.addSolid(cs)
        self.collisionNode.setIntoCollideMask(ToontownGlobals.PieBitmask | ToontownGlobals.CashbotBossObjectBitmask)
        self.wiggleTaskName = self.uniqueName('wiggleTask')
        self.wiggleFreeName = self.uniqueName('wiggleFree')
        self.boss.goons.append(self)
        self.reparentTo(render)

    def disable(self):
        i = self.boss.goons.index(self)
        del self.boss.goons[i]
        DistributedGoon.DistributedGoon.disable(self)
        DistributedCashbotBossObject.DistributedCashbotBossObject.disable(self)

    def delete(self):
        DistributedGoon.DistributedGoon.delete(self)
        DistributedCashbotBossObject.DistributedCashbotBossObject.delete(self)

    def hideShadows(self):
        self.dropShadow.hide()

    def showShadows(self):
        self.dropShadow.show()

    def getMinImpact(self):
        return ToontownGlobals.CashbotBossGoonImpact

    def doHitBoss(self, impact):
        self.d_hitBoss(impact)
        self.b_destroyGoon()

    def __startWalk(self):
        self.__stopWalk()
        if self.target:
            now = globalClock.getFrameTime()
            availableTime = self.arrivalTime - now
            if availableTime > 0:
                origH = self.getH()
                h = PythonUtil.fitDestAngle2Src(origH, self.targetH)
                delta = abs(h - origH)
                turnTime = delta / (self.velocity * 5)
                dist = Vec3(self.target - self.getPos()).length()
                walkTime = dist / self.velocity
                denom = turnTime + walkTime
                if denom != 0:
                    timeCompress = availableTime / denom
                    self.walkTrack = Sequence(self.hprInterval(turnTime * timeCompress, VBase3(h, 0, 0)), self.posInterval(walkTime * timeCompress, self.target))
                    self.walkTrack.start()
            else:
                self.setPos(self.target)
                self.setH(self.targetH)

    def __stopWalk(self):
        if self.walkTrack:
            self.walkTrack.pause()
            self.walkTrack = None
        return

    def __wiggleTask(self, task):
        elapsed = globalClock.getFrameTime() - self.wiggleStart
        h = math.sin(elapsed * 17) * 5
        p = math.sin(elapsed * 29) * 10
        self.crane.wiggleMagnet.setHpr(h, p, 0)
        return Task.cont

    def __wiggleFree(self, task):
        self.crane.releaseObject()
        self.stashCollisions()
        return Task.done

    def fellOut(self):
        self.b_destroyGoon()

    def handleToonDetect(self, collEntry = None):
        if self.boss.localToonIsSafe:
            return
        DistributedGoon.DistributedGoon.handleToonDetect(self, collEntry)

    def prepareGrab(self):
        DistributedCashbotBossObject.DistributedCashbotBossObject.prepareGrab(self)
        if self.isStunned or self.boss.localToonIsSafe:
            self.pose('collapse', 48)
            self.grabPos = (0, 0, self.stunGrabZ * self.scale)
        else:
            self.setPlayRate(4, 'walk')
            self.loop('walk')
            self.grabPos = (0, 0, self.walkGrabZ * self.scale)
            self.wiggleStart = globalClock.getFrameTime()
            taskMgr.add(self.__wiggleTask, self.wiggleTaskName)
            base.sfxPlayer.playSfx(self.wiggleSfx, node=self)
            if self.avId == localAvatar.doId:
                taskMgr.doMethodLater(self.wiggleFreeTime, self.__wiggleFree, self.wiggleFreeName)
        self.radar.hide()

    def prepareRelease(self):
        DistributedCashbotBossObject.DistributedCashbotBossObject.prepareRelease(self)
        self.crane.wiggleMagnet.setHpr(0, 0, 0)
        taskMgr.remove(self.wiggleTaskName)
        taskMgr.remove(self.wiggleFreeName)
        self.setPlayRate(self.animMultiplier, 'walk')

    def setObjectState(self, state, avId, craneId):
        if state == 'W':
            self.demand('Walk')
        elif state == 'B':
            if self.state != 'Battle':
                self.demand('Battle')
        elif state == 'S':
            if self.state != 'Stunned':
                self.demand('Stunned')
        elif state == 'R':
            if self.state != 'Recovery':
                self.demand('Recovery')
        elif state == 'a':
            self.demand('EmergeA')
        elif state == 'b':
            self.demand('EmergeB')
        else:
            DistributedCashbotBossObject.DistributedCashbotBossObject.setObjectState(self, state, avId, craneId)

    def setTarget(self, x, y, h, arrivalTime):
        self.target = Point3(x, y, 0)
        self.targetH = h
        now = globalClock.getFrameTime()
        self.arrivalTime = globalClockDelta.networkToLocalTime(arrivalTime, now)
        if self.state == 'Walk':
            self.__startWalk()

    def d_destroyGoon(self):
        self.sendUpdate('destroyGoon')

    def b_destroyGoon(self):
        if not self.isDead:
            self.d_destroyGoon()
            self.destroyGoon()

    def destroyGoon(self):
        if not self.isDead:
            self.playCrushMovie(None, None)
        self.demand('Off')
        return

    def enterOff(self):
        DistributedGoon.DistributedGoon.enterOff(self)
        DistributedCashbotBossObject.DistributedCashbotBossObject.enterOff(self)

    def exitOff(self):
        DistributedCashbotBossObject.DistributedCashbotBossObject.exitOff(self)
        DistributedGoon.DistributedGoon.exitOff(self)

    def enterWalk(self, avId = None, ts = 0):
        self.startToonDetect()
        self.isStunned = 0
        self.__startWalk()
        self.loop('walk', 0)
        self.unstashCollisions()

    def exitWalk(self):
        self.__stopWalk()
        self.stopToonDetect()
        self.stop()

    def enterEmergeA(self):
        self.undead()
        self.reparentTo(render)
        self.stopToonDetect()
        self.boss.doorA.request('open')
        self.radar.hide()
        self.__startWalk()
        self.loop('walk', 0)

    def exitEmergeA(self):
        if self.boss.doorA:
            self.boss.doorA.request('close')
        self.radar.show()
        self.__stopWalk()

    def enterEmergeB(self):
        self.undead()
        self.reparentTo(render)
        self.stopToonDetect()
        self.boss.doorB.request('open')
        self.radar.hide()
        self.__startWalk()
        self.loop('walk', 0)

    def exitEmergeB(self):
        if self.boss.doorB:
            self.boss.doorB.request('close')
        self.radar.show()
        self.__stopWalk()

    def enterBattle(self, avId = None, ts = 0):
        DistributedGoon.DistributedGoon.enterBattle(self, avId, ts)
        avatar = base.cr.doId2do.get(avId)
        if avatar:
            messenger.send('exitCrane')
            avatar.stunToon()
        self.unstashCollisions()

    def enterStunned(self, ts = 0):
        DistributedGoon.DistributedGoon.enterStunned(self, ts)
        self.unstashCollisions()

    def enterRecovery(self, ts = 0, pauseTime = 0):
        DistributedGoon.DistributedGoon.enterRecovery(self, ts, pauseTime)
        self.unstashCollisions()
