#include "calc.h"

#include <util/digest/city.h>
#include <util/string/cast.h>
#include <util/string/strip.h>

namespace NModExpStatic {

    TExp CalcExpByIp(
        const TExpConf& conf, const TExpRate& rate, const TString& combinedSalt, const TIpAddr& remoteAddr) noexcept
    {
        const auto digest = CityHash128(combinedSalt + remoteAddr.GetRawBytes());
        const double expRate = conf.SlotsCount * rate.Value;
        const double contRate = expRate * 2;
        const ui64 slot = digest.first % conf.SlotsCount;

        TExp exp;
        exp.Bucket = digest.second % conf.BucketsCount;

        if (slot < expRate) {
            exp.Id = conf.ExpId;
            exp.Type = ESlotType::Exp;
        } else if (slot < contRate) {
            exp.Id = conf.ContId;
            exp.Type = ESlotType::Cont;
        }

        return exp;
    }

    TString GenCombinedSalt(const TExpConf& conf, const TExpRate& rate) noexcept {
        return conf.Salt + rate.ValueStr + rate.ExtraSalt;
    }
}

template <>
NModExpStatic::TExpRate FromStringImpl<NModExpStatic::TExpRate, char>(const char* s, size_t len) {
    using namespace NModExpStatic;
    TExpRate res;
    TStringBuf str(s, len);
    TStringBuf rate = StripString(str.NextTok(','));
    res.Value = FromString<double>(rate);
    res.ValueStr = rate;
    res.ExtraSalt = StripString(str);
    return res;
}

template <>
void Out<NModExpStatic::TExpRate>(IOutputStream& out, const NModExpStatic::TExpRate& rate) {
    out << rate.Value;
    if (rate.ExtraSalt) {
        out << "," << rate.ExtraSalt;
    }
}
