#ifndef NETWORK_PACKET_H
#define NETWORK_PACKET_H

#include <cstdint>
#include <memory>
#include "core/types.h"
#include "core/node.h"

namespace dofs {

inline const std::size_t MAX_GROUPS = 128;

inline Bytes HEADER_SIZE_BYTES   = 64;
inline Bytes ACK_SIZE_BYTES      = 64;
inline Bytes DEFAULT_MTU_BYTES   = 4160;
inline Bytes DEFAULT_MSS_BYTES   = 4096;

class Packet {
public:
        Packet(NodeId src_node,
               PortId src_port,
               NodeId dst_node,
               PortId dst_port,
               PacketProtocol proto,
               FlowPriority prio,
               PacketSeq seq = 0,
               FlowId flow = 0,
               uint16_t entropy = 0,
               uint8_t notifications = 0,
               Bytes payload_bytes = DEFAULT_MSS_BYTES) noexcept;

        NodeId         src_node() const noexcept;
        PortId         src_port() const noexcept;
        NodeId         dst_node() const noexcept;
        PortId         dst_port() const noexcept;
        PacketProtocol protocol() const noexcept;
        PacketSeq      seq() const noexcept;
        FlowId         flow_id() const noexcept;
        uint32_t       entropy() const noexcept;

        void set_src_node(NodeId n) noexcept;
        void set_src_port(PortId p) noexcept;
        void set_dst_node(NodeId n) noexcept;
        void set_dst_port(PortId p) noexcept;
        void set_seq(PacketSeq s) noexcept;
        void set_flow_id(FlowId f) noexcept;
        void set_entropy(uint32_t e) noexcept;
        void set_protocol(PacketProtocol p) noexcept;

        void set_payload_size(Bytes size) noexcept;

        void set_ecn_enabled(bool v) noexcept;
        void set_ecn_marked(bool v) noexcept;
        // end of flow
        void set_eof(bool v) noexcept;

        bool is_ecn_enabled() const noexcept;
        bool is_ecn() const noexcept;
        bool is_eof() const noexcept;

        FlowPriority priority() const noexcept;
        uint8_t      priority_raw() const noexcept;

        Bytes header_size() const noexcept;
        Bytes payload_size() const noexcept;
        Bytes total_size() const noexcept;

        PacketGroups groups() const noexcept;
        void set_groups(PacketGroups g) noexcept;
        void add_groups(PacketGroups gmask) noexcept;

private:
        NodeId   _src_node;
        PortId   _src_port;
        NodeId   _dst_node;
        PortId   _dst_port;

        PacketProtocol _protocol;
        PacketSeq      _seq;
        FlowId         _flow;
        uint16_t       _entropy;

        Bytes        _payload_size;
        PacketGroups _groups;

        uint8_t  _notifications;

        static constexpr uint8_t ECN_ENABLED_MASK = 0x01;
        static constexpr uint8_t ECN_MARK_MASK    = 0x02;
        static constexpr uint8_t EOF_MASK         = 0x04;
        static constexpr uint8_t PRIORITY_MASK    = 0x18;
        static constexpr uint8_t PRIORITY_SHIFT   = 3;
};

} // namespace dofs

#endif // NETWORK_PACKET_H
