/*
   This file is part of Fennix Kernel.

   Fennix Kernel is free software: you can redistribute it and/or
   modify it under the terms of the GNU General Public License as
   published by the Free Software Foundation, either version 3 of
   the License, or (at your option) any later version.

   Fennix Kernel is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/

#ifndef __FENNIX_KERNEL_UDP_H__
#define __FENNIX_KERNEL_UDP_H__

#include <net/ipv4.hpp>
#include <net/udp.hpp>
#include <net/nc.hpp>
#include <types.h>

namespace NetworkUDP
{
    struct UDPHeader
    {
        uint16_t SourcePort;
        uint16_t DestinationPort;
        uint16_t Length;
        uint16_t Checksum;
    } __packed;

    struct UDPPacket
    {
        UDPHeader Header;
        uint8_t Data[];
    };

    class Socket;

    class UDPEvents
    {
    protected:
        UDPEvents();
        ~UDPEvents();

    public:
        virtual void OnUDPPacketReceived(Socket *Socket, uint8_t *Data, size_t Length)
        {
            UNUSED(Socket);
            UNUSED(Data);
            UNUSED(Length);
            warn("Not implemented.");
        }
    };

    class UDP : public NetworkIPv4::IPv4Events
    {
    private:
        NetworkIPv4::IPv4 *ipv4;
        NetworkInterfaceManager::DeviceInterface *Interface;

    public:
        NetworkInterfaceManager::DeviceInterface *GetInterface() { return this->Interface; }

        UDP(NetworkIPv4::IPv4 *ipv4, NetworkInterfaceManager::DeviceInterface *Interface);
        ~UDP();

        virtual Socket *Connect(InternetProtocol IP, uint16_t Port);
        virtual Socket *Listen(uint16_t Port);
        virtual void Disconnect(Socket *Socket);
        virtual void Send(Socket *Socket, uint8_t *Data, size_t Length);
        virtual void Bind(Socket *Socket, UDPEvents *EventHandler);

        virtual bool OnIPv4PacketReceived(InternetProtocol SourceIP, InternetProtocol DestinationIP, uint8_t *Data, size_t Length);
    };

    class Socket
    {
    public:
        InternetProtocol LocalIP;
        uint16_t LocalPort = 0;
        InternetProtocol RemoteIP;
        uint16_t RemotePort = 0;
        bool Listening = false;
        UDPEvents *EventHandler = nullptr;
        UDP *SocketUDP = nullptr;

        Socket(UDP *_UDP);
        ~Socket();
    };
}

#endif // !__FENNIX_KERNEL_UDP_H__