###########################################################
# Lazy Camera - Railshooter Module
# Creates a Camera that follows the player's movements lazily
###########################################################

# DESCRIPTION:
# This Class defines the Lazy Camera System for the Game.  The Lazy 
# Camera is a Camera System that slowly catches up to the player after
# the player moves.  This emphasizes the player's movement more than a 
# Locked-Camera System.  This Class also contains a method to do 
# Camera-Rocking to add extra punch to collisions and impacts.


from direct.showbase.ShowBaseGlobal import *
from direct.interval.IntervalGlobal import *
from direct.showbase import DirectObject
from direct.task import Task
from pandac.PandaModules import *
import math

# Import Railshooter Modules
import Level1
import ClassGlobals


########################################
# Lazy Camera Class
########################################
class LazyCamera(DirectObject.DirectObject):
    def __init__(self, target):   

 	self.target = target
	self.cameraX = self.target.getX(Level1.railDummy)
	self.cameraY = self.target.getY(Level1.railDummy) - 20
	self.cameraZ = self.target.getZ(Level1.railDummy) + 4

	self.moveAcceleration = 3
	self.currentSpeed = 0
	self.reactionSpeed = 0.5

	self.deadZone = 0.1
	self.noMoveZone = 1.0

	self.isTrackingPlayer = 0
	self.isLazyCamOn = 1

	self.tick = 0
	self.currentTick = 0
	self.lastTick = 0

	self.cameraRock = 5
        self.cameraRockSpeed = 0.05

        
    ########################################
    # Define Methods
    ########################################

    # Activate LazyCamera
    def startLazyCam(self):

	# Reparent Camera to RailDummy
	camera.reparentTo(Level1.railDummy)

	# Position the Camera behind Target
	camera.setPos(self.target, self.cameraX, self.cameraY, self.cameraZ)
	camera.setHpr(0, 0, 0)

	# Add a Task to Update the Camera
	self.isLazyCamOn = 1
	taskMgr.add(self.updateLazyCam, 'UpdateLazyCamera')


    # Deactivate LazyCamera
    def removeLazyCam(self):

	# Reparent Camera to RailDummy
	camera.reparentTo(render)

	# Add a Task to Update the Camera
	self.isLazyCamOn = 0
	taskMgr.remove('UpdateLazyCamera')

	# Set Variables back to Starting Values
	self.tick = 0
	self.currentTick = 0
	self.lastTick = 0
	self.currentSpeed = 0


    # Toggle Lazy Camera
    def toggleLazyCam(self):
	
	# Toggle Tracking of Player
	if self.isLazyCamOn == 1:
	    taskMgr.remove('UpdateLazyCamera')

	    # Reparent Camera to World
	    camera.reparentTo(render)
	    self.isLazyCamOn = 0
	else:

	    # Reparent Camera to RailDummy
	    camera.reparentTo(Level1.railDummy)
	    camera.setPos(self.target, self.cameraX, self.cameraY, self.cameraZ)
	    camera.setHpr(0, 0, 0)
	    self.isLazyCamOn = 1
	    taskMgr.add(self.updateLazyCam, 'UpdateLazyCamera')

 
    # Toggle Player Tracking
    def togglePlayerTracking(self):
	
	# Toggle Tracking of Player
	if self.isTrackingPlayer == 1:
	    taskMgr.remove('playerTracker')
	    self.isTrackingPlayer = 0
	else:
	    taskMgr.add(self.trackPlayer, 'playerTracker')
	    self.isTrackingPlayer = 1


    # Rocks the Camera 
    def cameraShaker(self, speed, strength):
        self.cameraRock = strength
        self.cameraRockSpeed = speed

        cameraRock1 = camera.hprInterval(self.cameraRockSpeed, 
				Point3(self.cameraRock, self.cameraRock, 0), 
				startHpr=Point3(0, 0, 0), bakeInStart = 0,
				blendType='easeInOut')
        
        cameraRock2 = camera.hprInterval(self.cameraRockSpeed, 
				Point3(-self.cameraRock, -self.cameraRock, 0),
                                startHpr=Point3(self.cameraRock, self.cameraRock, 0), bakeInStart = 0,
				blendType = 'easeInOut')

        cameraRock3 = camera.hprInterval(self.cameraRockSpeed, 
				Point3(self.cameraRock, self.cameraRock, 0),
                                startHpr=Point3(-self.cameraRock, -self.cameraRock, 0), bakeInStart = 0,
                                blendType = 'easeInOut')
        
        cameraRock4 = camera.hprInterval(self.cameraRockSpeed, 
				Point3(0, 0, 0),
                                startHpr=Point3(self.cameraRock, self.cameraRock, 0), bakeInStart = 0,
                                blendType = 'easeInOut')

        cameraShake = Sequence(cameraRock1, cameraRock2, cameraRock3, cameraRock4, name='cameraShake')

        cameraShake.start()
        

    ########################################
    # Define Tasks
    ########################################

    # Slowly repositions the Camera to be behind the Target
    def updateLazyCam(self, task):

	# Calculate the Current Tick (Game Time)	
	# This makes the game controls independent of Framerate
	self.currentTick = math.floor(task.time / ClassGlobals.gameSpeed)
	timeAdjust = self.currentTick - self.lastTick

	# If it is a Tick, then Update the World
	if self.currentTick > self.tick:
	    self.tick = self.currentTick

	    # Get Target's Position
	    targetX = self.target.getX(Level1.railDummy)
	    targetY = self.target.getY(Level1.railDummy) -10
	    targetZ = self.target.getZ(Level1.railDummy) +4

	    # Get Camera's Position
	    self.cameraX = camera.getX(Level1.railDummy)
	    self.cameraY = camera.getY(Level1.railDummy)
	    self.cameraZ = camera.getZ(Level1.railDummy)

	    # Get Difference between Coordinates
	    changeX = targetX - self.cameraX
	    changeY = targetY - self.cameraY
	    changeZ = targetZ - self.cameraZ

 	    # Calculate Camera Movement
	    if (targetX > self.cameraX + self.deadZone) or (targetX < self.cameraX - self.deadZone):
	        self.cameraX = self.cameraX + (changeX / self.moveAcceleration)

	    # if (targetY > self.cameraY + self.deadZone) or (targetY < self.cameraY - self.deadZone):
	        # self.cameraY = self.cameraY + (changeY / self.moveAcceleration)

	    if (targetZ > self.cameraZ + self.deadZone) or (targetZ < self.cameraZ - self.deadZone):
	        self.cameraZ = self.cameraZ + (changeZ / self.moveAcceleration)

	    # Update Camera Postion
	    camera.setPos(Level1.railDummy, self.cameraX, self.cameraY, self.cameraZ)
	
	    # Update the Older Tick
	    self.lastTick = self.currentTick

	return Task.cont


    # Make Camera Always Look at Player
    def trackPlayer(self, task):
	
	# Do only if Player Exists
        if ClassGlobals.p1.craft.isEmpty != 1:
	
	    # LookAtPlayer
	    if ClassGlobals.p1.isAlive == 1:
	        camera.lookAt(ClassGlobals.p1.cameraTarget)
	    else:
	        camera.lookAt(ClassGlobals.p1.deathCamTarget)
	    return Task.cont
	
	# Else, stop
	else:
	    return Task.done