#include "ft_type.h"
#include "magic_strings.h"

#include <maps/libs/common/include/exception.h>
#include <maps/libs/log8/include/log8.h>
#include <maps/libs/ymapsdf/include/ft.h>

#include <map>
#include <set>
#include <sstream>

namespace maps {

using FtType = ymapsdf::ft::Type;

namespace {

enum class FtGeomType
{
    None = 0,
    Point = 1,
    Linear = 2,
    Contour = 3,
    Polygon = 4,
    Line = 5
};

class FtFixer {
public:
    FtFixer();

    std::string fixCategory(
        const std::string& origCat,
        FtType ftType,
        IsPoint isPoint) const;

    bool hasFtTypeAttr(const std::string& category) const;
    std::string ftPartRole(const std::string& category) const;
    std::string ftMasterRole(const std::string& caregory) const;
    const std::string& polygonFtTypes() const { return polygonFtTypes_; }
    const std::string& trivialFtTypes() const { return trivialFtTypes_; }
    const std::string& lineFtTypes() const { return lineFtTypes_; }
    const std::string& pointFtTypes() const { return pointFtTypes_; }

public:
    typedef std::map<std::string, std::string> FtMapping;

private:
    typedef std::tuple<std::string, FtType, IsPoint> FtKey;
    typedef std::map<FtKey, std::string> FtCategoryMap;
    typedef std::map<std::string, bool> HasFtTypeMap;

private:
    void regInternal(
        const std::string& origCategory,
        const std::string& baseCategory,
        FtType ftType,
        const FtMapping& ftMapping,
        IsPoint isPoint = IsPoint::No);

    void reg(
        const std::vector<FtType>& ftTypes,
        FtGeomType ftGeomType,
        const std::string& baseCategory,
        const FtMapping& ftMapping = FtMapping(),
        FtType trivialFtType = FtType::None);

private:
    FtCategoryMap ftCategoryMap_;
    HasFtTypeMap hasFtTypeMap_;
    FtMapping ftPartRoleMap_;
    FtMapping ftMasterRoleMap_;
    std::string polygonFtTypes_;
    std::string lineFtTypes_;
    std::string pointFtTypes_;
    std::string trivialFtTypes_;
    bool allowUnknownFt_;
};

const FtFixer FT_FIXER;

std::string
fix(
    const std::string& category,
    const std::string& baseCategory,
    const FtFixer::FtMapping& ftMapping)
{
    const auto& it = ftMapping.find(category);
    if (it != ftMapping.end()) {
        return it->second;
    }

    size_t suffixPos = 0;
    if (category == category::FT) {
        suffixPos = category::FT.length();
    }
    for (const std::string& prefix: {"ft_", "ft_fc_", "ft_ln_"}) {
        if (category.starts_with(prefix)) {
            suffixPos = std::max(suffixPos, prefix.length() - 1);
        }
    }

    if (suffixPos > 0) {
        return baseCategory + category.substr(suffixPos);
    } else {
        return category;
    }

}

void
FtFixer::regInternal(
    const std::string& origCategory,
    const std::string& baseCategory,
    FtType ftType,
    const FtMapping& ftMapping,
    IsPoint isPoint)
{
    auto ftMapKey = std::make_tuple(origCategory, ftType, isPoint);
    ftCategoryMap_[ftMapKey] = fix(origCategory, baseCategory, ftMapping);
}

void
FtFixer::reg(
    const std::vector<FtType>& ftTypes,
    FtGeomType ftGeomType,
    const std::string& baseCategory,
    const FtMapping& ftMapping,
    FtType trivialFtType)
{
    bool hasFtType = hasFtTypeMap_.count(baseCategory) > 0 || ftTypes.size() > 1;
    hasFtTypeMap_[baseCategory] = hasFtType; // hasFtType must be calculated in another statement, so [] won't create an element in the map.

    ftPartRoleMap_[baseCategory] = fix(role::PART, baseCategory, ftMapping);
    ftMasterRoleMap_[baseCategory] = fix(role::ASSIGNED, baseCategory, ftMapping);

    if (trivialFtType != FtType::None) {
        if (!trivialFtTypes_.empty()) {
            trivialFtTypes_ += ", ";
        }
        trivialFtTypes_ += std::to_string(static_cast<int>(trivialFtType));
    }

    for (const auto& ftType: ftTypes) {
        if (ftGeomType == FtGeomType::Polygon) {
            if (!polygonFtTypes_.empty()) {
                polygonFtTypes_ += ", ";
            }
            polygonFtTypes_ += std::to_string(static_cast<int>(ftType));
        } else if (ftGeomType == FtGeomType::Line) {
            if (!lineFtTypes_.empty()) {
                lineFtTypes_ += ", ";
            }
            lineFtTypes_ += std::to_string(static_cast<int>(ftType));
        } else if (ftGeomType == FtGeomType::Point) {
            if (!pointFtTypes_.empty()) {
                pointFtTypes_ += ", ";
            }
            pointFtTypes_ += std::to_string(static_cast<int>(ftType));
        }
        IsPoint isPoint = ftGeomType == FtGeomType::Point
            ? IsPoint::Yes
            : IsPoint::No;

        regInternal("ft", baseCategory, ftType, ftMapping, isPoint);
        regInternal("ft_nm", baseCategory, ftType, ftMapping, isPoint);

        if (ftGeomType == FtGeomType::Linear) {
            regInternal("ft_ln_el", baseCategory, ftType, ftMapping);
            regInternal("ft_ln_jc", baseCategory, ftType, ftMapping);
        } else if (ftGeomType == FtGeomType::Contour) {
            regInternal("ft_fc", baseCategory, ftType, ftMapping);
            regInternal("ft_fc_el", baseCategory, ftType, ftMapping);
            regInternal("ft_fc_jc", baseCategory, ftType, ftMapping);
        }
    }
}


std::string
FtFixer::fixCategory(
    const std::string& origCategory,
    FtType ftType,
    IsPoint isPoint) const
{
    auto it = ftCategoryMap_.find(
        std::make_tuple(origCategory, ftType, isPoint));
    if (it != ftCategoryMap_.end()) {
        return it->second;
    }

    std::stringstream errorMsg;
    errorMsg << "Unknown mapping for cat:" << origCategory
        << ", ft_type=" << static_cast<int>(ftType)
        << (isPoint == IsPoint::Yes ? ", is a point" : ", not a point");
    REQUIRE(allowUnknownFt_, errorMsg.str());
    WARN() << errorMsg.str();

    return origCategory;
}

bool
FtFixer::hasFtTypeAttr(const std::string& category) const
{
    auto it = hasFtTypeMap_.find(category);
    if (it != hasFtTypeMap_.end()) {
        return it->second;
    }
    return true;
}

std::string
FtFixer::ftPartRole(const std::string& category) const
{
    auto it = ftPartRoleMap_.find(category);
    if (it != ftPartRoleMap_.end()) {
        return it->second;
    }
    return role::PART;
}

std::string
FtFixer::ftMasterRole(const std::string& category) const
{
    auto it = ftMasterRoleMap_.find(category);
    if (it != ftMasterRoleMap_.end()) {
        return it->second;
    }
    return role::ASSIGNED;
}

FtFixer::FtFixer() {
    allowUnknownFt_ = false;

    //ft, ft_nm, ft_face, ft_fc_el, ft_fc_jc, ft_ln_el, ft_ln_jc

    // Vegetation
    reg({
            FtType::Vegetation,
            FtType::VegetationPark,
            FtType::VegetationNatpark,
            FtType::VegetationLawn,
            FtType::VegetationGarden,
            FtType::VegetationResidential,
            FtType::UrbanCemetery,
        },
        FtGeomType::Contour,
        "vegetation");

    // Hydrography - contour
    reg({
            FtType::HydroOcean,
            FtType::HydroSea,
            FtType::HydroBay,
            FtType::HydroStrait,
            FtType::HydroLake,
            FtType::HydroReservoir,
            FtType::HydroPond,
            FtType::HydroSwamp,
            FtType::HydroGlacier,
            FtType::HydroPool,
            //+517
        },
        FtGeomType::Contour,
        "hydro",
        {
            {"ft_fc", "hydro_fc"},
            {"ft_fc_el", "hydro_fc_el"},
            {"ft_fc_jc", "hydro_fc_jc"},
            {"part", "fc_part"},
        });

    // Hydrography - point
    reg({
            FtType::HydroSpring,
            FtType::HydroFountain,
            FtType::HydroWaterfall,
            FtType::HydroWell,
            FtType::HydroGeyser,
            FtType::HydroStandpipe,
        },
        FtGeomType::Point,
        "hydro_point",
        {{"ft_nm", "hydro_nm"}});

    // Hydrography - linear
    reg({
            FtType::HydroRiverLarge,
            FtType::HydroRiver,
            FtType::HydroRiverSmall,
            FtType::HydroRiverStream,
            FtType::HydroRiverIrrigation,
            FtType::HydroRiverIntermittent,
            FtType::HydroRiverGreatest,
            FtType::HydroRiverCanal,
        },
        FtGeomType::Linear,
        "hydro_ln",
        {
            {"ft_nm", "hydro_nm"},
            {"ft_ln_el", "hydro_ln_el"},
            {"ft_ln_jc", "hydro_ln_jc"},
            {"part", "ln_part"}
        },
        FtType::HydroRiverStream);

    // Relief
    reg({
            FtType::Relief,
            FtType::ReliefIsland,
            FtType::ReliefArchipelago,
        },
        FtGeomType::Contour,
        "relief");
    reg({
            FtType::ReliefMountain,
            FtType::ReliefPass,
            FtType::ReliefVolcano,
        },
        FtGeomType::Point,
        "relief_point",
        {{"ft_nm", "relief_nm"}});

    // Buildings And Built Environment Areas
    reg({
            FtType::UrbanResidential,
            FtType::UrbanIndustrial,
            FtType::UrbanPublic,
            FtType::UrbanUnderConstruction,
            FtType::UrbanLeisure,
            FtType::UrbanReligionWorship,
            FtType::UrbanMedHospital,
            FtType::UrbanShopping,
            FtType::UrbanSport,
            FtType::UrbanSportground,
            FtType::UrbanTransport,
            FtType::UrbanLeisureBeach,
            FtType::UrbanGarbage,
            FtType::UrbanGov,
            FtType::UrbanEdu,
            FtType::UrbanBusinessCenter,
            FtType::UrbanRoadnetParkingLot,
            // +med, etc
        },
        FtGeomType::Polygon,
        "urban_areal",
        {
            {"ft_nm", ""},
            {"assigned", "urban_areal_assigned"}
        });

    // Squares And Roadnet Structures
    reg({
            FtType::UrbanRoadnetRoadconstruction,
            FtType::UrbanRoadnetSquare,
            FtType::UrbanRoadnetBridge,
            FtType::UrbanRoadnetTunnel,
            FtType::UrbanRoadnetPedestrianOverpass,
            FtType::UrbanRoadnetPedestrianBridge,
            FtType::UrbanRoadnetPedestrianUnderpass,
        },
        FtGeomType::Polygon,
        "urban_roadnet_areal",
        {{"ft_nm", "urban_roadnet_nm"}});
    reg({
            FtType::UrbanRoadnetParkingLot,
            FtType::UrbanRoadnetParkingFree,
            FtType::UrbanRoadnetParkingToll,
            FtType::UrbanRoadnetParkingRestricted,
        },
        FtGeomType::Point,
        "urban_roadnet_parking_lot",
        {{"ft_nm", "urban_roadnet_nm"}});
    reg({
            FtType::UrbanRoadnetParkingFree,
            FtType::UrbanRoadnetParkingToll,
            FtType::UrbanRoadnetParkingRestricted,
            FtType::UrbanRoadnetParkingProhibited,
        },
        FtGeomType::Line,
        "urban_roadnet_parking_lot_linear",
        {{"ft_nm", ""}});

    // Metro And Rapid Transit
    reg({
            FtType::TransportMetroLightLine,
            FtType::TransportMetroTramLine,
            FtType::TransportMetroMonorailLine,
            FtType::TransportMetroBusLine,
            FtType::TransportMetroCableLine,
            FtType::TransportMetroFunicularLine,
            FtType::TransportMetroLine,
        },
        FtGeomType::Linear,
        "transport_metro_line",
        {
            {"ft_nm", "transport_metro_nm"},
            {"ft_ln_el", "transport_metro_el"},
            {"ft_ln_jc", "transport_metro_jc"},
            {"assigned", "assigned_metro"},
        });
    reg({
            FtType::TransportMetroStation,
        },
        FtGeomType::Point,
        "transport_metro_station",
        {{"ft_nm", "transport_metro_nm"}});
    reg({
            FtType::TransportMetroExit,
        },
        FtGeomType::Point,
        "transport_metro_exit",
        {{"ft_nm", "transport_metro_nm"}});

    // Railway Transport
    reg({
            FtType::TransportRailway,
            FtType::TransportRailwaySiding,
            FtType::TransportRailwayChildren,
            FtType::TransportRailwayNarrowGauge,
            FtType::TransportRailwayFerry,
        },
        FtGeomType::Linear,
        "transport_railway",
        {},
        FtType::TransportRailwaySiding);
    reg({
            FtType::TransportRailwayStation,
            FtType::TransportRailwayGoodsStation,
            FtType::TransportRailwayTerminal,
        },
        FtGeomType::Point,
        "transport_railway_station",
        {{"ft_nm", "transport_railway_nm"}});

    // Water Transport
    reg({
            FtType::TransportWaterwayWharf,
            FtType::TransportWaterwaySeaport,
            FtType::TransportWaterwayRiverport,
        },
        FtGeomType::Point,
        "transport_waterway_stop",
        {{"ft_nm", "transport_waterway_nm"}});
    reg({
            FtType::TransportWaterway,
        },
        FtGeomType::Linear,
        "transport_waterway_route",
        {{"assigned", "assigned_waterway"}});

    // Avia Transport
    reg({
            FtType::TransportAirport,
            FtType::TransportAirportDomestic,
            FtType::TransportAirportAirfield,
        },
        FtGeomType::Point,
        "transport_airport");
    reg({
            FtType::TransportHelicopter,
        },
        FtGeomType::Point,
        "transport_helicopter",
        {{"ft_nm", "transport_airport_nm"}});
    reg({
            FtType::TransportAirportTerminal,
        },
        FtGeomType::Point,
        "transport_airport_terminal",
        {{"ft_nm", "transport_airport_nm"}});

    // Public Transport
    reg({
            FtType::TransportSystem,
        },
        FtGeomType::Point,
        "transport_operator",
        {
        },
        FtType::TransportSystem);

    reg({
            FtType::TransportRouteAlias,
        },
        FtGeomType::None,
        "transport_route_alias",
         {
         },
        FtType::TransportRouteAlias);

    reg({
            FtType::TransportTramRoute,
        },
        FtGeomType::Linear,
        "transport_tram_route",
         {
             {"ft_nm", "transport_nm"},
             {"ft_ln_el", "transport_rasp_el"},
             {"ft_ln_jc", "transport_rasp_jc"},
         },
         FtType::TransportTramRoute);

    reg({
            FtType::TransportBusRoute,
            FtType::TransportTrolleybusRoute,
            FtType::TransportMinibusRoute,
        },
        FtGeomType::Linear,
        "transport_bus_route",
         {
             {"ft_nm", "transport_nm"},
             {"ft_ln_el", "transport_rasp_el"},
             {"ft_ln_jc", "transport_rasp_jc"},
         },
         FtType::TransportBusRoute);

    reg({
            FtType::TransportTramThread,
        },
        FtGeomType::Linear,
        "transport_tram_thread",
         {
             {"ft_nm", "transport_nm"},
             {"part", "rasp_part"},
             {"ft_ln_el", "transport_rasp_el"},
             {"ft_ln_jc", "transport_rasp_jc"},
             {"assigned", "assigned_thread"}
         });

    reg({
            FtType::TransportBusThread,
        },
        FtGeomType::Linear,
        "transport_bus_thread",
         {
             {"ft_nm", "transport_nm"},
             {"part", "rasp_part"},
             {"ft_ln_el", "transport_rasp_el"},
             {"ft_ln_jc", "transport_rasp_jc"},
             {"assigned", "assigned_thread"}
         });

    reg({
            FtType::TransportThreadStop,
        },
        FtGeomType::None,
        "transport_thread_stop",
         {{"ft", "transport_thread_stop"}},
         FtType::TransportThreadStop);

    reg({
            FtType::TransportFreqDt,
        },
        FtGeomType::None,
        "freq_dt",
         {},
         FtType::TransportFreqDt);

    reg({
            FtType::TransportBusTerminal,
        },
        FtGeomType::Point,
        "transport_terminal",
         {{"ft_nm", "transport_nm"}});
    reg({
            FtType::TransportTramStop,
            FtType::TransportShareTaxiStop,
            FtType::TransportBusStop,
            FtType::TransportTaxiStop,
            // +691
        },
        FtGeomType::Point,
        "transport_stop",
        {{"ft_nm", "transport_nm"}});

    // Medical Buildings, Organizations, and Areas
    reg({
            FtType::UrbanMed,
            FtType::UrbanMedHospital,
            FtType::UrbanMedDental,
            FtType::UrbanMedVeterinary,
            FtType::UrbanMedPharmacy,
            FtType::UrbanMedOptician,
        },
        FtGeomType::Point,
        "poi_medicine",
        {{"ft_nm", "poi_nm"}});

    // Educational Buildings, Organizations, and Areas
    reg({
            FtType::UrbanEduKindergarten,
            FtType::UrbanEduSchoolSecondary,
            FtType::UrbanEduVocational,
            FtType::UrbanEduUniversity,
            FtType::UrbanEduExtraAcademic,
            FtType::UrbanEduLibrary,
            FtType::UrbanEduScientific,
        },
        FtGeomType::Point,
        "poi_edu",
        {{"ft_nm", "poi_nm"}});

    // Government And Public Service Organizations
    reg({
            FtType::UrbanGov,
            FtType::UrbanGovGovernment,
            FtType::UrbanGovCourt,
            FtType::UrbanGovPolice,
            FtType::UrbanGovFirefighting,
            FtType::UrbanGovCivilRegistry,
            FtType::UrbanGovMigration,
            FtType::UrbanGovCenter,
            FtType::UrbanGovSocialSecurity,
            FtType::UrbanGovTaxInspectorate,
            FtType::UrbanGovRecruitmentCenter,
            FtType::UrbanGovPrison,
            FtType::UrbanGovCondoManagement,
            FtType::UrbanGovPost,
            FtType::UrbanGovEmbassy,
        },
        FtGeomType::Point,
        "poi_goverment",
        {{"ft_nm", "poi_nm"}});

    // Religios Buildings, Organizations, and Areas
    reg({
            FtType::UrbanReligionWorship,
            FtType::UrbanReligionChrist,
            FtType::UrbanReligionIslam,
            FtType::UrbanReligionJudaism,
            FtType::UrbanReligionBuddhism,
        },
        FtGeomType::Point,
        "poi_religion",
        {{"ft_nm", "poi_nm"}});

    // Foodservice Organizations
    reg({
            FtType::UrbanFoodservice,
            FtType::UrbanFoodserviceFastfood,
            FtType::UrbanFoodserviceBar,
            FtType::UrbanFoodserviceRestaurant,
            FtType::UrbanFoodserviceCoffeeShop,
        },
        FtGeomType::Point,
        "poi_food",
        {{"ft_nm", "poi_nm"}});

    // Shopping Buildings, Organizations, and Areas
    reg({
            FtType::UrbanShopping,
            FtType::UrbanShoppingMall,
            FtType::UrbanShoppingStall,
            FtType::UrbanShoppingMarketFarmers,
            FtType::UrbanShoppingMarketClothes,
            FtType::UrbanShoppingMarketHousehold,
            FtType::UrbanShoppingGrocery,
            FtType::UrbanShoppingFlowers,
            FtType::UrbanShoppingBook,
            FtType::UrbanShoppingAntiques,
            FtType::UrbanShoppingHousehold,
            FtType::UrbanShoppingAppliances,
            FtType::UrbanShoppingSport,
            FtType::UrbanShoppingPerfumery,
            FtType::UrbanShoppingFurniture,
            FtType::UrbanShoppingFashion,
            FtType::UrbanShoppingTextile,
            FtType::UrbanShoppingPet,
            FtType::UrbanShoppingToy,
            FtType::UrbanShoppingJewelry,
            FtType::UrbanShoppingSouvenirs,
            FtType::UrbanShoppingDelivery,
        },
        FtGeomType::Point,
        "poi_shopping",
        {{"ft_nm", "poi_nm"}});

    // Vehicle Services, Places and Organizations
    reg({
            FtType::UrbanCar,
            FtType::UrbanCarFuelStation,
            FtType::UrbanCarTrafficPolice,
            FtType::UrbanCarDealership,
            FtType::UrbanCarParts,
            FtType::UrbanCarRepairshop,
            FtType::UrbanCarTyreshop,
            FtType::UrbanCarCarwash,
            FtType::UrbanCarGarage,
            FtType::UrbanCarDrivingSchool,
            FtType::UrbanCarImpoundLot,
            FtType::UrbanCarTrainingFacility,
            FtType::UrbanCarInspectionStation,
        },
        FtGeomType::Point,
        "poi_auto",
        {{"ft_nm", "poi_nm"}});

    // Financial Places And Organizations
    reg({
            FtType::UrbanMoney,
            FtType::UrbanMoneyBank,
            FtType::UrbanMoneyPawnshop,
            FtType::UrbanMoneyAtm,
            FtType::UrbanMoneyCurrencyExchange,
            FtType::UrbanMoneyPaymentMachine,
            FtType::UrbanMoneyInsurance,
            FtType::UrbanMoneyMicrofinance,
        },
        FtGeomType::Point,
        "poi_finance",
        {{"ft_nm", "poi_nm"}});

    // Service Organizations And Places
    reg({
            FtType::UrbanService,
            FtType::UrbanServiceFactory,
            FtType::UrbanServiceNotary,
            FtType::UrbanServiceLawyer,
            FtType::UrbanServiceBarbershop,
            FtType::UrbanServiceLaundry,
            FtType::UrbanServiceRepair,
            FtType::UrbanServicePhoto,
            FtType::UrbanServicePhoneshop,
            FtType::UrbanServiceTravelAgency,
            FtType::UrbanServiceTicketTransport,
            FtType::UrbanServiceSauna,
            FtType::UrbanServiceFuneral,
            FtType::UrbanServiceRealty,
            FtType::UrbanServiceWasteDisposal,
            FtType::UrbanServiceToilet,
            FtType::UrbanServiceNonprofit,
            FtType::UrbanBusinessCenter,
        },
        FtGeomType::Point,
        "poi_service",
        {{"ft_nm", "poi_nm"}});

    // Sport Buildings, Organizations, and Areas
    reg({
            FtType::UrbanSport,
            FtType::UrbanSportStadium,
            FtType::UrbanSportClub,
            FtType::UrbanSportSwimmingPool,
            FtType::UrbanSportSki,
            FtType::UrbanSportHippodrome,
            FtType::UrbanSportRacetrack,
        },
        FtGeomType::Point,
        "poi_sport",
        {{"ft_nm", "poi_nm"}});

    reg({
            FtType::UrbanSportGolf,
        },
        FtGeomType::Point,
        "poi_sport",
        {{"ft_nm", "poi_nm"}},
        FtType::UrbanSport);

    // Leisure Places And Organizations
    reg({
            FtType::UrbanLeisure,
            FtType::UrbanLeisureHotel,
            FtType::UrbanLeisureBeach,
            FtType::UrbanLeisureSanatorium,
            FtType::UrbanLeisureKidscamp,
            FtType::UrbanLeisureAnimalpark,
            FtType::UrbanLeisureTheater,
            FtType::UrbanLeisureConcertHall,
            FtType::UrbanLeisureCircus,
            FtType::UrbanLeisureCinema,
            FtType::UrbanLeisureMuseum,
            FtType::UrbanLeisureAmusementpark,
            FtType::UrbanLeisureEntertainmentCenter,
            FtType::UrbanLeisureWaterpark,
            FtType::UrbanLeisureHouseOfCulture,
            FtType::UrbanLeisureNightClub,
            FtType::UrbanLeisureObservationDeck,
            FtType::UrbanLeisureMonument,
            FtType::Landmark,
        },
        FtGeomType::Point,
        "poi_leisure",
        {{"ft_nm", "poi_nm"}});

    // Residential Infrastructure
    reg({
            FtType::UrbanPlayground,
            FtType::UrbanSportground,
            FtType::UrbanDogrun,
            FtType::UrbanGarbage,
            FtType::UrbanBikeRental,
            FtType::UrbanBikeParkingLot,
            FtType::UrbanLandmarkMinor,
        },
        FtGeomType::Point,
        "poi_urban",
        {{"ft_nm", "poi_nm"}});

    // Other
    reg({
            FtType::Zipcode,
        },
        FtGeomType::Point,
        "zipcode");
}

} // namespace

std::string
fixCategory(
    const std::string& origCategory,
    int ftType,
    IsPoint isPoint)
{
    return FT_FIXER.fixCategory(origCategory, static_cast<FtType>(ftType), isPoint);
}

bool
hasFtTypeAttr(const std::string& category)
{
    return FT_FIXER.hasFtTypeAttr(category);
}

std::string
ftPartRole(const std::string& category)
{
    return FT_FIXER.ftPartRole(category);
}

std::string
ftMasterRole(const std::string& category)
{
    return FT_FIXER.ftMasterRole(category);
}

const std::string&
polygonFtTypes()
{
    return FT_FIXER.polygonFtTypes();
}

const std::string&
trivialFtTypes()
{
    return FT_FIXER.trivialFtTypes();
}

const std::string&
lineFtTypes()
{
    return FT_FIXER.lineFtTypes();
}

const std::string&
pointFtTypes()
{
    return FT_FIXER.pointFtTypes();
}

} // namespace maps
