/*
   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 <types.h>
#include <printf.h>
#include <uart.hpp>

#include "../kernel.h"

bool EnableProfiler = false;
bool Wait = false;
unsigned long long LogDepth = 0;
unsigned int Level = 0;
using namespace UniversalAsynchronousReceiverTransmitter;

static inline SafeFunction NIF void profiler_uart_wrapper(char c, void *unused)
{
    bool renable = EnableProfiler;
    EnableProfiler = false;
    UART(COM2).Write(c);
    UNUSED(unused);
    if (renable)
        EnableProfiler = true;
}

EXTERNC SafeFunction NIF void __cyg_profile_func_enter(void *Function, void *CallSite)
{
    if (!EnableProfiler)
        return;

    while (Wait)
#if defined(a64) || defined(a32)
        asmv("pause");
#elif defined(aa64)
        asmv("yield");
#endif
    Wait = true;

    if (Level > 40)
        Level--;

    Level++;

    if (!KernelSymbolTable)
        fctprintf(profiler_uart_wrapper, nullptr, "%lld [%02d]: \033[42m->\033[0m%*c \033[33m%p\033[0m  -  \033[33m%p\033[0m\n",
                  LogDepth++,
                  Level - 1,
                  Level,
                  ' ',
                  Function,
                  CallSite);
    else
        fctprintf(profiler_uart_wrapper, nullptr, "%lld [%02d]: \033[42m->\033[0m%*c \033[33m%s\033[0m  -  \033[33m%s\033[0m\n",
                  LogDepth++,
                  Level - 1,
                  Level,
                  ' ',
                  KernelSymbolTable->GetSymbolFromAddress((uintptr_t)Function),
                  KernelSymbolTable->GetSymbolFromAddress((uintptr_t)CallSite));
    Wait = false;
}

EXTERNC SafeFunction NIF void __cyg_profile_func_exit(void *Function, void *CallSite)
{
    if (!EnableProfiler)
        return;

    while (Wait)
#if defined(a64) || defined(a32)
        asmv("pause");
#elif defined(aa64)
        asmv("yield");
#endif
    Wait = true;

    if (Level > 40)
        Level--;

    Level--;

    if (!KernelSymbolTable)
        fctprintf(profiler_uart_wrapper, nullptr, "%lld [%02d]: \033[41m<-\033[0m%*c \033[33m%p\033[0m  -  \033[33m%p\033[0m\n",
                  LogDepth++,
                  Level - 1,
                  Level,
                  ' ',
                  Function,
                  CallSite);
    else
        fctprintf(profiler_uart_wrapper, nullptr, "%lld [%02d]: \033[41m<-\033[0m%*c \033[33m%s\033[0m  -  \033[33m%s\033[0m\n",
                  LogDepth++,
                  Level - 1,
                  Level,
                  ' ',
                  KernelSymbolTable->GetSymbolFromAddress((uintptr_t)Function),
                  KernelSymbolTable->GetSymbolFromAddress((uintptr_t)CallSite));
    Wait = false;
}