#include "AneuMeshLoader.h"

namespace std {
    std::ostream &operator<<(std::ostream &ost, const std::vector<unsigned int> &vec) {
        for (auto elem: vec) {
            ost << elem << " ";
        }
        ost << "\b";
        return ost;
    }

    std::ostream &operator<<(std::ostream &ost, const std::vector<Node> &vec) {
        for (const auto &elem: vec) {
            ost << elem << std::endl;
        }
        return ost;
    }

    std::ostream &operator<<(std::ostream &ost, const std::vector<FiniteElement> &vec) {
        for (const auto &elem: vec) {
            ost << elem << std::endl;
        }
        return ost;
    }

    std::ostream &operator<<(std::ostream &ost, const std::vector<BoundaryElement> &vec) {
        for (const auto &elem: vec) {
            ost << elem << std::endl;
        }
        return ost;
    }

    std::ostream &operator<<(std::ostream &ost, const std::unordered_set<unsigned int> &vec) {
        for (auto elem: vec) {
            ost << elem << " ";
        }
        ost << "\b";
        return ost;
    }
}


//!!! Задание на защиту (не удалять!)
//!!! Реализовать на основе std::ranges
//!!! 1. Создать контайнер всех граничных КЭ (треугольников).
//!!! 2. За один pipeline вывести в файл списки ID (!) первых 10 граничных КЭ,
//!!!    у которых значение минимального угла от 30 до 40 градусов.


int main(int argc, char *argv[]) {
    AneuMeshLoader loader;
    try {
        if (argc > 1) {
            loader.loadMesh(argv[0]);
        } else {
            loader.loadMesh("../data/ellipsoid.aneu");
        }
    } catch (FileNotExistException &e) {
        std::cerr << e.what() << std::endl;
    }

    std::cout << std::endl << "Nodes: " << loader.getNodes() << std::endl;
    std::cout << "Finite elements: " << loader.getFiniteElements() << std::endl;
    std::cout << "Boundary elements: " << loader.getBoundaryElements() << std::endl;

    std::cout << "Elements with nodes 220, 366, 181: ";
    std::cout << loader.getElementsByNodesID(220, 366, 181) << std::endl;

    std::cout << "Elements with edge 220, 366: ";
    std::cout << loader.getElementsByEdge(220, 366) << std::endl;

    std::cout << "Nodes with boundary ID 1: ";
    std::cout << loader.getBoundaryNodesByBoundaryID(1);
    std::cout << std::endl;

    std::cout << "Elements with area ID 1: ";
    std::cout << loader.getFiniteElementsByAreaID(1) << std::endl;

    std::cout << "Boundary elements with boundary ID 1: ";
    std::cout << loader.getBoundaryElementsByBoundaryID(1) << std::endl;

    loader.insertNodesIntoMiddles();
    std::cout << "Mesh after inserting new nodes into middles of edges:";
    std::cout << std::endl << "Nodes: " << loader.getNodes() << std::endl;
    std::cout << "Finite elements: " << loader.getFiniteElements() << std::endl;
    std::cout << "Boundary elements: " << loader.getBoundaryElements() << std::endl;

    std::cout << "Nodes' neighbours:" << std::endl;
    auto neighbours = loader.makeVectorOfNeighbours();
    std::ranges::for_each(neighbours, [](auto &element) {
        std::cout << element << std::endl;
    });

    return 0;
}
