#include "urban.h"

#include <maps/wikimap/mapspro/services/editor/src/configs/categories_strings.h>
#include <maps/wikimap/mapspro/services/editor/src/configs/config.h>
#include <maps/wikimap/mapspro/services/editor/src/objects/line_object.h>
#include <maps/wikimap/mapspro/services/editor/src/objects/point_object.h>
#include "calc.h"
#include "generic.h"
#include "registry.h"

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

namespace maps {
namespace wiki {
namespace srv_attrs {

/*****************************************************************************/
/*                           P A R K I N G   L O T                           */
/*****************************************************************************/
class UrbanRoadnetParkingLotRegistrar: public ServiceAttributesRegistry::Registrar {
public:
    UrbanRoadnetParkingLotRegistrar(ServiceAttributesRegistry &registry):
        ServiceAttributesRegistry::Registrar(registry, CATEGORY_URBAN_ROADNET_PARKING_LOT)
    {
        registerAttr(SRV_IS_ASSIGNED_TO_ZONE,
                     CallbackWrapper<PointObject>(isAssignedToZone));
        registerAttr(SRV_HOTSPOT_LABEL,
                     CallbackWrapper<PointObject>(hotSpotLabel))
        .depends({
            {Aspect::Type::Attribute, URBAN_ROADNET_NM},
            {{RelationType::Master, ROLE_PARKING_LOT_ASSIGNED, CATEGORY_URBAN_ROADNET_PARKING_CONTROLLED_ZONE}}
        });

        // Generic callbacks.
        registerAttr(SRV_SCREEN_LABEL,
                     CallbackWrapper<PointObject>(GenericNamedObject::screenLabel));
        registerAttr(SRV_RENDER_LABEL,
                     CallbackWrapper<PointObject>(GenericNamedObject::renderLabel));
        registerSuggestCallback(SuggestCallbackWrapper<PointObject>(GenericNamedObject::suggestTexts));
    }

private:
    static std::string isAssignedToZone(const PointObject *parkingLot, ObjectsCache &) {
        return parkingLot->masterRelations().range(ROLE_PARKING_LOT_ASSIGNED).empty() ?
            SRV_ATTR_FALSE : SRV_ATTR_TRUE;
    }

    static std::string hotSpotLabel(const PointObject *parkingLot, ObjectsCache &cache) {
        const auto &zones = parkingLot->masterRelations().range(ROLE_PARKING_LOT_ASSIGNED);
        if (zones.empty()) return {};

        const auto &zone = zones.begin();
        const auto zoneName =
            objectNameByType(zone->id(), NAME_TYPE_OFFICIAL, cache) + " (" +
            cfg()->editor()->categories()[CATEGORY_URBAN_ROADNET_PARKING_CONTROLLED_ZONE].label() + ")";
        auto defaultLabel = GenericNamedObject::hotspotLabel(parkingLot, cache);

        if (defaultLabel.empty()) {
            defaultLabel = cfg()->editor()->categories()[CATEGORY_URBAN_ROADNET_PARKING_LOT].label();
        }

        if (!zoneName.empty()) {
            return zoneName + "\n" + defaultLabel;
        }

        return defaultLabel;
    }
};


/*****************************************************************************/
/*                    P A R K I N G   L O T   L I N E A R                    */
/*****************************************************************************/
class UrbanRoadnetParkingLotLinearRegistrar: public ServiceAttributesRegistry::Registrar {
public:
    UrbanRoadnetParkingLotLinearRegistrar(ServiceAttributesRegistry &registry):
        ServiceAttributesRegistry::Registrar(registry, CATEGORY_URBAN_ROADNET_PARKING_LOT_LINEAR)
    {
        registerAttr(SRV_IS_ASSIGNED_TO_ZONE,
                     CallbackWrapper<LineObject>(isAssignedToZone));
        registerAttr(SRV_HOTSPOT_LABEL,
                     CallbackWrapper<LineObject>(hotSpotLabel))
        .depends({
            {Aspect::Type::Attribute, URBAN_ROADNET_NM},
            {{RelationType::Master, ROLE_PARKING_LOT_LINEAR_ASSIGNED, CATEGORY_URBAN_ROADNET_PARKING_CONTROLLED_ZONE}}
        });
    }

private:
    static std::string isAssignedToZone(const LineObject *parkingLot, ObjectsCache &) {
        return parkingLot->masterRelations().range(ROLE_PARKING_LOT_LINEAR_ASSIGNED).empty() ?
            SRV_ATTR_FALSE : SRV_ATTR_TRUE;
    }

    static std::string hotSpotLabel(const LineObject *parkingLotLinear, ObjectsCache &cache) {
        const auto &zones = parkingLotLinear->masterRelations().range(ROLE_PARKING_LOT_LINEAR_ASSIGNED);
        if (zones.empty()) return {};

        const auto &zone = zones.begin();
        const auto zoneName =
            objectNameByType(zone->id(), NAME_TYPE_OFFICIAL, cache) + " (" +
            cfg()->editor()->categories()[CATEGORY_URBAN_ROADNET_PARKING_CONTROLLED_ZONE].label() + ")";
        const auto defaultLabel = GenericNamedObject::hotspotLabel(parkingLotLinear, cache);

        if (!zoneName.empty()) {
            return zoneName + "\n" + defaultLabel;
        }

        return defaultLabel;
    }
};


/*****************************************************************************/
/*              U R B A N   S E R V I C E   A T T R I B U T E S              */
/*****************************************************************************/
UrbanServiceAttributes::UrbanServiceAttributes(ServiceAttributesRegistry &registry) {
    UrbanRoadnetParkingLotRegistrar       parkingLot(registry);
    UrbanRoadnetParkingLotLinearRegistrar parkingLotLinear(registry);
}


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