#include "nav_room.hpp"
#include "nav_marker.hpp"
#include "utils/godot_macros.hpp"
#include <godot_cpp/classes/global_constants.hpp>
#include <cmath>

void NavRoom::_bind_methods() {
#define CLASSNAME NavRoom
    GDPROPERTY_HINTED(neighbours_inspector, gd::Variant::ARRAY, gd::PROPERTY_HINT_ARRAY_TYPE, GDNODETYPE("NavRoom"));
}

NavRoom *NavRoom::get_closest_room(gd::Vector3 const &closest_to) {
    NavRoom *candidate{nullptr};
    float shortest_distance{INFINITY};
    for(NavRoom *room : NavRoom::rooms) {
        float const distance{room->get_global_position().distance_squared_to(closest_to)};
        if(distance < shortest_distance) {
            shortest_distance = distance;
            candidate = room;
        }
    }
    return candidate;
}

void NavRoom::_enter_tree() {
    NavRoom::rooms.push_back(this);
    this->connect("child_entered_tree", callable_mp(this, &NavRoom::on_child_entered));
}

void NavRoom::_exit_tree() {
    NavRoom::rooms.erase(this);
}

void NavRoom::on_child_entered(gd::Node *child) {
    if(NavMarker *marker{gd::Object::cast_to<NavMarker>(child)})
        this->markers.push_back(marker);
}

gd::Vector<NavRoom*> const &NavRoom::get_neighbours() const {
    return this->neighbours;
}

gd::Vector<NavMarker*> const &NavRoom::get_markers() const {
    return this->markers;
}

gd::Array NavRoom::get_neighbours_inspector() const {
    gd::Array a{};
    for(NavRoom *room : this->neighbours)
        a.push_back(room);
    return a;
}

void NavRoom::set_neighbours_inspector(gd::Array array) {
    this->neighbours.clear();
    while(!array.is_empty()) if(NavRoom *room{gd::Object::cast_to<NavRoom>(array.pop_front())})
        this->neighbours.push_back(room);
}

gd::Vector<NavRoom*> NavRoom::rooms{};
