/*
 * Manger class for aircraft generated by swift
 * SPDX-FileCopyrightText: (C) 2019-2022 swift Project Community / Contributors (https://swift-project.org/)
 * SPDX-FileCopyrightText: (C) 2019-2022 Lars Toenning <dev@ltoenning.de>
 * SPDX-License-Identifier: GPL-2.0-or-later
 */

#include "SwiftAircraftManager.h"
#include <Main/globals.hxx>
#include <utility>

namespace flightgear::swift {

FGSwiftAircraftManager::FGSwiftAircraftManager()
{
    m_initialized = true;
}

FGSwiftAircraftManager::~FGSwiftAircraftManager()
{
    this->removeAllPlanes();
    m_initialized = false;
}

bool FGSwiftAircraftManager::isInitialized() const
{
    return m_initialized;
}

bool FGSwiftAircraftManager::addPlane(const std::string& callsign, const std::string& modelString)
{
    this->removePlane(callsign); // Remove plane if already exists e.g. when rematching is done.
    auto curAircraft = FGAISwiftAircraftPtr(new FGAISwiftAircraft(callsign, modelString));
    globals->get_subsystem<FGAIManager>()->attach(curAircraft);
    // Init props after prop-root is assigned
    curAircraft->initProps();

    aircraftByCallsign.insert(std::pair<std::string, FGAISwiftAircraftPtr>(callsign, curAircraft));
    return true;
}

void FGSwiftAircraftManager::updatePlanes(const std::vector<SwiftPlaneUpdate>& updates)
{
    for (auto& update : updates) {
        auto it = aircraftByCallsign.find(update.callsign);
        if (it != aircraftByCallsign.end()) {
            it->second->updatePosition(update.position, update.orientation, update.groundspeed, true);
        }
    }
}

void FGSwiftAircraftManager::getRemoteAircraftData(std::vector<std::string>& callsigns, std::vector<double>& latitudesDeg, std::vector<double>& longitudesDeg, std::vector<double>& elevationsM, std::vector<double>& verticalOffsets) const
{
    if (callsigns.empty() || aircraftByCallsign.empty()) { return; }

    const auto requestedCallsigns = callsigns;
    callsigns.clear();
    latitudesDeg.clear();
    longitudesDeg.clear();
    elevationsM.clear();
    verticalOffsets.clear();

    for (const auto& requestedCallsign : requestedCallsigns) {
        const auto it = aircraftByCallsign.find(requestedCallsign);
        if (it == aircraftByCallsign.end()) { continue; }

        const FGAISwiftAircraft* aircraft = it->second;
        assert(aircraft);


        SGGeod pos;
        pos.setLatitudeDeg(aircraft->_getLatitude());
        pos.setLongitudeDeg(aircraft->_getLongitude());
        const double latDeg = pos.getLatitudeDeg();
        const double lonDeg = pos.getLongitudeDeg();
        double groundElevation = aircraft->getGroundElevation(pos);

        callsigns.push_back(requestedCallsign);
        latitudesDeg.push_back(latDeg);
        longitudesDeg.push_back(lonDeg);
        elevationsM.push_back(groundElevation);
        verticalOffsets.push_back(0);
    }
}

void FGSwiftAircraftManager::removePlane(const std::string& callsign)
{
    auto it = aircraftByCallsign.find(callsign);
    if (it != aircraftByCallsign.end()) {
        it->second->setDie(true);
        aircraftByCallsign.erase(it);
    }
}

void FGSwiftAircraftManager::removeAllPlanes()
{
    for (const auto &[_, plane] : aircraftByCallsign) {
        plane->setDie(true);
    }
    aircraftByCallsign.clear();
}

double FGSwiftAircraftManager::getElevationAtPosition(const std::string& callsign, const SGGeod& pos) const
{
    auto it = aircraftByCallsign.find(callsign);
    if (it != aircraftByCallsign.end()) {
        return it->second->getGroundElevation(pos);
    }
    // Aircraft not found in list
    return std::numeric_limits<double>::quiet_NaN();
}

void FGSwiftAircraftManager::setPlanesTransponders(const std::vector<AircraftTransponder>& transponders)
{
    for (const auto& transponder : transponders) {
        auto it = aircraftByCallsign.find(transponder.callsign);
        if (it != aircraftByCallsign.end()) {
            it->second->setPlaneTransponder(transponder);
        }
    }
}

void FGSwiftAircraftManager::setPlanesSurfaces(const std::vector<AircraftSurfaces>& surfaces)
{
    for (const auto& surface : surfaces) {
        auto it = aircraftByCallsign.find(surface.callsign);
        if (it != aircraftByCallsign.end()) {
            it->second->setPlaneSurface(surface);
        }
    }
}

} // namespace flightgear::swift
