import BigWorld
import Avatar
from xfw import *
from gui.Scaleform.daapi.view.battle.shared.minimap.component import MinimapPluginsCollection
from gui.Scaleform.genConsts.BATTLE_VIEW_ALIASES import BATTLE_VIEW_ALIASES
from gui.shared import g_eventBus, events, EVENT_BUS_SCOPE
from gui.Scaleform.daapi.view.battle.shared.minimap import common
from gui.Scaleform.daapi.view.battle.shared.minimap import settings
from gui.battle_control import minimap_utils

from constants import ARENA_PERIOD
from helpers import dependency
from skeletons.gui.battle_session import IBattleSessionProvider
from gui.battle_control.arena_info import vos_collections
from projectile_trajectory import *
from gun_rotation_shared import decodeGunAngles, isShootPositionInsideOtherVehicle
from items.vehicles import VEHICLE_CLASS_TAGS
import ProjectileMover
import Math
import weakref
import sys
from tutorial.control.battle.functional import _IMarker
from tutorial.control.battle.functional import _StaticObjectMarker3D
from gui.Scaleform.daapi.view.battle.shared.minimap.component import MinimapComponent

try:
	class AimPosition():
		def __init__(self):
			self.oldtargetid=0
			g_eventBus.addListener(events.ComponentEvent.COMPONENT_REGISTERED, self.__onComponentRegistered, scope=EVENT_BUS_SCOPE.GLOBAL)
			g_eventBus.addListener(events.ComponentEvent.COMPONENT_UNREGISTERED, self.__onComponentUnregistered, scope=EVENT_BUS_SCOPE.GLOBAL)
			self.__minimap = None
			self.markerList={}
			self.marker3d={}
			
		def fini(self):
			self.__minimap = None
			g_eventBus.removeListener(_Event.COMPONENT_REGISTERED, self.__onComponentRegistered, scope=EVENT_BUS_SCOPE.GLOBAL)
			g_eventBus.removeListener(_Event.COMPONENT_UNREGISTERED, self.__onComponentUnregistered, scope=EVENT_BUS_SCOPE.GLOBAL)
			return
			
		def __onComponentRegistered(self, event):
			alias = event.alias
			if alias == BATTLE_VIEW_ALIASES.MINIMAP:
				plugin = event.componentPy.getPlugin('aiming')
				if plugin is not None:
					self.__minimap = plugin
			return
			
		def __onComponentUnregistered(self, event):
			alias = event.alias
			if alias == BATTLE_VIEW_ALIASES.MINIMAP and self.__minimap is not None:
				self.__minimap.stop()
				self.__minimap = None
			return
				
		def refreshList(self):
			try:
				if self.__minimap is None:
					return
				sessionProvider = dependency.instance(IBattleSessionProvider)
				if sessionProvider is None or sessionProvider.getArenaDP() is None:
					return
				if sessionProvider._BattleSessionProvider__arenaVisitor.getArenaPeriod()!=ARENA_PERIOD.BATTLE:
					return
				allyIdList=vos_collections.AllyItemsCollection(vos_collections.VehicleInfoSortKey).ids(sessionProvider.getArenaDP())
				aimDict={}
				for vid in allyIdList:
					player=BigWorld.player()
					if vid==player.playerVehicleID:
						continue
					veh = player.arena.vehicles.get(vid)
					vehicleType=veh['vehicleType']
					tags = set(vehicleType.type.tags & VEHICLE_CLASS_TAGS)
					if tags and tags.pop()=='SPG' and veh['isAlive']:
						ent=BigWorld.entity(vid)
						if ent is not None:
							descr = ent.typeDescriptor
							turretYaw, gunPitch = decodeGunAngles(ent.gunAnglesPacked, descr.gun['pitchLimits']['absolute'])
							collideWithSpaceBB = player.arena.collideWithSpaceBB
							(position, vector) = getShotPosition(turretYaw, gunPitch, descr, ent.matrix)
							(endPos, dir, maxDistCheckFlag) = getGunMarkerPosition(position, vector, descr.shot, vid, collideWithSpaceBB)
							if not maxDistCheckFlag:
								aimDict[vid]=endPos
				for vid in aimDict:
					newpos = aimDict[vid]
					newmatrix = Math.Matrix()
					newmatrix.setTranslate(newpos)
					if vid in self.markerList:
						try:
							self.__minimap._setMatrix(self.markerList[vid].eid, newmatrix)
							self.marker3d[vid]._StaticObjectMarker3D__model.position = Math.Vector3(newpos[:]) + (0,1,0)
						except Exception, e2:
							del self.markerList[vid]
							del self.marker3d[vid]
							self.markerList[vid]=MinimapMarker(vid, self.__minimap, newpos)
							self.marker3d[vid]=_StaticObjectMarker3D({'action': '','path': 'content/Interface/CheckPoint/CheckPoint_white.model','offset': (0,1,0)}, newpos)
					else:
						self.markerList[vid]=MinimapMarker(vid, self.__minimap, newpos)
						self.marker3d[vid]=_StaticObjectMarker3D({'action': '','path': 'content/Interface/CheckPoint/CheckPoint_white.model','offset': (0,1,0)}, newpos)
				dellist=[]
				for vid in self.markerList:
					if vid not in aimDict and self.markerList[vid] is not None:
						self.markerList[vid].clear()
						self.marker3d[vid].clear()
						dellist.append(vid)
				for vid in dellist:
					del self.markerList[vid]
					del self.marker3d[vid]
			except Exception, e:
				s=sys.exc_info()
				err(str(s[2].tb_lineno)+' aimpos|'+ str(e.message))
						
	posManager=AimPosition()		

	@registerEvent(MinimapPluginsCollection,'addPlugins')
	def addPlugins(self, plugins):
		if 'aiming' not in self._PluginsCollection__plugins:
			pluginObj = AimTargetPlugin(self._parentObj)
			self._PluginsCollection__plugins['aiming'] = pluginObj
			
	class AimTargetPlugin(common.EntriesPlugin):

		def addTarget(self, markerID, position):
			matrix = minimap_utils.makePositionMatrix(position)
			model = self._addEntryEx(markerID, settings.ENTRY_SYMBOL_NAME.DEAD_POINT, settings.CONTAINER_NAME.PERSONAL, matrix = matrix, active=True)
			return model

		def delTarget(self, markerID):
			return self._delEntryEx(markerID)
					
					
					
	def getShotPosition(turretYaw, gunPitch, descr, matrix):
		turretOffs = descr.hull['turretPositions'][0] + descr.chassis['hullPosition']
		gunOffs = descr.turret['gunPosition']
		shotSpeed = descr.shot['speed']
		turretWorldMatrix = Math.Matrix()
		turretWorldMatrix.setRotateY(turretYaw)
		turretWorldMatrix.translation = turretOffs
		turretWorldMatrix.postMultiply(matrix)
		position = turretWorldMatrix.applyPoint(gunOffs)
		gunWorldMatrix = Math.Matrix()
		gunWorldMatrix.setRotateX(gunPitch)
		gunWorldMatrix.postMultiply(turretWorldMatrix)
		vector = gunWorldMatrix.applyVector(Math.Vector3(0, 0, shotSpeed))
		return (position, vector)
		
	def getGunMarkerPosition(shotPos, shotVec, shotDescr, vid, collideWithSpaceBB):
		#shotDescr = self.__avatar.vehicleTypeDescriptor.shot
		gravity = Math.Vector3(0.0, -shotDescr['gravity'], 0.0)
		maxDist = shotDescr['maxDistance']
		testStartPoint = shotPos
		testEndPoint = shotPos + shotVec * 10000.0
		testEntities = ProjectileMover.getCollidableEntities((vid,), testStartPoint, testEndPoint)
		#collideVehiclesAndStaticScene = ProjectileMover.collideVehiclesAndStaticScene
		#collideWithSpaceBB = self.__avatar.arena.collideWithSpaceBB
		prevPos = shotPos
		prevVelocity = shotVec
		dt = 0.0
		maxDistCheckFlag = False
		while True:
			dt += 0.1
			checkPoints = computeProjectileTrajectory(prevPos, prevVelocity, gravity, 0.1, 0.03)
			prevCheckPoint = prevPos
			bBreak = False
			for curCheckPoint in checkPoints:
				testRes = collideVehiclesAndStaticScene(prevCheckPoint, curCheckPoint, testEntities)
				if testRes is not None:
					collData = testRes[1]
					if collData is not None and not collData.isVehicle():
						collData = None
					dir = testRes[0] - prevCheckPoint
					endPos = testRes[0]
					bBreak = True
					break
				pos = collideWithSpaceBB(prevCheckPoint, curCheckPoint)
				if pos is not None:
					collData = None
					maxDistCheckFlag = True
					dir = pos - prevCheckPoint
					endPos = pos
					bBreak = True
					break
				prevCheckPoint = curCheckPoint

			if bBreak:
				break
			prevPos = shotPos + shotVec.scale(dt) + gravity.scale(dt * dt * 0.5)
			prevVelocity = shotVec + gravity.scale(dt)

		dir.normalise()
		distance = (endPos - shotPos).length
		return (endPos, dir, maxDistCheckFlag)
		
	def collideVehiclesAndStaticScene(startPoint, endPoint, vehicles, collisionFlags = 128, skipGun = True):
		testResStatic = BigWorld.wg_collideSegment(BigWorld.player().spaceID, startPoint, endPoint, collisionFlags)
		testResDynamic = ProjectileMover.collideEntities(startPoint, endPoint if testResStatic is None else testResStatic[0], vehicles, skipGun)
		if testResStatic is None and testResDynamic is None:
			return
		else:
			distDynamic = 1000000.0
			if testResDynamic is not None:
				distDynamic = testResDynamic[0]
			distStatic = 1000000.0
			if testResStatic is not None:
				distStatic = (testResStatic[0] - startPoint).length
			if distDynamic < 1000000:
				dir = endPoint - startPoint
				dir.normalise()
				return (startPoint + distDynamic * dir, testResDynamic[1])
			return (testResStatic[0], None)
	class MinimapMarker(_IMarker):
		def __init__(self, markerID, minimap, position):
			super(MinimapMarker, self).__init__()
			modal=minimap.addTarget(markerID, position[:])
			if markerID and modal is not None:
				self.__markerID = markerID
				self.__minimap = weakref.ref(minimap)
				self.eid = modal._entryID
			else:
				self.__markerID = ''
				self.__minimap = lambda : None
				self.eid = 0

		def update(self):
			pass

		def clear(self):
			try:
				minimap = self.__minimap()
				if minimap is not None and self.__markerID:
					minimap.delTarget(self.__markerID)
				self.__markerID = ''
				self.__minimap = None
				self.eid = 0
			except Exception, e:
				s=sys.exc_info()
				err(str(s[2].tb_lineno)+' aimpos|'+ str(e.message))
			return
except Exception, e:
	s=sys.exc_info()
	err(str(s[2].tb_lineno)+' aimpos|'+ str(e.message))