#include "graph.h"

#include <maps/libs/graph/po_helpers/include/graph_objects.h>
#include <yandex/maps/jams/static_graph2/persistent_index.h>

namespace maps {
namespace mrc {
namespace features_deleter {

namespace gpo = graph2::po;
namespace jsg = jams::static_graph2;

namespace {

constexpr db::TFc MAX_FUN_CLASS = 7;

// Not all edges are available to take free pictures
bool isAcceptableForPhotos(const jsg::DirectedEdgeData& edge)
{
    return static_cast<db::TFc>(edge.category()) <= MAX_FUN_CLASS
           && edge.type() != jsg::DirectedEdgeData::Type::Ferry
           && edge.passable() && !edge.isToll();
}

} // anonymous namespace

Graph::Graph(const std::string& graphFolder)
    : optionsDescr_("Options", 110)
    , graphObjects_(new graph2::GraphObjects(
          &optionsDescr_,
          gpo::GraphEntity::TOPOLOGY | gpo::GraphEntity::DATA
              | gpo::GraphEntity::EDGES_RTREE))
{
    std::vector<const char*> options = {""};

    if (!graphFolder.empty()) {
        options.push_back("--graph-folder");
        options.push_back(graphFolder.c_str());
    }

    program_options::parseCommandLine(options.size(), (char**)options.data(),
                                      optionsDescr_, true);
    graphObjects_->load();
}

Graph::~Graph() = default;

Edges Graph::edgesInWindow(const geolib3::BoundingBox& bbox)
{
    Edges result;
    const jsg::Graph graph(
        graphObjects_->getPointer<gpo::GraphEntity::TOPOLOGY>(),
        graphObjects_->getPointer<gpo::GraphEntity::DATA>());
    const auto& rtree = graphObjects_->get<gpo::GraphEntity::EDGES_RTREE>();
    const auto edgeIds = rtree.edgesInWindow(graph.data(), bbox);
    for (const auto edgeId : edgeIds) {
        const auto& edgeData = graph.edgeData(edgeId);
        if (isAcceptableForPhotos(edgeData)) {
            result.push_back({edgeId, geolib3::Polyline2(edgeData.points())});
        }
    }
    return result;
}

Edge Graph::edgeById(db::TId edgeId)
{
    const jsg::Graph graph(
        graphObjects_->getPointer<gpo::GraphEntity::TOPOLOGY>(),
        graphObjects_->getPointer<gpo::GraphEntity::DATA>());
    const auto& edgeData = graph.edgeData(edgeId);
    return {edgeId, geolib3::Polyline2(edgeData.points())};
}

} // features_deleter
} // mrc
} // maps
