#include "FreeRTOS.h"
#include "semphr.h"
#include "task.h"

// TODO namespace the names

SemaphoreHandle_t global_threading_semaphore = NULL;

uint8_t global_threading_available_c() {
  if (global_threading_semaphore == NULL) {
    
    global_threading_semaphore = xSemaphoreCreateBinary();
    //xSemaphoreGive(global_threading_semaphore);
  }
  if (uxSemaphoreGetCount(global_threading_semaphore) == 1) {
    return 1;
  } else {
    return 0;
  }
}

void enable_global_threading_c() {
  xSemaphoreGive(global_threading_semaphore);
}

void disable_global_threading_c() {
  xSemaphoreTake(global_threading_semaphore, portMAX_DELAY);
}

const char *get_task_name() { return pcTaskGetName(NULL); }

void stop_it() { taskENTER_CRITICAL(); }

// TODO return some error code?
void *create_task(TaskFunction_t taskFunction, void *parameter,
                  uint32_t stack_size) {
  //TODO verify uint32_t vs configSTACK_DEPTH_TYPE
  TaskHandle_t newTask;
  BaseType_t result =
      xTaskCreate(taskFunction, "rust", stack_size, parameter, 4, &newTask);
  if (result == pdTRUE) {
    return newTask;
  } else {
    return NULL;
  }
}

void task_delay(uint32_t milliseconds) {
  //TODO verify uint32_t vs TickType_t
  vTaskDelay(pdMS_TO_TICKS(milliseconds));
}

void delete_task(void * task){
  vTaskSuspend(task); //we can not use vDeleteTask as it would free the allocated memory which is forbidden using heap1 (which we use)
}

void *create_queue(uint32_t length, uint32_t element_size) {
  //TODO verify uint32_t vs UBaseType_t
  QueueHandle_t newQueue = xQueueCreate(length, element_size);
  return newQueue;
}

uint8_t queue_receive(void *queue, void *message) {
  if (xQueueReceive(queue, message, 0) == pdPASS) {
    return 1;
  } else {
    return 0;
  }
}

uint8_t queue_send(void *queue, void *message) {
  if (xQueueSend(queue, message, 0) != pdPASS) {
    return 1;
  } else {
    return 0;
  }
}

void *create_mutex() {
  return xSemaphoreCreateRecursiveMutex();
}

uint8_t take_mutex(void * handle) {
  // TODO check if global semaphore is free (ie, we are doing multitasking)
  // if not, pointers are invalid, bail out
  if (xSemaphoreTakeRecursive(handle, portMAX_DELAY) == pdPASS) {
    return 1;
  } else {
    return 0;
  }
}

uint8_t give_mutex(void * handle) {
  // TODO check if global semaphore is free (ie, we are doing multitasking)
  // if not, pointers are invalid, bail out
  if (xSemaphoreGiveRecursive(handle) == pdPASS) {
    return 1;
  } else {
    return 0;
  }
}