/*
 * Author:
 *   Sven Czarnian <devel@svcz.de>
 * Brief:
 *   Implements the EuroScope plug-in definition
 * Copyright:
 *   2021 Sven Czarnian
 * License:
 *   GNU General Public License v3 (GPLv3)
 */

#include "stdafx.h"

#include <gsl/gsl>
#include <Shlwapi.h>
#include <Windows.h>

#include <aman/config/CommunicationFileFormat.h>
#include <aman/config/IdentifierFileFormat.h>

#include "PlugIn.h"

EXTERN_C IMAGE_DOS_HEADER __ImageBase;

using namespace aman;

PlugIn::PlugIn() :
        EuroScopePlugIn::CPlugIn(EuroScopePlugIn::COMPATIBILITY_CODE,
                                 PLUGIN_NAME,
                                 PLUGIN_VERSION,
                                 PLUGIN_DEVELOPER,
                                 PLUGIN_COPYRIGHT),
        m_configuration() {
    this->DisplayUserMessage(PLUGIN_NAME, "INFO", (std::string("Loaded ") + PLUGIN_NAME + " " + PLUGIN_VERSION).c_str(), true, true, false, false, false);

    /* get the dll-path */
    char path[MAX_PATH + 1] = { 0 };
    const gsl::span<char, MAX_PATH + 1> span(path);
    GetModuleFileNameA((HINSTANCE)&__ImageBase, span.data(), span.size());
    PathRemoveFileSpecA(span.data());
    std::string dllPath = span.data();

    CommunicationFileFormat comFormat;
    if (false == comFormat.parse(dllPath + "\\AmanCommunication.txt", this->m_configuration) || true == comFormat.errorFound()) {
        this->DisplayUserMessage(PLUGIN_NAME, "ERROR", "Unable to parse AmanCommunication.txt", true, true, true, true, true);
        this->DisplayUserMessage(PLUGIN_NAME, "ERROR", ("AmanCommunication.txt:" + std::to_string(comFormat.errorLine()) + " - " + comFormat.errorMessage()).c_str(), true, true, true, true, true);
        return;
    }

    IdentifierFileFormat identFormat;
    if (false == identFormat.parse(dllPath + "\\AmanIdentity.txt", this->m_configuration) || true == identFormat.errorFound()) {
        this->DisplayUserMessage(PLUGIN_NAME, "ERROR", "Unable to parse AmanIdentity.txt", true, true, true, true, true);
        this->DisplayUserMessage(PLUGIN_NAME, "ERROR", ("AmanIdentity.txt:" + std::to_string(identFormat.errorLine()) + " - " + identFormat.errorMessage()).c_str(), true, true, true, true, true);
        return;
    }
}

PlugIn::~PlugIn() noexcept { }

EuroScopePlugIn::CRadarScreen* PlugIn::OnRadarScreenCreated(const char* displayName, bool needsRadarContent, bool geoReferenced,
    bool canBeSaved, bool canBeCreated) {
    std::ignore = needsRadarContent;
    std::ignore = geoReferenced;
    std::ignore = canBeSaved;
    std::ignore = canBeCreated;
    std::ignore = displayName;

    if (nullptr == this->m_screen)
        this->m_screen = std::make_shared<RadarScreen>();

    return this->m_screen.get();
}

void PlugIn::OnRadarTargetPositionUpdate(EuroScopePlugIn::CRadarTarget radarTarget) {
    /* ignore invalid targets */
    if (false == radarTarget.IsValid())
        return;

    auto flightPlan = radarTarget.GetCorrelatedFlightPlan();

    /* ignore invalid flightplans */
    if (false == flightPlan.IsValid())
        return;

    /* ignore flights that are not tracked by the current controller */
    if (false == flightPlan.GetTrackingControllerIsMe())
        return;

    /* ignore non-IFR flights */
    if (nullptr == flightPlan.GetFlightPlanData().GetPlanType() || 'I' != *flightPlan.GetFlightPlanData().GetPlanType())
        return;

    /* filter by distance to destination */
    double distanceNM = flightPlan.GetDistanceToDestination();
    if (250.0 < distanceNM)
        return;

    /* filter by airborne identifier (assume a GS>50kn and a big distance to the origin) */
    if (50 > radarTarget.GetGS() || 10.0 > flightPlan.GetDistanceFromOrigin())
        return;

    /* TODO generate protobuf message */
    /* TODO send aircraft update */
}
