#include "by_hash.h"

#include <balancer/kernel/balancer/algorithm.h>
#include <balancer/kernel/balancing/backend.h>
#include <balancer/modules/balancer/policies/policy_factory.h>

namespace NSrvKernel::NByHash {

class TConnDescrHashProcessor final : public IHashProcessor {
public:
    TConnDescrHashProcessor(NSrvKernel::TRequestHash hash) noexcept
        : Hash_(hash)
    {}

    bool Has() const noexcept override {
        return Hash_ != 0;
    }

    TRequestHash Get() noexcept override {
        return Hash_;
    }

    void Set(TRequestHash) noexcept override {}

private:
    NSrvKernel::TRequestHash Hash_;
};

IBackend* TByHashPolicy::Next(IAlgorithm* algo, bool fastAttempt) noexcept {
    if (First_) {
        First_ = false;
        TConnDescrHashProcessor hasher(Descr_.Hash);
        IBackend* backend = algo->NextByHash(hasher);
        if (backend) {
            algo->RemoveSelected(backend);
            return backend;
        }
    }

    return Slave_->Next(algo, fastAttempt);
}


POLICY_FACTORY_BASE(by_hash_policy, TPolicyFactoryWithSlave), public TModuleParams {
    TPolicyFactory(const TModuleParams& mp)
        : TModuleParams(mp)
    {
        mp.Config->ForEach(this);
        CheckConfiguration();
    }

    THolder<IPolicy> ConstructPolicy(const TStepParams& params) noexcept override {
        return MakeHolder<TByHashPolicy>(TPolicyBase::ConstructPolicy(params), params);
    }

    void FillFeatures(TPolicyFeatures& features) const noexcept override {
        features.WantsHash = true;
        TPolicyBase::FillFeatures(features);
    }

private:
    START_PARSE {
        if (Configure(key, Copy(value->AsSubConfig()))) {
            return;
        }
    } END_PARSE
};

INodeHandle<IPolicyFactory>* Handle() {
    return TPolicyFactory::Handle();
}

}  // namespace NSrvKernel::NByHash
