from go_to_adjacent_systems import *
from go_somewhere_significant import *
from Vector import *
import vsrandom
import launch
import faction_ships
import VS
import Briefing
import universe
import unit
import Director
import quest


def calcCatchupPosition( toPos, fromPos, makeDistance):
        curDistance = calcDistance( toPos, fromPos)
        if makeDistance < curDistance:
            newPos = posBetweenByRatio( toPos, fromPos, makeDistance / curDistance)
            print "PODXXescpod wasDistance: " + str( curDistance) + ", newDistance: " + str( calcDistance( toPos, newPos))  # + ", new pos: " + newPos
            return newPos
        return fromPos

        
class escort_pod (Director.Mission):
	def __init__ ( self, creds, flightPath, destBaseName, escorteeShipType, enemyLockOnEscorteeChance = 1, guildRewardMod = 1.0, attackProb = 0 ):
            Director.Mission.__init__(self)
            self.creds = creds
            self.you = VS.getPlayer()
            self.currentSystemName = self.you.getUnitSystemFile()
            self.isAutopilotedFlag = False
            self.isJumpedFlag = False
            self.credBonusEarned = 0
            self.guildRewardMod = guildRewardMod
            self.radarRange = faction_ships.calcRadarRange( self.you)
            
            self.escorteeFaction = "merchant"
            self.escorteeShipType = escorteeShipType
            self.escortee = None
            self.escorteeGreeting = universe.getRandomGreeting( "common")
            self.escorteeGreetTime = 10000000
            self.distanceToEscortee = 0
            
            self.flightPath = flightPath
            self.nextSystemIndex = 1
            self.systemsNavpointsList = []   #[ ( self.currentSystemName, self.findJumppointToSystem( flightPath[1])) ]
            self.nextNavpointEnroute = None
            self.destBaseUnit = None
            self.destBaseName = destBaseName
            self.destSysTask = go_to_adjacent_systems( self.you, 0, self.flightPath)
            self.credBonusObjective = VS.addObjective( "Extra payment: %d" % self.credBonusEarned)
            VS.setCompleteness( self.credBonusObjective, -.4)

            self.escorteeDistanceObjectiveText = "Escortee distance: "
            self.escorteeDistanceObjective = VS.addObjective( self.escorteeDistanceObjectiveText)
            self.missionStage = "start"
            self.oncourseText = "Stay on course..."
            self.escortingOjective = VS.addObjective( self.oncourseText)
            self.objectiveGotoDestBase = -1
            self.dockingEndTime = 10000000
            self.escorteeAwayFailTime = 10000000
            self.escorteeJumpOutTime = 10000000
            self.escorteeJumpAllowedDistance = 500
            
            self.nextEnemyScanTime = 0
            self.enemyTrackingRange = 2000
            self.nearbyEnemyShips = []
            self.isEnemiesAround = False
            self.enemyLockOnEscorteeChance = enemyLockOnEscorteeChance
            self.attackProb = attackProb   # XXX unused

            self.updateNavpointsEnroute()
                
                
        def payOffMission( self):
            VS.AdjustRelation( self.you.getFactionName(), self.escorteeFaction, .03, 1)
            if self.creds > 0:
                self.you.addCredits( self.creds + self.credBonusEarned)
            VS.terminateMission( 1)
                
                
        def failMission( self, punishCreds):
            if punishCreds:
                self.you.addCredits( -0.5 * self.creds)
            VS.AdjustRelation( self.you.getFactionName(), self.escorteeFaction, -.02, 1)				
            VS.terminateMission(0)
            
            
        def launchEscortee( self, launchAroundUnit, minRadius, maxRadius):
            L = launch.Launch()
            L.fg = "Escort"
            L.faction = self.escorteeFaction
            L.type = self.escorteeShipType
            if not L.type or L.type == '':
                L.type = faction_ships.getRandomFighter( self.escorteeFaction)
            L.ai = "civ"
            L.num = 1
            L.minradius = minRadius
            L.maxradius = maxRadius
            L.forcetype = True
            self.escortee = L.launch( launchAroundUnit)
            
            self.escortee.setFlightgroupLeader( self.escortee)
            self.escortee.setMissionRelevant()
            self.escortee.setFullname( self.escortee.getFullname() + " (escortee)")

            
        def setOnCourseObjective( self, objectiveText):
            VS.setObjective( self.escortingOjective, objectiveText)
            VS.setCompleteness( self.escortingOjective, -.2)
        

        def setTooFarObjective( self):
            timeLeft = max( 0, .33 * (self.escorteeAwayFailTime - VS.GetGameTime()))
            VS.setObjective( self.escortingOjective, "Get back to the escortee! (" + str( int( timeLeft)) + ")")
            VS.setCompleteness( self.escortingOjective, -.6)
        
        
        def setWaitJumpingObjective( self):
            VS.setObjective( self.escortingOjective, "The escortee is jumping, wait...")
            VS.setCompleteness( self.escortingOjective, -.2)
        
        
        def setWaitDockingObjective( self):
            VS.setObjective( self.escortingOjective, "The escortee is docking, wait...")
            VS.setCompleteness( self.escortingOjective, .2)
        
        
        def setProtectObjective( self):
            VS.setObjective( self.escortingOjective, "Break off the attack!")
            VS.setCompleteness( self.escortingOjective, -1.0)
            
            
        def isEscorteeTooFar( self):
            return self.you.getUnitSystemFile() <> self.escortee.getUnitSystemFile() or self.you.getDistance( self.escortee) > 1500
        
        
        def findJumppointToSystem( self, destSystemName):
            if destSystemName[:7] == "Gemini/":
                destSystemName = destSystemName[7:]
            destJpName = "jump_to_" + destSystemName.lower()
            
            for njp in universe.getJumppointList():
                if destJpName == njp.getName().lower().replace( "'", ""):
                    #print "PODXXescpod found jumpPoint: " + njp.getName()
                    return njp
            return None
            
        
        def isEscorteeDistanceInstaRaised( self):
            oldDest = self.distanceToEscortee
            self.distanceToEscortee = self.you.getDistance( self.escortee)
            return self.distanceToEscortee - oldDest > 1500

        
        def isNextEnrouteSystem( self, systemName):
            escorteeSystemName = self.escortee.getUnitSystemFile()
            print "PODXXescpod isNextEnrouteSystem: " + systemName + ", escorteeSystemName: " + escorteeSystemName + ", flightPath: " + str( self.flightPath)
            try:
                yourIndex = self.flightPath.index( systemName)
                escIndex = self.flightPath.index( escorteeSystemName)
                print "PODXXescpod yourIndex: " + str( yourIndex) + ", escIndex: " + str( escIndex)
                return  yourIndex - escIndex == 1
            except ValueError:
                return False
        
        
        def getNextNavpointEnroute( self):
            esys = self.escortee.getUnitSystemFile()
            for sn in self.systemsNavpointsList:
                if sn[0] == esys:
                    return sn[1]
            return None
            
        
        def updateNavpointsEnroute( self):
            try:
                i = self.flightPath.index( self.currentSystemName)
                if i >= len( self.systemsNavpointsList):	# assuming a player won't skip enroute systems, mission will be failed anyway if he will
                    if i == len( self.flightPath) - 1:
                        self.destBaseUnit = universe.findUnit( self.destBaseName)
                        self.systemsNavpointsList += [ ( self.currentSystemName, self.destBaseUnit) ]
                    else:
                        self.systemsNavpointsList += [ ( self.currentSystemName, self.findJumppointToSystem( self.flightPath[i+1])) ]
                    print "PODXXescpod updated systemsNavpointsList: " + str( self.systemsNavpointsList)
            except ValueError:
                pass
        
        
        def isEscorteeJumpAllowed( self):
            return self.escortee.getDistance( self.nextNavpointEnroute) < self.escorteeJumpAllowedDistance
            
            
	def isOnTrackList( self, unit):
            for nextEnemy in self.nearbyEnemyShips:
                if ( unit == nextEnemy[0] ):
                    return True
            return False
        

        def untrackDeadOrFarawayEnemies( self):
            validEnemies = []
            for nextEnemy in self.nearbyEnemyShips:
                if nextEnemy[0].isNull():
                    self.credBonusEarned += self.calcShipValue( nextEnemy[1], nextEnemy[2])
                    VS.setObjective( self.credBonusObjective, "Extra payment: %d" % self.credBonusEarned)
                elif ( self.escortee.getDistance( nextEnemy[0]) < self.enemyTrackingRange ):
                    validEnemies.append( nextEnemy )
            self.nearbyEnemyShips = validEnemies


        def calcShipValue( self, shipType, faction):
                value = 500
                if ( faction == "retro" ):
                    value = 600
                elif ( faction == "pirates" ):
                    value = 700
                elif ( faction == "kilrathi" and shipType == "dralthi" ):
                    value = 1250
                elif ( faction == "kilrathi" and shipType == "gothri" ):
                    value = 2250
                return value * self.guildRewardMod


        def Execute( self):
            if not self.you:
                VS.terminateMission( 0)
                return
            self.destSysTask.Execute()
            if VS.GetGameTime() >= self.escorteeGreetTime:
                self.escorteeGreetTime = 10000000
                universe.greet( self.escorteeGreeting, self.escortee, self.you)

            if self.escortee == None:
                self.launchEscortee( self.you, 250, 300)
                self.escorteeGreetTime = VS.GetGameTime() + 6
                self.distanceToEscortee = self.you.getDistance( self.escortee)
                self.nextNavpointEnroute = self.getNextNavpointEnroute()
                self.escortee.SetTarget( self.nextNavpointEnroute)
                self.missionStage = "enroute"
            if self.escortee == None or self.escortee.isNull():
                self.failMission( True)
                return
            
            distanceText = "???"
            if self.distanceToEscortee < self.radarRange:
                distanceText = str( int( 10 * self.distanceToEscortee))
            VS.setObjective( self.escorteeDistanceObjective, self.escorteeDistanceObjectiveText + distanceText)
            
            #################### Enemies scan
            if self.nextEnemyScanTime < VS.GetGameTime():
                self.nextEnemyScanTime = VS.GetGameTime() + 3

                self.untrackDeadOrFarawayEnemies()
                    
                unitsList = VS.getUnitList()
                nextUnit = unitsList.current()
                while ( unitsList.notDone() and not nextUnit.isNull() ):
                    if ( nextUnit.isStarShip() ):
                        uFaction = nextUnit.getFactionName()
                        uDistance = self.escortee.getDistance( nextUnit)
                        uName = nextUnit.getFullname()
                        if ( uFaction in ["retro", "pirates", "kilrathi"] ):
                            nextUnit.setFgDirective( 'a')
                            lockChance = self.enemyLockOnEscorteeChance
                            if uFaction == "kilrathi":
                                lockChance *= .5
                            if vsrandom.random() < lockChance:
                                lockOnto = self.escortee
                            else:
                                lockOnto = self.you
                            #print "PODXXescpod Next unit: " + uName + ", fac: " + uFaction + ", dist: " + str(uDistance)
                            if ( uDistance < self.enemyTrackingRange and not self.isOnTrackList( nextUnit) ):
                                self.nearbyEnemyShips.append( (nextUnit, uName, uFaction, lockOnto) )
                    unitsList.advanceInsignificant()
                    nextUnit = unitsList.current()
                self.isEnemiesAround = len( self.nearbyEnemyShips) > 0

            #################### Jump and Autopilot checks
            if self.currentSystemName != self.you.getUnitSystemFile():
                print "PODXXescpod jumped flag"
                self.isJumpedFlag = True
                self.currentSystemName = self.you.getUnitSystemFile()
                self.distanceToEscortee = self.you.getDistance( self.escortee)
                self.updateNavpointsEnroute()
            elif self.isEscorteeDistanceInstaRaised() and self.you.getUnitSystemFile() == self.escortee.getUnitSystemFile():
                print "PODXXescpod autopiloted flag"
                self.isAutopilotedFlag = True
                return

            #################### Away mode
            if self.missionStage == "escorteeIsAway":
                if not self.isEscorteeTooFar():
                    self.escorteeAwayFailTime = 10000000
                    self.missionStage = "enroute"
                else:
                    #print "PODXXescpod away" 
                    if self.escorteeAwayFailTime <= VS.GetGameTime():
                        self.failMission( False)
                        return
                    self.setTooFarObjective()
                    self.escortee.SetTarget( self.nextNavpointEnroute)
                    if not self.isEnemiesAround:
                        self.escortee.setFgDirective( 'f')
                
            #################### Normal mode
            if self.missionStage == "enroute":
                self.escortee.SetTarget( self.nextNavpointEnroute)
                if self.objectiveGotoDestBase < 0 and self.nextSystemIndex == len( self.flightPath):
                    print "PODXXescpod setting destBase objective"
                    self.objectiveGotoDestBase = self.escortingOjective
                    VS.setObjective( self.objectiveGotoDestBase, "Proceed to " + self.destBaseName)
                    VS.setCompleteness( self.objectiveGotoDestBase, 0)
                    self.escortingOjective = VS.addObjective( self.oncourseText)
                if self.isJumpedFlag:
                    self.isJumpedFlag = False
                    if self.isEscorteeJumpAllowed() and self.isNextEnrouteSystem( self.you.getUnitSystemFile()):
                        self.escorteeJumpOutTime = VS.GetGameTime() + 5
                        self.missionStage = "waitEscorteeJumps"
                    return
                if self.isEscorteeTooFar():
                    if self.isAutopilotedFlag:
                        self.isAutopilotedFlag = False
                        print "PODXXescpod autopiloted, dest2NP: " + str( self.you.getDistance( self.nextNavpointEnroute))
                        if self.you.getDistance( self.nextNavpointEnroute) < 3000 or self.you.getUnitSystemFile() in ["Gemini/Xytani", "Gemini/Rikel", "Gemini/Penders_Star", "Gemini/Palan", "Gemini/Pollux", "Gemini/Crab-12"]:
                            catchupPosition = calcCatchupPosition( self.you.Position(), self.nextNavpointEnroute.Position(), 250)
                            print "PODXXescpod catchupPosition: " + str( catchupPosition) + ", esc position: " + str( self.escortee.Position()) + ", dist2escortee: " + str( self.you.getDistance( self.escortee))
                            self.escortee.Kill()
                            self.launchEscortee( self.you, 100, 150)
                            self.escortee.SetPosition( VS.SafeEntrancePoint( catchupPosition, self.escortee.rSize()))
                            self.distanceToEscortee = self.you.getDistance( self.escortee)
                            self.you.SetTarget( self.escortee)
                            return
                    self.escorteeAwayFailTime = VS.GetGameTime() + 90
                    self.missionStage = "escorteeIsAway"
                    return
                if self.destBaseUnit and self.escortee.getDistance( self.destBaseUnit) < 750:
                    VS.setCompleteness( self.objectiveGotoDestBase, 1.0)
                    self.dockingEndTime = VS.GetGameTime() + 24
                    self.missionStage = "docking"
                    return
                if self.isEnemiesAround:
                    self.missionStage = "enemiesAround"
                    self.escortee.SetTarget( self.nearbyEnemyShips[0][0])   #initial setting, later the escortee decides on it's own
                    return
                #print "PODXXescpod enroute, nextNavpointEnroute: " + self.nextNavpointEnroute.getName()
                self.escortee.DisableTurretAI()
                # jumping info
                if self.isEscorteeJumpAllowed():
                    self.setOnCourseObjective( "Stay on course, ready for a jump... ")
                else:
                    self.setOnCourseObjective( self.oncourseText)
                    self.escortee.setFgDirective( 'b')
                    return
                # waiting near the jumppoint
                if self.escortee.getDistance( self.nextNavpointEnroute) < 200:
                    self.escortee.setFgDirective( 'f')
                return
            
            
            #################### Waiting escortee jumps mode
            if self.missionStage == "waitEscorteeJumps":
                if self.flightPath[self.nextSystemIndex] == self.escortee.getUnitSystemFile():
                    self.nextNavpointEnroute = self.getNextNavpointEnroute()
                    #self.escortee.SetTarget( self.nextNavpointEnroute)
                    self.nextSystemIndex += 1
                    print "PODXXescpod escortee jumped, setting to enroute; self.nextSystemIndex: " + str(self.nextSystemIndex) + ", your system: " + self.you.getUnitSystemFile() + ", esc system: " + self.escortee.getUnitSystemFile()
                    self.missionStage = "enroute"
                else:
                    self.setWaitJumpingObjective()
                    if VS.GetGameTime() < self.escorteeJumpOutTime:
                        return
                    print "PODXXescpod forcing jump, nextNavpointEnroute: " + self.nextNavpointEnroute.getName() + ", dist: " + str( self.escortee.getDistance( self.nextNavpointEnroute)) + ", sys: " + self.escortee.getUnitSystemFile()
                    self.escorteeJumpOutTime = 10000000
                    self.escortee.Kill()
                    jumpOutNavpoint = self.findJumppointToSystem( self.flightPath[self.nextSystemIndex-1])
                    self.launchEscortee( jumpOutNavpoint, 100, 150)
                    self.distanceToEscortee = self.you.getDistance( self.escortee)
                return
                
            #################### Last moments before payoff mode
            if self.missionStage == "docking":
                if self.escortee.getDistance( self.destBaseUnit) < 150 or VS.GetGameTime() > self.dockingEndTime:
                    self.payOffMission()
                    self.escortee.Kill()
                else:
                    self.setWaitDockingObjective()
                    self.escortee.performDockingOperations( self.destBaseUnit, 0)
                return
             
            #################### Fighting mode
            if self.missionStage == "enemiesAround":
                if not self.isEnemiesAround:
                    #self.escortee.SetTarget( self.nextNavpointEnroute)
                    self.missionStage = "enroute"
                else:
                    #print "PODXXescpod enemiesAround" 
                    self.setProtectObjective()
                    if self.isEscorteeTooFar():
                        self.escorteeAwayFailTime = VS.GetGameTime() + 90
                        self.missionStage = "escorteeIsAway"
                    else:
                        self.escortee.setFgDirective( 'a')
                    for enShip in self.nearbyEnemyShips:
                        enShip[0].SetTarget( enShip[3])


            
            return   # End of Execute()


#        def initbriefing( self):
#            print "init briefing"
#            self.adjsys.initbriefing()				
#        def loopbriefing( self):
#            print "loop briefing"
#            self.adjsys.loopbriefing()
#            Briefing.terminate()
#        def endbriefing( self):
#            print "ending briefing"
#            self.adjsys.endbriefing()
