-- =======================================================
-- SCRIPT: LASTE Wind/Temp Correction
-- VERSION: 14-06-2026 (ver. 1.6)
-- SCRIPTED BY: CaptMike
-- =======================================================
-- DESCRIPTION:
-- In an A-10 Thunderbolt II, LASTE stands for Low Altitude Safety
-- and Targeting Enhancement.
--
-- This script provides an in-cockpit weather data service 
-- for the A-10C and A-10C II modules via the F10 Radio Menu.
-- It dynamically probes localized weather and pressure data 
-- directly below the aircraft's current coordinate vector.
--
-- The output formats data matching the 4 physical CDU entry 
-- altitude tiers (00, 02, 08, 26). Wind parameters are 
-- packed into a raw 5-digit string (e.g., 08001) with no 
-- slashes, allowing direct entry into the CDU scratchpad.
-- Negative temperatures are prefixed with a minus sign (-).
--
-- Displays data via native DCS group text blocks for 5 
-- minutes, with an on-demand option to clear the layout.
-- Uses the MOOSE framework engine to handle weather tracking.
-- MOOSE Framework: https://github.com/FlightControl-Master/MOOSE
--
--
-- =======================================================
-- MISSION EDITOR SETUP INSTRUCTIONS:
-- =======================================================
-- 1. Create a trigger to load the MOOSE framework:
--    - TYPE: 4 MISSION START
--    - NAME: Load MOOSE
--    - ACTION: DO SCRIPT FILE -> Select your "Moose.lua" file.
--
-- 2. Create a delayed trigger to load this script file:
--    - TYPE: 1 ONCE
--    - NAME: Load LASTE Script
--    - CONDITION: TIME MORE (5) 
--      (This 5-second delay ensures MOOSE initializes first)
--    - ACTION: DO SCRIPT FILE -> Select this saved script file.
--
-- 3. In-Game Usage:
--    - Hop into any A-10C or A-10C II aircraft slot.
--    - Press your Communication Menu key (\) -> F10 Other.
--    - Select "LASTE" -> Opens the custom tool suite.
--    - Click "Request LASTE Winds" to view or "Clear LASTE Data" to close.
-- =======================================================

-- Print confirmation message directly to the dcs.log file upon execution
env.info("=== LASTE WIND/TEMP CORRECTION SYSTEM LOADED SUCCESSFULLY ===")

-- Global tracking table to manage F10 items natively across network slots
if not _G.LasteMultiplayerTrack then
    _G.LasteMultiplayerTrack = {
        Menus = {}
    }
end

-- Helper function to fetch and format magnetic variation via MOOSE
-- UTILS.GetMagneticDeclination() returns degrees (positive=East, negative=West)
local function GetMagneticVariationString()
    local ok, magVarDeg = pcall(function()
        return UTILS.GetMagneticDeclination()
    end)

    if not ok or magVarDeg == nil then return "N/A" end

    local sign = magVarDeg >= 0 and "+" or "-"
    return string.format("%s%.1f deg", sign, math.abs(magVarDeg))
end

-- Function to fetch and display weather safely using native Group environment
local function ShowLasteToGroup(GroupName)
    local dcsGroup = Group.getByName(GroupName)
    
    if dcsGroup and dcsGroup:isExist() then
        local dcsUnits = dcsGroup:getUnits()
        local dcsUnit = dcsUnits[1]
        
        if dcsUnit and dcsUnit:isExist() and dcsUnit:getLife() > 0 then
            local unitPos = dcsUnit:getPosition().p
            local PlayerPos = COORDINATE:NewFromVec3(unitPos)
            
            -- The 5 valid distinct physical CDU entry tiers
            local AltitudesFeet = {0, 1000, 2000, 8000, 26000}
            
            -- Fetch local sea-level barometric pressure (QNH) via native DCS atmosphere engine
            local sampleCoord = { x = unitPos.x, y = 0, z = unitPos.z }
            local _, rawPressurePascal = atmosphere.getTemperatureAndPressure(sampleCoord)
            
            -- Convert Pascals to inches of Mercury (inHg)
            local qnhInHg = rawPressurePascal * 0.000295300

            -- Fetch magnetic variation via MOOSE UTILS (map-wide constant)
            local magVarStr = GetMagneticVariationString()
            
            -- Clean, bold header style
            local Message = "===========================================\n"
            Message = Message .. "       LASTE WIND/TEMP CORRECTION DATA       \n"
            Message = Message .. "===========================================\n"
            Message = Message .. string.format("Location: %s\n", PlayerPos:ToStringMGRS())
            Message = Message .. string.format("Local Magnetic Variation: %s\n", magVarStr)
            Message = Message .. string.format("Current Ground QNH: A%.2f\n\n", qnhInHg)
            
            -- Master-aligned headers calibrated to baseline tracking
            Message = Message .. "ALT LAYER          ALT          WIND             TEMP\n"
            Message = Message .. "---------------------------------------------------------\n"
            
            -- Loop through altitudes, extract weather, and format
            for _, AltFeet in ipairs(AltitudesFeet) do
                local AltMeters = AltFeet * 0.3048
                local WindDir, WindSpeedms = PlayerPos:GetWind(AltMeters)
                local TempC = math.floor(PlayerPos:GetTemperature(AltMeters))
                local WindKnots = math.floor(WindSpeedms * 1.94384)
                local WindHeading = math.floor(WindDir)
                
                -- Format temperature for the CDU with consistent fixed-width alignment
                -- Positive temps padded to 3 chars (e.g. " 20"), negatives keep minus sign (e.g. "-32")
                local TempStr
                if TempC < 0 then
                    TempStr = string.format("-%d", math.abs(TempC))
                else
                    TempStr = string.format("%3d", TempC)
                end
                
                -- Format Wind Data string WITHOUT the slash (e.g., 08001)
                local WindString = string.format("%03d%02d", WindHeading, WindKnots)
                
                -- Calibrated space layouts tailored to offset proportional text drift perfectly
                if AltFeet == 0 then
                    Message = Message .. string.format("0000 ft                00              %s             %s\n", WindString, TempStr)
                elseif AltFeet == 1000 then
                    Message = Message .. string.format("1000 ft                01              %s             %s\n", WindString, TempStr)
                elseif AltFeet == 2000 then
                    Message = Message .. string.format("2000 ft                02              %s             %s\n", WindString, TempStr)
                elseif AltFeet == 8000 then
                    Message = Message .. string.format("8000 ft                08              %s             %s\n", WindString, TempStr)
                elseif AltFeet == 26000 then
                    Message = Message .. string.format("26000 ft              26              %s             %s\n", WindString, TempStr)
                end
            end
            
            Message = Message .. "---------------------------------------------------------\n\n"
            Message = Message .. "=== MANUAL DATA ENTRY STEPS ===\n"
            Message = Message .. "1. Turn Altimeter Pressure knob to match Ground QNH.\n"
            Message = Message .. "2. Press [SYS] on CDU -> OSB 06 [LASTE] -> OSB 07 [WIND].\n"
            Message = Message .. "3. Select/Create Altitude Layer First:\n"
            Message = Message .. "   Type ALT value into scratchpad -> Press target ALT OSB.\n"
            Message = Message .. "4. Enter Layer Editing Mode:\n"
            Message = Message .. "   Press OSB 07 [WNDEDIT] to open data fields for that altitude.\n"
            Message = Message .. "5. Input Target Data:\n"
            Message = Message .. "   Type Wind Entry (e.g. 08001) -> Press OSB 02 [WIND].\n"
            Message = Message .. "   Type Temp Entry (e.g. 19 or -32) -> Press OSB 03 [TEMP].\n"
            Message = Message .. "6. Press [WP] on the UFC to return to Steerpoint page."
            
            local groupID = dcsGroup:getID()
            trigger.action.outTextForGroup(groupID, "", 1, true)
            trigger.action.outTextForGroup(groupID, Message, 300, true)
        end
    end
end

-- Function called by the F10 menu item to clear the display instantly
local function ClearLasteDisplay(GroupName)
    local dcsGroup = Group.getByName(GroupName)
    if dcsGroup then
        local groupID = dcsGroup:getID()
        trigger.action.outTextForGroup(groupID, "", 1, true)
    end
end

-- Dedicated Multiplayer Safe Loop Scheduler Engine
local LastePlayerFilter = SET_CLIENT:New():FilterCoalitions("blue"):FilterStart()

SCHEDULER:New(nil, function()
    -- Scan all active blue client slots via MOOSE tracking filters
    LastePlayerFilter:ForEachClient(function(ClientUnit)
        if ClientUnit and ClientUnit:IsAlive() then
            local airframeType = ClientUnit:GetTypeName()
            
            if airframeType == "A-10C" or airframeType == "A-10C_2" then
                local ClientGroup = ClientUnit:GetGroup()
                
                if ClientGroup and ClientGroup:IsAlive() then
                    local groupName = ClientGroup:GetName()
                    local dcsGroup = Group.getByName(groupName)
                    
                    if dcsGroup then
                        local groupID = dcsGroup:getID()
                        
                        -- If this group ID doesn't have an active F10 menu record, construct it natively
                        if not _G.LasteMultiplayerTrack.Menus[groupID] then
                            -- Insert menus directly into the DCS mission commands network array passing the raw GroupName string
                            local rootMenu = missionCommands.addSubMenuForGroup(groupID, "LASTE")
                            missionCommands.addCommandForGroup(groupID, "Request LASTE Winds", rootMenu, ShowLasteToGroup, groupName)
                            missionCommands.addCommandForGroup(groupID, "Clear LASTE Data", rootMenu, ClearLasteDisplay, groupName)                                                      
                            _G.LasteMultiplayerTrack.Menus[groupID] = rootMenu
                        end
                    end
                end
            end
        end
    end)
end, {}, 1, 2)
