from panda3d.core import *
from direct.interval.IntervalGlobal import *
from StomperGlobals import *
from direct.distributed import ClockDelta
from direct.showbase.PythonUtil import lerp
import math
from otp.level import DistributedEntity
from direct.directnotify import DirectNotifyGlobal
from pandac.PandaModules import NodePath
from otp.level import BasicEntities
from direct.task import Task
from toontown.toonbase import ToontownGlobals
from toontown.coghq import BattleBlocker
import random
from math import *

def circleX(angle, radius, centerX, centerY):
    x = radius * cos(angle) + centerX
    return x


def circleY(angle, radius, centerX, centerY):
    y = radius * sin(angle) + centerY
    return y


def getCirclePoints(segCount, centerX, centerY, radius, wideX = 1.0, wideY = 1.0):
    returnShape = []
    for seg in xrange(0, int(segCount)):
        coordX = wideX * circleX(pi * 2.0 * float(float(seg) / float(segCount)), radius, centerX, centerY)
        coordY = wideY * circleY(pi * 2.0 * float(float(seg) / float(segCount)), radius, centerX, centerY)
        returnShape.append((coordX, coordY, 1))

    coordX = wideX * circleX(pi * 2.0 * float(0 / segCount), radius, centerX, centerY)
    coordY = wideY * circleY(pi * 2.0 * float(0 / segCount), radius, centerX, centerY)
    returnShape.append((coordX, coordY, 1))
    return returnShape


class DistributedSecurityCamera(BasicEntities.DistributedNodePathEntity):
    notify = DirectNotifyGlobal.directNotify.newCategory('DistributedSecurityCamera')
    laserFieldModels = ['phase_9/models/cogHQ/square_stomper']

    def __init__(self, cr):
        BasicEntities.DistributedNodePathEntity.__init__(self, cr)
        node = hidden.attachNewNode('DistributedNodePathEntity')
        self.trackBeamGN = None
        self.trackFloorGN = None
        self.trackX = 10.0
        self.trackY = -5.0
        self.radius = 5.0
        self.trackShape = []
        self.trackShape = getCirclePoints(7, 0.0, 0.0, self.radius)
        self.trackShapeFloor = []
        self.trackShapeFloor = getCirclePoints(16, 0.0, 0.0, self.radius)
        self.zFloat = 0.05
        self.projector = Point3(0, 0, 25)
        self.isToonIn = 0
        self.toonX = 0
        self.toonY = 0
        self.canDamage = 1
        self.accel = 0.5
        self.maxVel = 1.0
        self.vX = 0.0
        self.vY = 0.0
        self.targetX = self.trackX
        self.targetY = self.trackY
        self.target = 0
        self.trackTargetList = [None,
         None,
         None,
         None]
        self.lastTime = 0.0
        self.currentTime = 0.0
        self.delta = 0.0
        self.Norm = {}
        self.Norm['Red'] = 0.2
        self.Norm['Green'] = 0.2
        self.Norm['Blue'] = 0.2
        self.Norm['Alpha'] = 1.0
        self.Alert = {}
        self.Alert['Red'] = 1.0
        self.Alert['Green'] = 0.0
        self.Alert['Blue'] = 0.0
        self.Alert['Alpha'] = 1.0
        self.attackSound = loader.loadSfx('phase_9/audio/sfx/CHQ_GOON_tractor_beam_alarmed.ogg')
        self.onSound = loader.loadSfx('phase_11/audio/sfx/LB_camera_shutter_2.ogg')
        self.attackTrack = Parallel(SoundInterval(self.attackSound, node=self, volume=0.8), SoundInterval(self.onSound, node=self, volume=0.8))
        self.moveStartSound = loader.loadSfx('phase_11/audio/sfx/LB_laser_beam_on_2.ogg')
        self.moveStartTrack = Parallel(SoundInterval(self.moveStartSound, node=self, volume=0.4))
        self.moveLoopSound = loader.loadSfx('phase_11/audio/sfx/LB_laser_beam_hum_2.ogg')
        self.moveLoopSound.setLoop()
        self.moveLoopTrack = Parallel(SoundInterval(self.moveLoopSound, node=self, volume=0.4))
        self.moveStopSound = loader.loadSfx('phase_11/audio/sfx/LB_laser_beam_off_2.ogg')
        self.moveStopTrack = Parallel(SoundInterval(self.moveStopSound, node=self, volume=0.4))
        self.taskName = None
        return

    def generateInit(self):
        self.notify.debug('generateInit')
        BasicEntities.DistributedNodePathEntity.generateInit(self)

    def generate(self):
        self.notify.debug('generate')
        BasicEntities.DistributedNodePathEntity.generate(self)

    def announceGenerate(self):
        self.notify.debug('announceGenerate')
        BasicEntities.DistributedNodePathEntity.announceGenerate(self)
        self.trackBeamNode = self.attachNewNode('tracking Beam Node')
        self.trackBeamGN = GeomNode('tracking Beam')
        self.trackBeamNode.attachNewNode(self.trackBeamGN)
        self.trackBeamNode.setTransparency(TransparencyAttrib.MAlpha)
        self.trackBeamNode.setAttrib(ColorBlendAttrib.make(ColorBlendAttrib.MAdd))
        self.trackBeamNode.setTwoSided(False)
        self.trackBeamNode.setDepthWrite(False)
        self.trackFloorNode = self.attachNewNode('tracking floor Node')
        self.trackFloorGN = GeomNode('tracking Floor')
        self.trackFloorNode.attachNewNode(self.trackFloorGN)
        self.trackFloorNode.setTransparency(TransparencyAttrib.MAlpha)
        self.trackFloorNode.setAttrib(ColorBlendAttrib.make(ColorBlendAttrib.MAdd))
        self.trackFloorNode.setTwoSided(False)
        self.trackFloorNode.setDepthWrite(False)
        if not hasattr(self, 'trackTarget1'):
            self.trackTarget1 = None
        else:
            self.trackTargetList[1] = self.trackTarget1
        if not hasattr(self, 'trackTarget2'):
            self.trackTarget2 = None
        else:
            self.trackTargetList[2] = self.trackTarget2
        if not hasattr(self, 'trackTarget3'):
            self.trackTarget3 = None
        else:
            self.trackTargetList[3] = self.trackTarget3
        self.loadModel()
        self.detectName = 'securityCamera %s' % self.doId
        return

    def initCollisionGeom(self):
        pass

    def sendFail(self):
        self.battleStart()
        self.sendUpdate('trapFire', [])

    def battleStart(self):
        pass

    def setTarget(self, targetHash):
        targetCount = targetHash % 3
        sanity = 10
        self.target = None
        while targetCount >= 0 and sanity > 0:
            sanity -= 1
            for index in xrange(1, 4):
                if self.trackTargetList[index]:
                    if targetCount == 0:
                        self.target = self.trackTargetList[index]
                    targetCount -= 1

        return

    def setTrackTarget1(self, targetId):
        self.trackTarget1 = targetId
        self.trackTargetList[1] = targetId

    def setTrackTarget2(self, targetId):
        self.trackTarget2 = targetId
        self.trackTargetList[2] = targetId

    def setTrackTarget3(self, targetId):
        self.trackTarget3 = targetId
        self.trackTargetList[3] = targetId

    def __detect(self, task):
        distance = self.getDistance(localAvatar)
        greaterDim = self.gridScaleX
        if self.gridScaleY > self.gridScaleX:
            greaterDim = self.gridScaleY
        if distance < greaterDim * 1.6:
            if localAvatar.getPos(self)[0] > 0 and localAvatar.getPos(self)[0] < self.gridScaleX and localAvatar.getPos(self)[1] > 0 and localAvatar.getPos(self)[1] < self.gridScaleY:
                self.__toonHit()
            else:
                if self.isToonIn:
                    self.isToonIn = 0
                self.isToonIn = 0
        taskMgr.doMethodLater(0.1, self.__detect, self.detectName)
        return Task.done

    def __toonHit(self):
        posX = localAvatar.getPos(self)[0]
        posY = localAvatar.getPos(self)[1]
        tileX = int(posX / (self.gridScaleX / self.gridNumX))
        tileY = int(posY / (self.gridScaleY / self.gridNumY))
        if self.toonX != tileX or self.toonY != tileY or not self.isToonIn:
            self.toonX = tileX
            self.toonY = tileY
            self.isToonIn = 1
            if self.gridData[tileX][tileY] < len(self.gridSymbols):
                tileFunction = self.gridSymbols[self.gridData[tileX][tileY]][0]
                if tileFunction:
                    tileFunction()
            self.sendHit()
        self.isToonIn = 1

    def sendHit(self):
        self.sendUpdate('hit', [self.toonX, self.toonY])

    def disable(self):
        self.notify.debug('disable')
        if self.moveLoopTrack.isPlaying():
            self.moveLoopTrack.finish()
        if self.attackTrack.isPlaying():
            self.attackTrack.finish()
        if self.moveStartTrack.isPlaying():
            self.moveStartTrack.finish()
        if self.moveStopTrack.isPlaying():
            self.moveStopTrack.finish()
        self.ignoreAll()
        taskMgr.remove(self.detectName)
        BasicEntities.DistributedNodePathEntity.disable(self)

    def delete(self):
        self.notify.debug('delete')
        self.unloadModel()
        if self.taskName:
            taskMgr.remove(self.taskName)
        BasicEntities.DistributedNodePathEntity.delete(self)

    def loadModel(self):
        self.rotateNode = self.attachNewNode('rotate')
        self.model = loader.loadModel(self.laserFieldModels[self.modelPath])
        self.model.reparentTo(self.rotateNode)
        self.model.setPos(0, 1, 0)
        self.taskName = 'securityCameraupdate %s' % self.doId
        taskMgr.add(self.__updateTrack, self.taskName, priority=25)

    def unloadModel(self):
        if self.model:
            self.model.removeNode()
            del self.model
            self.model = None
        return

    def __updateTrack(self, task):
        if self.target and self.level and hasattr(self.level, 'entities'):
            thing = self.level.entities.get(self.target, None)
            self.targetX = thing.getPos(self)[0]
            self.targetY = thing.getPos(self)[1]
        else:
            return Task.cont
        self.rotateNode.setPos(self.projector)
        self.rotateNode.lookAt(Point3(self.trackX, self.trackY, 0.0))
        dt = globalClock.getDt()
        deccel = 1.0 - 1.0 * (dt * 7.0)
        if deccel < 0:
            deccel = 0.0
        dirX = 0.0
        dirY = 0.0
        distX = self.targetX - self.trackX
        distY = self.targetY - self.trackY
        trigDist = math.sqrt(distX * distX + distY * distY)
        totalDist = abs(distX) + abs(distY)
        propX = abs(distX) / (totalDist + 0.01)
        propY = abs(distY) / (totalDist + 0.01)
        if self.targetX != self.trackX:
            dirX = distX / abs(distX)
        if self.targetY != self.trackY:
            dirY = distY / abs(distY)
        if trigDist < self.radius * 0.5 + 1.0:
            self.vX = self.vX * deccel
            self.vY = self.vY * deccel
            self.moveStopTrack.start()
            self.moveLoopTrack.finish()
        else:
            if not self.moveLoopTrack.isPlaying():
                self.moveLoopTrack.start()
                self.moveStartTrack.start()
            self.vX += dirX * self.accel * propX
            self.vY += dirY * self.accel * propY
        if self.vX > self.maxVel:
            self.vX = self.maxVel
        if self.vX < -self.maxVel:
            self.vX = -self.maxVel
        if self.vY > self.maxVel:
            self.vY = self.maxVel
        if self.vY < -self.maxVel:
            self.vY = -self.maxVel
        self.trackX += self.vX * dt
        self.trackY += self.vY * dt
        self.genTrack()
        dist = self.getDist(base.localAvatar)
        if dist < self.radius and self.canDamage:
            self.canDamage = 0
            self.sendUpdate('trapFire', [])
            taskMgr.doMethodLater(2.0, self._resetDam, 'reset Damage')
            self.attackTrack.start()
        return Task.cont

    def _resetDam(self, task = None):
        self.canDamage = 1

    def getDist(self, thing):
        posTX = thing.getX()
        posTY = thing.getY()
        dx = thing.getPos(self)[0] - self.trackX
        dy = thing.getPos(self)[1] - self.trackY
        return sqrt(dx * dx + dy * dy)

    def genTrack(self):
        dist = self.getDist(base.localAvatar)
        draw = 1.0 / (0.01 + float(pow(dist, 0.4)))
        self.trackShape = []
        wideX = 1
        wideY = 1
        self.trackShape = getCirclePoints(5 + draw * 12.0, 0.0, 0.0, self.radius, wideX, wideY)
        self.trackShapeFloor = []
        self.trackShapeFloor = getCirclePoints(5 + draw * 50.0, 0.0, 0.0, self.radius, wideX, wideY)
        if self.trackBeamGN:
            self.trackBeamGN.removeAllGeoms()
        if self.trackFloorGN:
            self.trackFloorGN.removeAllGeoms()
        beamRed = 0.0
        beamGreen = 0.0
        beamBlue = 0.0
        beamAlpha = 1.0
        origin = {}
        origin['Red'] = 0.2
        origin['Green'] = 0.2
        origin['Blue'] = 0.2
        origin['Alpha'] = 1.0
        if self.canDamage:
            origin = self.Norm
        else:
            origin = self.Alert
        self.gFormat = GeomVertexFormat.getV3cp()
        self.trackBeamVertexData = GeomVertexData('holds my vertices', self.gFormat, Geom.UHDynamic)
        self.trackBeamVertexWriter = GeomVertexWriter(self.trackBeamVertexData, 'vertex')
        self.trackBeamColorWriter = GeomVertexWriter(self.trackBeamVertexData, 'color')
        self.trackFloorVertexData = GeomVertexData('holds my vertices', self.gFormat, Geom.UHDynamic)
        self.trackFloorVertexWriter = GeomVertexWriter(self.trackFloorVertexData, 'vertex')
        self.trackFloorColorWriter = GeomVertexWriter(self.trackFloorVertexData, 'color')
        self.trackBeamVertexWriter.addData3f(self.projector[0], self.projector[1], self.projector[2])
        self.trackBeamColorWriter.addData4f(origin['Red'], origin['Green'], origin['Blue'], origin['Alpha'])
        self.trackFloorVertexWriter.addData3f(self.trackX, self.trackY, self.zFloat)
        self.trackFloorColorWriter.addData4f(origin['Red'], origin['Green'], origin['Blue'], origin['Alpha'])
        for vertex in self.trackShape:
            self.trackBeamVertexWriter.addData3f(self.trackX + vertex[0], self.trackY + vertex[1], self.zFloat)
            self.trackBeamColorWriter.addData4f(beamRed, beamGreen, beamBlue, beamAlpha)

        for vertex in self.trackShapeFloor:
            self.trackFloorVertexWriter.addData3f(self.trackX + vertex[0], self.trackY + vertex[1], self.zFloat)
            self.trackFloorColorWriter.addData4f(origin['Red'], origin['Green'], origin['Blue'], origin['Alpha'])

        self.trackBeamTris = GeomTrifans(Geom.UHStatic)
        self.trackFloorTris = GeomTrifans(Geom.UHStatic)
        sizeTrack = len(self.trackShape)
        self.trackBeamTris.addVertex(0)
        for countVertex in xrange(1, sizeTrack + 1):
            self.trackBeamTris.addVertex(countVertex)

        self.trackBeamTris.addVertex(1)
        self.trackBeamTris.closePrimitive()
        self.trackBeamGeom = Geom(self.trackBeamVertexData)
        self.trackBeamGeom.addPrimitive(self.trackBeamTris)
        self.trackBeamGN.addGeom(self.trackBeamGeom)
        sizeTrack = len(self.trackShapeFloor)
        self.trackFloorTris.addVertex(0)
        for countVertex in xrange(1, sizeTrack + 1):
            self.trackFloorTris.addVertex(countVertex)

        self.trackFloorTris.addVertex(1)
        self.trackFloorTris.closePrimitive()
        self.trackFloorGeom = Geom(self.trackFloorVertexData)
        self.trackFloorGeom.addPrimitive(self.trackFloorTris)
        self.trackFloorGN.addGeom(self.trackFloorGeom)

    def setProjector(self, projPoint):
        self.projector = projPoint
        if self.trackBeamGN and self.trackFloorGN:
            self.genTrack()

    def setHideModel(self, flag):
        if flag:
            self.model.stash()
        else:
            self.model.unstash()
