#include "../categories.h"
#include "../magic_strings.h"
#include "../attribute_dumper.h"
#include "../relation_dumper.h"
#include "../ft_helper.h"

namespace maps {

namespace {
const std::string NODE_ID = "node_id";
const std::string FT_TYPE_ID = "ft_type_id";
const std::string FT_TYPE_IDS = "ft_type_ids";
} // namespace

struct FtJcCategory: public Category {
    const Table& table() const override
    {
        return table::NODE;
    }

    void tupleToJson(
        json::ObjectBuilder& builder,
        const pqxx::row& tuple) const override
    {
        FtData ft(tuple);
        
        builder[jkey::ATTRIBUTES] = [&](json::ObjectBuilder builder) {
            AttributeDumper ad(ft.category(name()), builder);
            ad.dumpCategory();
        };
        dumpGeometry(builder, tuple);
    }
};

struct FtLnJcCategory: public FtJcCategory {
    std::string name() const override
    {
        return category::FT_LN_JC;
    }

    std::string loadIdsSql() const override
    {
        return
            "SELECT DISTINCT node.node_id "
            "FROM ft_edge "
            "JOIN edge ON (ft_edge.edge_id = edge.edge_id) "
            "JOIN node ON "
                "(edge.f_node_id = node.node_id "
                "OR edge.t_node_id = node.node_id)";
    }

    std::string loadRowsSqlTemplate() const override
    {
        return 
            "SELECT DISTINCT node.node_id id, st_asgeojson(node.shape) shape, " +
                ftMacroSql("MAX(ft_edge.ft_id)") + " "
            "FROM node, edge, ft_edge "
            "WHERE "
                "(edge.f_node_id = node.node_id "
                "OR edge.t_node_id = node.node_id) "
            "AND ft_edge.edge_id = edge.edge_id "
            "AND node_id IN %1% "
            "GROUP BY node.node_id, node.shape";
    }
};

struct FtFcJcCategory: public FtJcCategory {
    std::string name() const override
    {
        return category::FT_FC_JC;
    }

    std::string loadIdsSql() const override
    {
        return
            "SELECT DISTINCT node.node_id "
            "FROM ft, ft_face, face_edge, edge, node "
            "WHERE ft.ft_type_id NOT IN (" + polygonFtTypes() + ") "
            "AND ft.ft_id = ft_face.ft_id "
            "AND face_edge.face_id = ft_face.face_id "
            "AND edge.edge_id = face_edge.edge_id "
            "AND (edge.f_node_id = node.node_id "
                "OR edge.t_node_id = node.node_id)";
    }

    std::string loadRowsSqlTemplate() const override
    {
        return
            "SELECT node_id id, st_asgeojson(shape) shape," +
                ftFcJcSql("node_id") + " "
            "FROM node "
            "WHERE node_id IN %1%";
    }
};

DEFINE_CATEGORY_OBJECT(FtLnJc, FT_LN_JC);
DEFINE_CATEGORY_OBJECT(FtFcJc, FT_FC_JC);

} // namespace maps
