/*
 * Copyright (c) 2023 Juan Manuel Cruz <jcruz@fi.uba.ar> <jcruz@frba.utn.edu.ar>.
 * Copyright (c) 2026 Martin Javier Klöckner <mklockner@fi.uba.ar>
 *
 * See file `LICENSE` for full details
 */

#include "main.h"

#include "logger.h"
#include "dwt.h"

#include "app.h"
#include "task_buttons_attribute.h"
#include "task_system_attribute.h"
#include "task_system_interface.h"
#include "task_buzzer_attribute.h"
#include "task_buzzer_interface.h"

#define TASK_BTN_TICK_CNT_INI   0ul

#define DEL_BTN_XX_MIN          0ul
#define DEL_BTN_XX_MED          25ul
#define DEL_BTN_XX_MAX          50ul

#define BTN_X_PRESSED GPIO_PIN_RESET
#define BTN_X_HOVER   GPIO_PIN_SET

static const task_buttons_cfg_t task_buttons_cfg_list[] = {
    {ID_BTN_A, BTN_A_GPIO_Port, BTN_A_Pin, BTN_X_PRESSED, DEL_BTN_XX_MAX, EV_SYS_BTN_A_IDLE, EV_SYS_BTN_A_ACTIVE},
    {ID_BTN_B, BTN_B_GPIO_Port, BTN_B_Pin, BTN_X_PRESSED, DEL_BTN_XX_MAX, EV_SYS_BTN_B_IDLE, EV_SYS_BTN_B_ACTIVE},
    {ID_BTN_C, BTN_C_GPIO_Port, BTN_C_Pin, BTN_X_PRESSED, DEL_BTN_XX_MAX, EV_SYS_BTN_C_IDLE, EV_SYS_BTN_C_ACTIVE},
    {ID_BTN_D, BTN_D_GPIO_Port, BTN_D_Pin, BTN_X_PRESSED, DEL_BTN_XX_MAX, EV_SYS_BTN_D_IDLE, EV_SYS_BTN_D_ACTIVE},
};

#define BUTTONS_CFG_QTY (sizeof(task_buttons_cfg_list)/sizeof(task_buttons_cfg_t))

static task_buttons_dta_t task_buttons_dta_list[] = {
    {DEL_BTN_XX_MIN, ST_BTN_XX_UP, EV_BTN_XX_UP},
    {DEL_BTN_XX_MIN, ST_BTN_XX_UP, EV_BTN_XX_UP},
    {DEL_BTN_XX_MIN, ST_BTN_XX_UP, EV_BTN_XX_UP},
    {DEL_BTN_XX_MIN, ST_BTN_XX_UP, EV_BTN_XX_UP},
};

#define BUTTONS_DTA_QTY (sizeof(task_buttons_dta_list)/sizeof(task_buttons_dta_t))

// this variable is incremented by 1 on every ms by HAL_SysTick
volatile uint32_t g_task_buttons_tick_cnt;

// Private functions declaration
static void task_buttons_statechart(void);

void task_buttons_init(void *parameters)
{
    task_buttons_dta_t *p_task_buttons_dta;

    LOGGER_INFO("Initializing `task_buttons`...");

    for (uint32_t index = 0; BUTTONS_DTA_QTY > index; index++)
    {
        p_task_buttons_dta = &task_buttons_dta_list[index];

        p_task_buttons_dta->tick = DEL_BTN_XX_MIN;
        p_task_buttons_dta->state = ST_BTN_XX_UP;
        p_task_buttons_dta->event = EV_BTN_XX_UP;
    }

    LOGGER_INFO("Done initializing `task_buttons`");
}

void task_buttons_update(void *parameters)
{
    bool b_time_update_required = false;

    __asm("CPSID i");
    if (TASK_BTN_TICK_CNT_INI < g_task_buttons_tick_cnt)
    {
        g_task_buttons_tick_cnt--;
        b_time_update_required = true;
    }
    __asm("CPSIE i");

    while (b_time_update_required)
    {
        task_buttons_statechart();

        __asm("CPSID i");
        if (TASK_BTN_TICK_CNT_INI < g_task_buttons_tick_cnt)
        {
            g_task_buttons_tick_cnt--;
            b_time_update_required = true;
        }
        else
        {
            b_time_update_required = false;
        }
        __asm("CPSIE i");

    }
}

static void task_buttons_statechart(void)
{
    uint32_t index;
    const task_buttons_cfg_t *p_task_buttons_cfg;
    task_buttons_dta_t       *p_task_buttons_dta;
    uint8_t button_pin_status;

    for (index = 0; BUTTONS_DTA_QTY > index; index++)
    {
        p_task_buttons_cfg = &task_buttons_cfg_list[index];
        p_task_buttons_dta = &task_buttons_dta_list[index];

        button_pin_status = HAL_GPIO_ReadPin(p_task_buttons_cfg->gpio_port, p_task_buttons_cfg->pin);

        if (button_pin_status == p_task_buttons_cfg->pressed)
        {
            p_task_buttons_dta->event = EV_BTN_XX_DOWN;
        }
        else
        {
            p_task_buttons_dta->event = EV_BTN_XX_UP;
        }

        switch (p_task_buttons_dta->state)
        {
            case ST_BTN_XX_UP:
                if (EV_BTN_XX_DOWN == p_task_buttons_dta->event)
                {
                    p_task_buttons_dta->state = ST_BTN_XX_FALLING;
                    p_task_buttons_dta->tick  = DEL_BTN_XX_MAX;
                }
            break;

            case ST_BTN_XX_FALLING:
                if (EV_BTN_XX_UP == p_task_buttons_dta->event)
                {
                    if (0 == p_task_buttons_dta->tick) {
                        p_task_buttons_dta->state = ST_BTN_XX_UP;
                    }
                    else
                    {
                        p_task_buttons_dta->tick--;
                    }
                }

                if (EV_BTN_XX_DOWN == p_task_buttons_dta->event)
                {
                    if (0 == p_task_buttons_dta->tick) {
                        p_task_buttons_dta->state = ST_BTN_XX_DOWN;
                        task_system_interface_put_event(p_task_buttons_cfg->signal_down);
                        task_buzzer_interface_put_event(EV_BUZ_XX_SHORT_BEEP, ID_BUZ_A);
                    }
                    else
                    {
                        p_task_buttons_dta->tick--;
                    }
                }
            break;

            case ST_BTN_XX_DOWN:
                if (EV_BTN_XX_UP == p_task_buttons_dta->event)
                {
                    p_task_buttons_dta->state = ST_BTN_XX_RISING;
                    p_task_buttons_dta->tick  = DEL_BTN_XX_MAX;
                }
            break;

            case ST_BTN_XX_RISING:
                if (EV_BTN_XX_UP == p_task_buttons_dta->event)
                {
                    if (0 == p_task_buttons_dta->tick) {
                        task_system_interface_put_event(p_task_buttons_cfg->signal_up);
                        p_task_buttons_dta->state = ST_BTN_XX_UP;
                    }
                    else
                    {
                        p_task_buttons_dta->tick--;
                    }
                }

                if (EV_BTN_XX_DOWN == p_task_buttons_dta->event)
                {
                    if (0 == p_task_buttons_dta->tick) {
                        p_task_buttons_dta->state = ST_BTN_XX_DOWN;
                    }
                        p_task_buttons_dta->tick--;
                    }
            break;
            default: break;
        }
    }
}
