#include "Abstraction/Include/OS_Interface.h"
#include "Config/Include/SYS_Config.h"
#include "Kernel.h"

typedef struct
{
	uint8_t     	src_task_id;
	uint8_t     	target_task_id;
	uint16_t    	event_code;
	uint32_t    	data_size;
	void *    		data_buffer;
} OS_Message;

static OS_Error os_error(uint32_t status)
{
    if(KERN_STATUS_INVALID_MSG == status)
    {
        return OS_ERROR_QUEUE;
    }
    else if(KERN_STATUS_QUEUE_FULL == status)
    {
        return OS_ERROR_FULL;
    }
    else if(KERN_STATUS_TIMEOUT == status)
    {
        return OS_ERROR_TIMEOUT;
    }
    else if(KERN_STATUS_SUCCESS == status)
    {
        return OS_ERROR_OK;
    }
    else
    {
        return OS_ERROR_UNKNOWN;
    }
}

static void task_proc(void* parameter)
{
    KERN_Status status_code = KERN_STATUS_SUCCESS;
    OS_Message message = { 0 };

    const OS_TaskParam* param = (OS_TaskParam*)(parameter);

    if(param->task_init)
    {
        param->task_init();
    }

    while(1)
    {
        status_code = KERN_rcvMsg(param->queue_id, &message, param->wait_time);

        if(status_code == KERN_STATUS_SUCCESS)
        {
            if(param->recv_msg)
            {
                param->recv_msg(message.event_code, message.data_buffer, message.data_size);
            }

            if(NULL != message.data_buffer)
            {
                KERN_free(message.data_buffer);
            }
        }
        else if(status_code == KERN_STATUS_TIMEOUT)
        {
            if(param->time_out)
            {
                param->time_out();
            }
        }

        if(param->loop)
        {
            param->loop();
        }
    }
}

void OS_init()
{
    SYS_Init();
}

void OS_start()
{
    KERN_start();
}

void OS_createTask(OS_TaskConfig* config)
{
    if(NULL != config)
    {
        KERN_createTask(task_proc, config->name, config->task_id, config->stack_depth, config->priority, config->get_param());
    }
}

void OS_createQueue(OS_QueueConfig* config)
{
    if(NULL != config)
    {
        KERN_createQueue(config->id, config->length, sizeof(OS_Message));
    }
}

void OS_sleep(uint32_t milliseconds)
{
    KERN_sleep(milliseconds);
}

uint32_t OS_getCurrentTime()
{
    return KERN_getCurrentTime();
}

void* OS_malloc(size_t size)
{
    return KERN_malloc(size);
}

void OS_free(void * mem)
{
    if(NULL != mem)
    {
        KERN_free(mem);
    }
}

void* OS_createLock()
{
    return KERN_createMutex();
}

void OS_destroyLock(void* mutex)
{
    KERN_destroyMutex(mutex);
}

void OS_lock(void* mutex)
{
    KERN_lock(mutex);
}

void OS_unlock(void* mutex)
{
    KERN_unlock(mutex);
}

void* OS_createSemaphore(const uint8_t init_value)
{
    return KERN_createSemaphore(init_value);
}

void OS_destroySemaphore(void* semaphore)
{
    KERN_destroySemaphore(semaphore);
}

void OS_wait(void* semaphore, uint32_t milliseconds)
{
    KERN_wait(semaphore, milliseconds);
}

void OS_post(void* semaphore)
{
    KERN_post(semaphore);
}

void OS_createTimer(uint8_t id, uint32_t milliseconds, uint8_t reload, TIMERPROC callback)
{
    KERN_registerTimer(id, milliseconds, reload, callback);
}

void OS_destroyTimer(uint8_t id)
{
    KERN_releaseTimer(id);
}

void OS_startTimer(uint8_t id)
{
    KERN_startTimer(id);
}

void OS_stopTimer(uint8_t id)
{
    KERN_stopTimer(id);
}

void OS_resetTimer(uint8_t id)
{
    KERN_resetTimer(id);
}

void OS_changeTimer(uint8_t id, uint32_t milliseconds, TIMERPROC callback)
{
    KERN_changeTimer(id, milliseconds, callback);
}

OS_Error OS_sndMsg(uint8_t queue_id, uint16_t event_code, void * data_buffer, uint32_t data_size, uint32_t milliseconds)
{    
    OS_Message message =
    {
        .event_code = event_code,
    };

    if((NULL != data_buffer) && (0 != data_size))
    {
        void * target = KERN_malloc(data_size);

        if(NULL != target)
        {
            memcpy(target, data_buffer, data_size);

            message.data_buffer = target;
            message.data_size = data_size;
        }
        else
        {
            return OS_ERROR_MEMORY;
        }
    }

    int32_t status_code = KERN_sndMsg(queue_id, &message, milliseconds);

    if(KERN_STATUS_SUCCESS != status_code)
    {
        if(NULL != message.data_buffer)
        {
            KERN_free(message.data_buffer);
        }

        return os_error(status_code);
    }

    return OS_ERROR_OK;
}

OS_Error OS_sndMsgFromISR(uint8_t queue_id, uint16_t event_code)
{
    OS_Message message =
    {
        .event_code = event_code,
    };

    int32_t status_code = KERN_sndMsgFromISR(queue_id, &message);

    if(KERN_STATUS_SUCCESS != status_code)
    {
        return os_error(status_code);
    }

    return OS_ERROR_OK;
}

OS_Error OS_sndMsgToFront(uint8_t queue_id, uint16_t event_code, void * data_buffer, uint32_t data_size, uint32_t milliseconds)
{
    OS_Message message =
    {
        .event_code = event_code,
    };

    if((NULL != data_buffer) && (0 != data_size))
    {
        void * target = KERN_malloc(data_size);

        if(NULL != target)
        {
            memcpy(target, data_buffer, data_size);

            message.data_buffer = target;
            message.data_size = data_size;
        }
        else
        {
            return OS_ERROR_MEMORY;
        }
    }

    int32_t status_code = KERN_sndMsgToFront(queue_id, &message, milliseconds);

    if(KERN_STATUS_SUCCESS != status_code)
    {
        if(NULL != message.data_buffer)
        {
            KERN_free(message.data_buffer);
        }

        return os_error(status_code);
    }

    return OS_ERROR_OK;
}

OS_Error OS_sndMsgToFrontFromISR(uint8_t queue_id, uint16_t event_code)
{
    OS_Message message =
    {
        .event_code = event_code,
    };

    int32_t status_code = KERN_sndMsgToFrontFromISR(queue_id, &message);

    if(KERN_STATUS_SUCCESS != status_code)
    {
        return os_error(status_code);
    }

    return OS_ERROR_OK;
}
