/*
   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/>.
*/

#include <net/ntp.hpp>
#include <debug.h>

#include "../kernel.h"

namespace NetworkNTP
{
    void NTP::OnUDPPacketReceived(NetworkUDP::Socket *Socket, uint8_t *Data, uint64_t Length)
    {
        UNUSED(Socket);
        UNUSED(Length);
        this->NTPPacket = *(NTPHeader *)Data;
        this->TimeReceived = true;
        netdbg("Received UDP packet for NTP.");
    }

    NTP::NTP(NetworkUDP::Socket *Socket) : NetworkUDP::UDPEvents()
    {
        debug("NTP interface %#lx created.", this);
        this->UDPSocket = Socket;
    }

    NTP::~NTP()
    {
        debug("NTP interface %#lx destroyed.", this);
    }

    int NTP::ReadTime()
    {
        netdbg("Requesting time");
        this->TimeReceived = false;

        NTPHeader ReqPacket;                      // This may require phyiscal memory allocation but Ethernet already has this job.
        memset(&ReqPacket, 0, sizeof(NTPHeader)); // Zero out the packet
        *((char *)&ReqPacket) = 0x1b;             // byteswap nightmare, this is the code below but in little endian
        // ReqPacket.LeapIndicator = 0;
        // ReqPacket.VersionNumber = 3;
        // ReqPacket.Mode = 3;
        UDPSocket->SocketUDP->Send(UDPSocket, (uint8_t *)&ReqPacket, sizeof(NTPHeader));

        debug("Waiting for response...");
        int RequestTimeout = 20;
        while (!this->TimeReceived)
        {
            if (--RequestTimeout == 0)
            {
                warn("Request timeout.");
                return 0;
            }
            netdbg("Still waiting...");
            TaskManager->Sleep(1000);
        }

        long UnixTimestamp = b32(this->NTPPacket.TransmitTimestamp[0]) - 2208988800;
        debug("Unix time: %d", UnixTimestamp);
        return s_cst(int, UnixTimestamp);
    }
}