-- $LastChangedDate: 2010-04-16 22:43:07 -0500 (Fri, 16 Apr 2010) $
-- Weapons.

-----------
-- Radar --
-----------

Radar = { }

-- NOTE: The Actor containing a Radar responsible for calling Radar:Tick().
-- Else Radar won't function (Radar doesn't install a tick handler of its own).

-- ctor
function Radar:New( actor, geoRange )
    if ( self == Radar ) then
        self = lib.NewInstance( Radar )  -- not chained, need new instance
    end
    self.actor        = actor   -- Actor
    self.lockedTarget = nil     -- Actor
    self.range        = Meters2Sim(geoRange)
    self.minAltGeo    = defs.SAM_RADAR_MIN_ALT_METERS -- Radar cannot detect target below this altitude
    self.enemyTeamNum = Game:OppositeTeamNum( actor:GetTeamNum() )
    return self
end

-- dtor (explicit)
function Radar:Destroy()
    self.destroyed = true
    self.actor = nil
    self.lockedTarget = nil  -- unreference Actor/Object
end

function Radar:Reset()
    self.lockedTarget = nil  -- forget
end

-- Get target that radar has lock or nil.
function Radar:GetTarget()
    return self.lockedTarget
end

-- Position is considered dynamic (in case Actor is an Aircraft).
function Radar:GetPosition()
    return self.actor:GetObject():GetPosition()
end

-- Tick method must be called by the encapsulating actor (see actor.lua).
function Radar:Tick()
    if ( self.destroyed ) then return end  -- fail-safe

    local radarPos = self:GetPosition()

    -- If locked-on, is the target still within range of the radar?
    if ( self.lockedTarget and not self.lockedTarget:IfDestroyed() ) then
        local enemyObject = self.lockedTarget:GetObject()
        local enemyPos = enemyObject:GetPosition()
        local distance = Distance3( radarPos, enemyPos )
        if ( distance < self.range ) then
            return  -- still within range
        end
    end

    -- Either no-lock, or target was destroyed, or target moved out-of-range.
    self.lockedTarget = nil
    local enemy = nil
    while true do
        -- Don't target Actors such as missiles.
        enemy = Game:NextActor( self.enemyTeamNum, enemy )
        if ( not enemy ) then
            break
        elseif ( Game:IfTarget( enemy ) ) then
            -- How far away is the enemy?
            local enemyObject = enemy:GetObject()
            local enemyPos = enemyObject:GetPosition()
            local distance = Distance3( radarPos, enemyPos )
            if ( distance < self.range ) then
                -- How high is the enemy?
                -- Radars cannot detect aircraft flying at very low altitudes.
                local enemyAlt = sim.World:AltitudeInMeters( enemyPos )
                if ( enemyAlt > self.minAltGeo ) then
                    -- Radar has locked-on.
                    self.lockedTarget = enemy
                    break
                end
            end
        end
    end
end

-- Release reference to Actor.
function Radar:UnreferenceActor( actor )
    if ( self.lockedTarget == actor ) then
        self.lockedTarget = nil
    end
end

-----------------
-- PlayerRadar --
-----------------

PlayerRadar = lib.DerivedClass( Radar )

-- ctor
function PlayerRadar:New( actor )
    self = lib.NewInstance( PlayerRadar )

    Radar.New( self, actor, defs.AIRCRAFT_RADAR_RANGE_METERS )  -- chain

    -- For debugging radar/missiles.
    if ( sim.argvMap["-inf-radar"] ) then
        self.range = Meters2Sim( 10000000.0 )
    end

    return self
end

-- dtor (explicit)
function PlayerRadar:Destroy()
    Radar.Destroy( self )  -- chain
end

-- Tick method must be called by the encapsulating actor (see actor.lua).
function PlayerRadar:Tick()
    if ( self.destroyed ) then
        return
    end

    -- Assume no-lock.
    self.lockedTarget = nil
    sim.GameHud:RemoveRadarLock()

    -- Has player selected a target?
    local target = PlayerActor:GetSelectedTarget()
    if ( target ) then
        -- Compute distance between player and target.
        local targetObject = target:GetObject()
        if ( not targetObject ) then return end -- can become nil
        local targetPos = targetObject:GetPosition()
        local playerPos = PlayerActor:GetObject():GetPosition()
        local distance = Distance3( playerPos, targetPos )
        if ( distance < self.range ) then
            -- Draw HUD box with X to indicate radar-lock.
            if ( target ~= self.lockedTarget ) then  -- transition?
                PlayerActor:SelectTarget( target, true )
            end
            -- Remember.
            self.lockedTarget = target
            Hud:RemoveStatusText( defs.HUD_STATUS_NO_RADAR_LOCK )
        end
    end
end
