#pragma once

#include "data.hpp"
#include "../data/mem.hpp"

namespace net {

//TODO: preallocate static data pool

/// Helper to write allocated packets
class PacketWriter final: public data::in_writer {
public:
    PacketWriter(size_t size): data::in_writer(size) { }
    PacketWriter(uint8_t type, size_t data_size): PacketWriter(sizeof(type) + data_size) {
        write(type);
    }
    PacketWriter(net::client_packet_type type, size_t data_size): PacketWriter((uint8_t)type, data_size) { }
    PacketWriter(net::server_packet_type type, size_t data_size): PacketWriter((uint8_t)type, data_size) { }

    [[nodiscard]]
    data::out_buffer finish() {
        assert(isFull());
        return data::out_buffer(*this);
    }

    [[nodiscard]]
    static data::out_buffer Of(net::client_packet_type type, const void* data, size_t size) {
        auto packet = PacketWriter(type, size);
        packet.write(data, size);
        return packet.finish();
    }
    [[nodiscard]]
    static data::out_buffer Of(net::server_packet_type type, const void* data, size_t size) {
        auto packet = PacketWriter(type, size);
        packet.write(data, size);
        return packet.finish();
    }
    template<typename D>
    [[nodiscard]]
    static data::out_buffer Of(net::client_packet_type type, const D& data) {
        return Of(type, &data, sizeof(data));
    }
    template<typename D>
    [[nodiscard]]
    static data::out_buffer Of(net::server_packet_type type, const D& data) {
        return Of(type, &data, sizeof(data));
    }
};

/// Helper to read out_view
class PacketReader final: public data::out_reader {
public:
    PacketReader(const data::out_view& buf): data::out_reader(buf) { }
};

}