/*
    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 <time.hpp>
#include <debug.h>
#include <io.h>

namespace Time
{
    Clock ReadClock()
    {
        Clock tm;
#if defined(a86)
        uint32_t t = 0;
        outb(0x70, 0x00);
        t = inb(0x71);
        tm.Second = ((t & 0x0F) + ((t >> 4) * 10));
        outb(0x70, 0x02);
        t = inb(0x71);
        tm.Minute = ((t & 0x0F) + ((t >> 4) * 10));
        outb(0x70, 0x04);
        t = inb(0x71);
        tm.Hour = ((t & 0x0F) + ((t >> 4) * 10));
        outb(0x70, 0x07);
        t = inb(0x71);
        tm.Day = ((t & 0x0F) + ((t >> 4) * 10));
        outb(0x70, 0x08);
        t = inb(0x71);
        tm.Month = ((t & 0x0F) + ((t >> 4) * 10));
        outb(0x70, 0x09);
        t = inb(0x71);
        tm.Year = ((t & 0x0F) + ((t >> 4) * 10));
        tm.Counter = 0;
#elif defined(aa64)
        tm.Year = 0;
        tm.Month = 0;
        tm.Day = 0;
        tm.Hour = 0;
        tm.Minute = 0;
        tm.Second = 0;
        tm.Counter = 0;
#endif
        return tm;
    }

    Clock ConvertFromUnix(int Timestamp)
    {
        Clock result;

        uint64_t Seconds = Timestamp;
        uint64_t Minutes = Seconds / 60;
        uint64_t Hours = Minutes / 60;
        uint64_t Days = Hours / 24;

        result.Year = 1970;
        while (Days >= 365)
        {
            if (result.Year % 4 == 0 &&
                (result.Year % 100 != 0 ||
                 result.Year % 400 == 0))
            {
                if (Days >= 366)
                {
                    Days -= 366;
                    result.Year++;
                }
                else
                    break;
            }
            else
            {
                Days -= 365;
                result.Year++;
            }
        }

        int DaysInMonth[] = {31,
                             result.Year % 4 == 0
                                 ? 29
                                 : 28,
                             31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
        for (result.Month = 0; result.Month < 12; result.Month++)
        {
            if (Days < s_cst(uint64_t, (DaysInMonth[result.Month])))
                break;
            Days -= DaysInMonth[result.Month];
        }
        result.Month++;

        result.Day = s_cst(int, (Days) + 1);
        result.Hour = s_cst(int, (Hours % 24));
        result.Minute = s_cst(int, (Minutes % 60));
        result.Second = s_cst(int, (Seconds % 60));
        result.Counter = s_cst(uint64_t, (Timestamp));
        return result;
    }
}