-- $LastChangedDate: 2010-04-11 20:45:55 -0500 (Sun, 11 Apr 2010) $
-- Mission in OSSIM.
-- mission.lua defines an equivalent of a Mission base class which this extends.
-- See module.txt for documentation and pitfalls.

-- Specialize mission class.
assert( Mission )  -- mission.lua defines base methods
Mission.BaseReset       = Mission.Reset
Mission.simulationSpeed = 25.0
Mission.initialSpeedKPH = 2000.0
Mission.initialThrottle = 0.1
Mission.baseAlt         = 150000.0
local argIdxAlt = sim.GetArgvIdx( "-alt" )
if ( argIdxAlt ) then
    Mission.baseAlt = tonumber(sim.argvArray[argIdxAlt + 1])
    Log( "base altitude = " .. tostring(Mission.baseAlt) )
end
Mission.placeNames = {
    ["UserDefined"]     = Vec3(   0.0,    0.00, Mission.baseAlt ),
    ["Nepal"]           = Vec3(  27.0,   82.00, Mission.baseAlt ),
    ["Himalayas"]       = Vec3(  33.2,   78.10, Mission.baseAlt ),
    ["Oregon"]          = Vec3(  43.4, -121.70, Mission.baseAlt ),
    ["Sahara"]          = Vec3(  22.1,   15.30, Mission.baseAlt ),
    ["San Francisco"]   = Vec3(  37.5, -122.40, Mission.baseAlt ),
    ["New York"]        = Vec3(  40.3,  -74.00, Mission.baseAlt ),
    ["Chicago"]         = Vec3(  41.5,  -87.30, Mission.baseAlt ),
    ["Grand Canyon"]    = Vec3(  36.1, -112.10, Mission.baseAlt ),
    ["Florida"]         = Vec3(  25.0,  -82.00, Mission.baseAlt ),
    ["Antarctica"]      = Vec3( -78.0,   81.00, Mission.baseAlt ),
    ["London"]          = Vec3(  51.76,   0.00, Mission.baseAlt ),
    ["Mediterrean Sea"] = Vec3(  35.00,  21.52, Mission.baseAlt ),
    ["Japan"]           = Vec3(  33.83, 138.46, Mission.baseAlt ),
    ["Australia"]       = Vec3( -39.57, 146.39, Mission.baseAlt ),
    ["South America"]   = Vec3( -30.24, -64.02, Mission.baseAlt ),
}
Mission.initialPositionName = "Florida"

-- Set user-defined position.
function Mission:SetUserDefinedPosition( lat, lon, alt )
    if ( lat and lon and alt ) then
        self.initialPositionName = "UserDefined"
        local pos = Vec3( tonumber(lat),
                          tonumber(lon),
                          tonumber(alt) )
        self.placeNames["UserDefined"] = pos
    end
end

-- Hook into the processing of commands from the simulator's "command queue".
-- CommandQueue will defer commands it doesn't recognize.
function Mission:ProcessCommand( cmdFields )
    local cmd = cmdFields[1]
    -- Is this a place-name?
    if ( self.placeNames[cmd] ) then
        self.initialPositionName = cmd
        self:Reset()
    end
end
CommandQueue:RegisterProcessFunction( Mission.ProcessCommand )

-- (private)
function Mission:ResetLocation()
    -- Using the GUI, the user can select the location by name or by entering lat,lon,alt.
    -- Normally, (lat,lon,alt) will be empty strings.
    local cmdFields = CommandQueue:GetCmdFields()
    if ( cmdFields and (cmdFields[CommandQueue.COMMAND_FIELD] == "RESTART") ) then
        local locationName = cmdFields[CommandQueue.RESTART_FIELD_LOCATION]
        local locationLat  = cmdFields[CommandQueue.RESTART_FIELD_LAT]
        local locationLon  = cmdFields[CommandQueue.RESTART_FIELD_LON]
        local locationAlt  = cmdFields[CommandQueue.RESTART_FIELD_ALT]
        -- Change location (OSSIM).
        if ( locationLat ~= "" and locationLon ~= "" and locationAlt ~= "" ) then
            self:SetUserDefinedPosition( locationLat, locationLon, locationAlt )
            Log( "Changing location to (" .. locationLat .. "," .. locationLon .. "," .. locationAlt .. ")." )
        else
            -- Set by name.
            self.initialPositionName = locationName
            Log( "Changing location to " .. tostring(locationName) .. "." )
        end
    end
end

-- (private)
function Mission:ResetPlayer()
    local placement = sim.BeginPlacement()

        local physics = PlayerActor.aircraft:GetPhysics()

        -- Set position of player.
        local initialPosSphere = self.placeNames[self.initialPositionName]
        self.initialPos = sim.World.SphereVertex2WorldVertex( initialPosSphere )
        PlayerActor.aircraft:SetPosition( self.initialPos )

        -- Set orientation of player.
        sim.World:RotateTangential( PlayerActor.aircraft, initialPosSphere )  -- align with surface of planet
        PlayerActor.aircraft:Rotate( YY, Deg2Rad(90.0) ) -- fly west

        -- Set throttle, speed, etc.
        PlayerActor.aircraft:SetThrottle( self.initialThrottle )
        physics:SetSpeed( sim.Physics.KPH2Speed( self.initialSpeedKPH ) )
        PlayerActor.aircraft:SetLandingGear( sim.LANDING_GEAR_UP )  -- SUBTLE: SetLandingGear() becomes a NOP if speed is zero.

    sim.EndPlacement( placement )
end

-- (private)
function Mission:ResetViews()
    sim.SuperView:SetViewMode( sim.SuperView.eViewMode_CHASE ) -- OTW_FRONT
    ChaseView.chaseViewpoint = ChaseView.chaseViewpointPlayer
    if ( not self.ifDoneResetView ) then
        self.ifDoneResetView = true
        ChaseView.chaseViewpoint:Save()
        sim.SuperView:MakeSecondView()
    end
    --local chaseDistance = sim.World.Meters2Sim( 35.0 )
    local chaseDistance = sim.World.Meters2Sim( 200.0 )
    ChaseView.chaseViewpoint:SetDistance( 0.0, 0.0, chaseDistance )
    ChaseView.chaseViewpoint:Rotate( sim.ChaseViewpoint.AXIS_CHASE_PLANE_VERT, Deg2Rad(85.0) )
    ChaseView.chaseViewpoint:Rotate( sim.ChaseViewpoint.AXIS_CHASE_PLANE_HORZ, Deg2Rad(180.0) )
end

-- Reset/init mission.
function Mission:Reset()
    self:BaseReset()
    self:ResetLocation()
    self:ResetPlayer()
    self:ResetViews()
end

-- Initialization/start mission (done once).
function Mission:Start()
    -- Parse -llh (lat/lon/height) arg.
    local llhIdx = sim.GetArgvIdx( "-llh" )
    if ( llhIdx ) then
        self:SetUserDefinedPosition( sim.argvArray[llhIdx + 1], sim.argvArray[llhIdx + 2], sim.argvArray[llhIdx + 3] )
    end

    -- Disable stalling for Space Shuttle.
    sim.Physics:EnableStall( false )

    -- Increase simulation speed (unless user passed arg).
    if ( not sim.argvMap["-speed"] ) then
        sim.Base:SetSimulationSpeed( Mission.simulationSpeed )
    end

    -- Initial reset.
    self:Reset()
end

-- Mission-specific timer-tick handler.
function Mission:Tick()
    -- NOP
end

Timer:Register( Mission, defs.MISSION_TICK_FREQ )

-- Let startup.lua continue...
