#include "routeslist.h"

#include <saas/library/behaviour/behaviour.h>

#include <util/generic/algorithm.h>
#include <util/generic/yexception.h>
#include <util/system/defaults.h>

using namespace NSearchMapParser;

class THostSelector: public ISearchMapProcessor {
public:
    enum EMode {
        BROADCAST, SHARD
    };
public:
    THostSelector(TRoutesList& routes, TRoutesList& ignoreRoutes, EMode mode, TShardIndex shard)
        : Routes(routes)
        , IgnoreRoutes(ignoreRoutes)
        , Mode(mode)
        , Shard(shard)
    {}

    void Do(const TServiceSpecificOptions& options, const TReplicaSpecificOptions& rso, const TInterval<TShardIndex>& /*interval*/, const TSearchInformation& si) override {
        if (options.ShardsDispatcher->CheckInterval(Shard, si.Shards) || Mode == BROADCAST) {
            if (si.IsSd) {
                return;
            } else if (rso.DisableIndexing || si.DisableIndexing) {
                IgnoreRoutes.insert(TComparableAddress(si.Name, si.IndexerPort));
            } else {
                Routes.insert(TComparableAddress(si.Name, si.IndexerPort));
            }
        }
    }

private:
    TRoutesList& Routes;
    TRoutesList& IgnoreRoutes;
    EMode Mode;
    TShardIndex Shard;
};

TShardIndex GetShard(const NSearchMapParser::TServiceSpecificOptions& options, const NRTYServer::TMessage& message) {
    return options.ShardsDispatcher->GetShard(message);
}

TRoutesList GetRoutesList(const NSearchMapParser::TSearchCluster& unifiedService,
    const ISrvDispContext& dispMessage, TRoutesList& ignoreRoutes)
{
    // element presence was enforced by verifier
    TRoutesList result;
    const NRTYServer::TMessage& message = dispMessage.GetMessage();

    TShardIndex shard = 0;
    THostSelector::EMode mode = THostSelector::SHARD;
    if (GetBehaviour(message.GetMessageType()).IsBroadcastMessage ||
        IsQueryProcessorMessage(message.GetMessageType(), message.GetDocument()))
    {
        mode = THostSelector::BROADCAST;
    } else {
        shard = GetShard(unifiedService, message);
    }

    THostSelector selector(result, ignoreRoutes, mode, shard);
    unifiedService.ProcessSearchMap(selector);

    return result;
}

