#include "by_name.h"

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

namespace NSrvKernel::NByName {

IBackend* TByNamePolicy::Next(IAlgorithm* algo, bool fastAttempt) noexcept {
    if (First_) {
        First_ = false;
        IBackend* backend = algo->NextByName(Name_, Opts_.AllowZeroWeights);
        if (backend) {
            algo->RemoveSelected(backend);
            return backend;
        }
    }

    if (Opts_.Strict) {
        return nullptr;
    }

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


bool TByNamePolicyFactoryBase::ConsumeOpts(const TString& key, NConfig::IConfig::IValue* value) {
    ON_KEY("strict", Opts_.Strict) {
        return true;
    }

    ON_KEY("allow_zero_weights", Opts_.AllowZeroWeights) {
        return true;
    }

    return false;
}

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

        if (!Name_) {
            ythrow TConfigParseError{} << "balancer2/by_name_policy: no \"name\" specified";
        }
    }

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

private:
    START_PARSE {
        ON_KEY("name", Name_) {
            return;
        }

        if (ConsumeOpts(key, value)) {
            return;
        }

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

private:
    TString Name_;
};

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

}  // namespace NSrvKernel::NByName
