#include "subnet.h"
#include "hasher.h"

#include <balancer/kernel/module/iface.h>

#include <balancer/modules/hasher/lib/calc_hash.h>

#include <library/cpp/digest/old_crc/crc.h>

#include <util/generic/strbuf.h>
#include <util/network/address.h>
#include <util/stream/file.h>
#include <util/system/byteorder.h>

#include <cstring>

using namespace NSrvKernel;
using namespace NModHasher;

HASHER(subnet) {
public:
    THasher(const TModuleParams& mp) {
        mp.Config->ForEach(this);
    }

    TErrorOr<ui64> CalcHash(const TConnDescr& descr) const noexcept override {
        return CalcHashSubnet(descr, IpFsm_.Get(), V4Mask_, V6Mask_);
    }

private:
    START_PARSE {
        TString takeIpFrom;
        ON_KEY("take_ip_from", takeIpFrom) {
            IpFsm_.Reset(new TFsm(takeIpFrom, TFsm::TOptions().SetCaseInsensitive(true)));
            return;
        }

        ON_KEY("subnet_v4_mask", V4Mask_) {
            if (V4Mask_ == 0 || V4Mask_ > 32) {
                ythrow TConfigParseError() << "invalid IPv4 subnet mask " << V4Mask_;
            }
            return;
        }

        ON_KEY("subnet_v6_mask", V6Mask_) {
            if (V6Mask_ == 0 || V6Mask_ > 128) {
                ythrow TConfigParseError() << "invalid IPv6 subnet mask " << V6Mask_;
            }
            return;
        }

        return;
    } END_PARSE

private:
    THolder<TFsm> IpFsm_;
    unsigned V4Mask_ = 16;
    unsigned V6Mask_ = 64;
};

INodeHandle<IHasher>* NModHasher::NSubnet::Handle() {
    return THasher::Handle();
}
