#include "MeshLoader.h"

std::vector<Node> MeshLoader::getNodes() {
    return nodes;
}

std::vector<FiniteElement> MeshLoader::getFiniteElements() {
    return finiteElements;
}

std::vector<BoundaryElement> MeshLoader::getBoundaryElements() {
    return boundaryElements;
}

std::vector<FiniteElement> MeshLoader::getElementsByNodesID(unsigned int ID1, unsigned int ID2, unsigned int ID3) {
    std::vector<FiniteElement> elements;
    auto beg = finiteElements.begin(), end = finiteElements.end();
    while (beg != end) {
        auto e = std::find_if(beg, end,
                              [ID1, ID2, ID3](const FiniteElement &elem) -> bool {
                                  auto iter_curr = elem.nodesID.begin(), iter_end = elem.nodesID.end();
                                  return std::find(iter_curr, iter_end, ID1) != iter_end &&
                                         std::find(iter_curr, iter_end, ID2) != iter_end &&
                                         std::find(iter_curr, iter_end, ID3) != iter_end;
                              });
        if (e != end) {
            elements.push_back(*e);
            ++e;
        }
        beg = e;
    }
    return elements;
}

std::vector<FiniteElement> MeshLoader::getElementsByEdge(unsigned int ID1, unsigned int ID2) {
    std::vector<FiniteElement> elements;
    auto beg = finiteElements.begin(), end = finiteElements.end();
    while (beg != end) {
        auto e = std::find_if(beg, end,
                              [ID1, ID2](const FiniteElement &elem) -> bool {
                                  auto iter_curr = elem.nodesID.begin(), iter_end = elem.nodesID.end();
                                  return std::find(iter_curr, iter_end, ID1) != iter_end &&
                                         std::find(iter_curr, iter_end, ID2) != iter_end;
                              });
        if (e != end) {
            elements.push_back(*e);
            ++e;
        }
        beg = e;
    }
    return elements;
}

std::unordered_set<unsigned int> MeshLoader::getBoundaryNodesByBoundaryID(unsigned int ID) {
    std::unordered_set<unsigned int> elements;
    auto beg = boundaryElements.begin(), end = boundaryElements.end();
    while (beg != end) {
        auto e = std::find_if(beg, end,
                              [ID](const BoundaryElement &elem) -> bool {
                                  return elem.boundaryID == ID;
                              });
        if (beg != end) {
            for (auto element: e->nodesID) {
                elements.insert(element);
            }
        }
        ++beg;
    }
    return elements;
}

std::vector<FiniteElement> MeshLoader::getFiniteElementsByAreaID(unsigned int ID) {
    std::vector<FiniteElement> elements;
    auto beg = finiteElements.begin(), end = finiteElements.end();
    while(beg != end){
        auto e = std::find_if(beg, end,
                              [ID](const FiniteElement &elem) -> bool {
                                  return elem.areaID == ID;
                              });
        if (beg != end) {
            elements.push_back(*e);
            ++e;
        }
        ++beg;
    }
    return elements;
}

std::vector<BoundaryElement> MeshLoader::getBoundaryElementsByBoundaryID(unsigned int ID) {
    std::vector<BoundaryElement> elements;
    auto beg = boundaryElements.begin(), end = boundaryElements.end();
    while(beg != end){
        auto e = std::find_if(beg, end,
                              [ID](const BoundaryElement &elem) -> bool {
                                  return elem.boundaryID == ID;
                              });
        if (beg != end) {
            elements.push_back(*e);
            ++e;
        }
        ++beg;
    }
    return elements;
}

void MeshLoader::insertNodesIntoMiddles() {
    //TODO
}

std::vector<std::unordered_set<unsigned int>> MeshLoader::makeVectorOfNeighbours() {
    std::vector<std::unordered_set<unsigned int>> neighbours(nodes.size() + 1);
    for (auto &elem: boundaryElements) {
        for (auto &i: elem.nodesID) {
            for (auto &j: elem.nodesID) {
                if (i != j) {
                    neighbours[i].insert(j);
                }
            }
        }
    }
    return neighbours;
}
