#pragma once

#include "registry.h"

#include <yandex/maps/wiki/configs/editor/fwd.h>

#include <string>
#include <map>

namespace maps {
namespace wiki {

class GeoObject;
class Junction;
class PointObject;
class LinearElement;
class ObjectsCache;

namespace srv_attrs {

class ServiceAttributesRegistry;

class GenericServiceAttributes
{
public:
    GenericServiceAttributes(ServiceAttributesRegistry& registry);
};

class GenericJC : public ServiceAttributesRegistry::Registrar
{
public:
    GenericJC(const std::string& jcCategoryId,
        const std::string& elCategoryId,
        ServiceAttributesRegistry& registry);

private:
    static std::string canDelete(const Junction* jc, ObjectsCache&);
    static std::string valency(const Junction* jc, ObjectsCache&);
};

class GenericEL : public ServiceAttributesRegistry::Registrar
{
public:
    enum class DependenceType
    {
        Direct,
        Indirect
    };

    GenericEL(
            const std::string& elCategoryId,
            const std::string& featureCategoryId,
            const std::string& countourCategoryId,
            const std::string& nameAttribute,
            ServiceAttributesRegistry& registry);

    static std::string isPartOfInterior(
            const LinearElement* el,
            ObjectsCache& cache,
            const std::string& countourCategoryId);

    static void registerFtTypes(
            ServiceAttributesRegistry::Registrar& registrar,
            DependenceType featureType,
            const std::string& featureCategoryId,
            const std::string& countourCategoryId);

    static std::string ftTypeSrvAttrValue(
            const LinearElement* el,
            ObjectsCache& cache,
            const std::string& attrId,
            const std::string& value,
            DependenceType dependenceType);
private:
    static std::string screenLabel(
            const LinearElement* el,
            ObjectsCache& cache,
            DependenceType dependenceType);

    void registerSrvIsInterior(const std::string& countourCategoryId);

    void registerScreenLabel(
            DependenceType featureType,
            const std::string& featureCategoryId,
            const std::string& countourCategoryId,
            const std::string& nameAttribute);

    void registerFtTypes(
            DependenceType featureType,
            const std::string& featureCategoryId,
            const std::string& countourCategoryId);
};

class GenericCNT : public ServiceAttributesRegistry::Registrar
{
public:
    GenericCNT(
        const std::string& cntCategoryId,
        const std::string& contourCategoryId,
        const std::string& nameAttribute,
        ServiceAttributesRegistry& registry);
private:
    static std::string hotSpotLabel(const PointObject* pt, ObjectsCache& cache);
    static std::string renderLabel(const PointObject* pt, ObjectsCache& cache);
    static std::string dispclass(const PointObject* pt, ObjectsCache& cache);
    static std::string ftTypeSrvAttrValue(
        const PointObject* pt,
        ObjectsCache& cache,
        const std::string& ftTypeValue);
};

class GenericNamedObject : public ServiceAttributesRegistry::Registrar
{
public:
    GenericNamedObject(const std::string& categoryId,
            ServiceAttributesRegistry& registry);
    static std::string hotspotLabel(const GeoObject* obj, ObjectsCache& cache);
    static std::string screenLabel(const GeoObject* obj, ObjectsCache& cache);
    static std::string renderLabel(const GeoObject* obj, ObjectsCache& cache);
    static SuggestTexts suggestTexts(const GeoObject* obj, ObjectsCache& cache);
};

class GenericPointObject : public ServiceAttributesRegistry::Registrar
{
public:
    GenericPointObject(const std::string& categoryId,
            ServiceAttributesRegistry& registry);
    static std::string hasUrbanAreal(const GeoObject* obj, ObjectsCache& cache);
private:
    void registerSrvHasUrbanAreal();
};

const AttrDefPtr&
ftTypeAttrDefForCategory(const std::string& categoryId);

const AttrDefPtr&
enumeratedTypeAttrDefForCategory(const std::string& categoryId);

const AttrDefPtr&
plainNameAttrDefForCategory(const std::string& categoryId);

} // namespace srv_attrs
} // namespace wiki
} // namespace maps
