#include "duplicates_check_common.h"

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

using categories::RD_EL;
using categories::RD_JC;
using categories::COND_TOLL;

namespace {
const size_t VISIT_BATCH_SIZE = 1000;
} // namespace

template<>
bool equal(const CondToll& left, const CondToll& right)
{
    return left.viaJunction() == right.viaJunction();
};

VALIDATOR_CHECK_PART( cond_toll, cond_toll_duplicates, COND_TOLL, RD_JC )
{
    ConditionAccumulator<COND_TOLL>(context).checkDuplicates("duplicate-cond-toll");
}

VALIDATOR_CHECK_PART( cond_toll, cond_toll_topo, COND_TOLL, RD_EL, RD_JC )
{
    context->objects<COND_TOLL>().batchVisit(
        [&](const COND_TOLL::TObject* condToll) {
            if (!context->objects<RD_JC>().loaded(condToll->viaJunction())) {
                // CondToll out of AOI
                return;
            };
            if (!context->objects<RD_EL>().loaded(condToll->fromRoadElement())) {
                return;
            }
            const auto jcId = condToll->viaJunction();
            const auto& element = context->objects<RD_EL>().byId(condToll->fromRoadElement());
            if (element->startJunction() != jcId &&
                element->endJunction() != jcId) {
                context->critical(
                        "cond-toll-is-not-topologically-valid",
                        context->objects<RD_JC>().byId(jcId)->geom(),
                        { condToll->id(), jcId });
            }
        },
        VISIT_BATCH_SIZE);
}

VALIDATOR_CHECK_PART( cond_toll, cond_toll_logic, COND_TOLL, RD_EL, RD_JC )
{
    context->objects<COND_TOLL>().batchVisit(
        [&](const COND_TOLL::TObject* condToll) {
            if (!context->objects<RD_JC>().loaded(condToll->viaJunction())) {
                // CondToll out of AOI
                return;
            };
            auto hasTollElements = [&](const std::vector<TId>& elements) {
                for (const auto elementId : elements) {
                    if (!context->objects<RD_EL>().loaded(elementId)) {
                        continue;
                    }
                    const auto rdEl = context->objects<RD_EL>().byId(elementId);
                    if (rdEl->toll()) {
                        return true;
                    }
                }
                return false;
            };
            const auto jcId = condToll->viaJunction();
            const auto junction = context->objects<RD_JC>().byId(jcId);
            if (!hasTollElements(junction->inElements()) &&
                !hasTollElements(junction->outElements())) {
                context->critical(
                        "cond-toll-is-not-toll-road",
                        junction->geom(),
                        { condToll->id(), jcId });
            }
        },
        VISIT_BATCH_SIZE);
}

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