#pragma once

#include <balancer/production/x/okula/apps/common/pcap.h>
#include <util/generic/string.h>

#include <memory>

struct IPcapOptions;

void RunMain(int argc, const char** argv);
void RunFileSplitter(const TString& filePath,
                     const TString& outputDir,
                     int depth);

void RunYtSplitter(const TString& filePath,
                   const TString& clusterName,
                   const TString& tableName);

template <typename T>
class TClientWorker final {
private:
    std::unique_ptr<TPcap> Pcap_{nullptr};
    std::unique_ptr<TPcapFilter> Filter_{nullptr};
    std::unique_ptr<T> DumperInstance_{nullptr};

private:
    TClientWorker(
        std::unique_ptr<TPcap> pcap,
        std::unique_ptr<TPcapFilter> filter,
        std::unique_ptr<T> dumperInstance)
        : Pcap_(std::move(pcap))
        , Filter_(std::move(filter))
        , DumperInstance_(std::move(dumperInstance)){};

    void ProcessPacket(const TPcapPacketHeader* pktHdr, const unsigned char* packet);
public:
    static std::unique_ptr<TClientWorker<T>> CreateWorker(const TString& filePath, const TString& filter, IPcapOptions& options);

    TClientWorker(const TClientWorker& that) = delete;
    TClientWorker& operator=(const TClientWorker& that) = delete;

    void Start();
};

class TMultiFrame {
private:
    int AFInet_ = -1;
    ui8 Proto_ = 0;
    unsigned char* SrcAdr_ = nullptr;
    unsigned char* DstAdr_ = nullptr;
    ui16 SrcPort_ = 0;
    ui16 DstPort_ = 0;

public:
    void AFInet(int afInet) {
        AFInet_ = afInet;
    }

    int AFInet() const {
        return AFInet_;
    }

    void Proto(ui8 proto) {
        Proto_ = proto;
    }

    ui8 Proto() {
        return Proto_;
    }

    void SrcAdr(unsigned char* adr) {
        SrcAdr_ = adr;
    }

    unsigned char* SrcAdr() const {
        return SrcAdr_;
    }

    void DstAdr(unsigned char* adr) {
        DstAdr_ = adr;
    }

    unsigned char* DstAdr() const {
        return DstAdr_;
    }

    void SrcPort(ui16 port) {
        SrcPort_ = port;
    }

    ui16 SrcPort() const {
        return SrcPort_;
    }

    void DstPort(ui16 port) {
        DstPort_ = port;
    }

    ui16 DstPort() const {
        return DstPort_;
    }
};
