#include "module.h"
#include "../transport-thread-common/common.h"
#include <yandex/maps/wiki/validator/check.h>
#include <yandex/maps/wiki/validator/categories.h>

#include <boost/none.hpp>

namespace maps {
namespace wiki {
namespace validator {
namespace checks {

using categories::TRANSPORT_OPERATOR;
using categories::TRANSPORT_BUS_THREAD;
using categories::TRANSPORT_TRAM_THREAD;
using categories::TRANSPORT_WATERWAY_THREAD;

using categories::TRANSPORT_BUS_ROUTE;
using categories::TRANSPORT_TRAM_ROUTE;
using categories::TRANSPORT_WATERWAY_ROUTE;

#define NOT_METRO_THREAD_CATEGORIES \
    TRANSPORT_BUS_THREAD, TRANSPORT_BUS_ROUTE, \
    TRANSPORT_TRAM_THREAD, TRANSPORT_TRAM_ROUTE, \
    TRANSPORT_WATERWAY_THREAD, TRANSPORT_WATERWAY_ROUTE

namespace {
template<typename ThreadCategory, typename RouteCategory>
void
performDuplicateImportSourceIdCheck(CheckContext* context)
{
    std::map<std::pair<std::string, std::string>, std::vector<TId>> importSourceIdToThreadId;
    context->objects<ThreadCategory>().visit(
        [&](const TransportThread* thread)
        {
            if (!isBoundToOperatorToValidate<RouteCategory>(context, thread)) {
                return;
            }
            const auto& importSourceId = thread->importSourceId();
            const auto& importSource = thread->importSource();
            if (importSourceId.empty()) {
                return;
            }
            importSourceIdToThreadId[std::make_pair(importSource, importSourceId)].push_back(thread->id());
        });
    for (const auto& pair : importSourceIdToThreadId) {
        const auto& sameImportSourceIdThreads = pair.second;
        if (sameImportSourceIdThreads.size() < 2) {
            continue;
        }
        context->fatal("transport-thread-duplicate-import-source-id",
            boost::none, sameImportSourceIdThreads);
    }
}

template<typename... Categories>
struct Performer;
template<>
struct Performer<>
{
    Performer(CheckContext*){};
};

template<typename ThreadCategory, typename RouteCategory, typename... Categories>
struct Performer<ThreadCategory, RouteCategory, Categories...> : public Performer<Categories...>
{
    Performer(CheckContext* context)
        : Performer<Categories...>(context)
    {
        performDuplicateImportSourceIdCheck<ThreadCategory, RouteCategory>(context);
    }

};
}//namespace

VALIDATOR_CHECK_PART(transport_thread_attributes, unique_import_source,
    NOT_METRO_THREAD_CATEGORIES, TRANSPORT_OPERATOR)
{
    Performer<NOT_METRO_THREAD_CATEGORIES> check(context);
}


} // namespace checks
} // namespace validator
} // namespace wiki
} // namespace maps
