/* Include Files */
#include "KTag.h"

TaskHandle_t Switches_Task_Handle;

#define SWITCHES_TASK_PERIOD_IN_TICKS   (100 / portTICK_PERIOD_MS)

//! Continuously pressing a switch for this length of time will be interpreted as a long press.
/*!
 *  #Duration_Of_Long_Press_in_Ticks must be an integer multiple of #SWITCHES_TASK_PERIOD_IN_TICKS!
 */
static const TickType_t Duration_Of_Long_Press_in_Ticks = (10 * SWITCHES_TASK_PERIOD_IN_TICKS);

#if (defined LIL_BRUV) || (defined LITTLE_BOY_BLUE)
static TickType_t Up_Switch_Time_Pressed_in_Ticks = 0;
static TickType_t Up_Switch_Time_Released_in_Ticks = 0;
static TickType_t Down_Switch_Time_Pressed_in_Ticks = 0;
static TickType_t Down_Switch_Time_Released_in_Ticks = 0;
static TickType_t Forward_Switch_Time_Pressed_in_Ticks = 0;
static TickType_t Forward_Switch_Time_Released_in_Ticks = 0;
static TickType_t Backward_Switch_Time_Pressed_in_Ticks = 0;
static TickType_t Backward_Switch_Time_Released_in_Ticks = 0;
#elif (defined TWENTY20TPC)
static TickType_t Accessory_Switch_Time_Pressed_in_Ticks = 0;
static TickType_t Accessory_Switch_Total_Time_Pressed_in_Ticks = 0;
static TickType_t Accessory_Switch_Time_Released_in_Ticks = 0;
static TickType_t Accessory_Switch_Time_Since_Last_Release_in_Ticks = 0;
#endif // Model
    
void Switches_Init(void)
{

}


//! Reads the hardware switches and creates press and release events.
/*!
 *  This is a periodic task--see https://www.freertos.org/vtaskdelayuntil.html.
 */
void Switches_Task(void * pvParameters)
{
    TickType_t xLastWakeTime;

     // Initialize the xLastWakeTime variable with the current time.
     xLastWakeTime = xTaskGetTickCount();
    
    while (true)
    {
#if (defined LIL_BRUV) || (defined LITTLE_BOY_BLUE)
        if (Cy_GPIO_Read(Pin_Up_PORT, Pin_Up_NUM) == 0)
        {
            if (Up_Switch_Time_Pressed_in_Ticks == 0)
            {
                Up_Switch_Time_Released_in_Ticks = 0;
                KEvent_T switch_event = {.ID = KEVENT_UP_SWITCH_PRESSED, .Data = &Up_Switch_Time_Released_in_Ticks};
                Post_KEvent(&switch_event);
            }
            else if (Up_Switch_Time_Pressed_in_Ticks == Duration_Of_Long_Press_in_Ticks)
            {
                KEvent_T switch_event = {.ID = KEVENT_UP_SWITCH_LONG_PRESSED, .Data = &Up_Switch_Time_Pressed_in_Ticks};
                Post_KEvent(&switch_event);
            }

            Up_Switch_Time_Pressed_in_Ticks += SWITCHES_TASK_PERIOD_IN_TICKS;
        }
        else
        {
            if (Up_Switch_Time_Released_in_Ticks == 0)
            {
                Up_Switch_Time_Pressed_in_Ticks = 0;
                KEvent_T switch_event = {.ID = KEVENT_UP_SWITCH_RELEASED, .Data = &Up_Switch_Time_Pressed_in_Ticks};
                Post_KEvent(&switch_event);
            }

            Up_Switch_Time_Released_in_Ticks += SWITCHES_TASK_PERIOD_IN_TICKS;
        }
        
        if (Cy_GPIO_Read(Pin_Down_PORT, Pin_Down_NUM) == 0)
        {
            if (Down_Switch_Time_Pressed_in_Ticks == 0)
            {
                Down_Switch_Time_Released_in_Ticks = 0;
                KEvent_T switch_event = {.ID = KEVENT_DOWN_SWITCH_PRESSED, .Data = &Down_Switch_Time_Released_in_Ticks};
                Post_KEvent(&switch_event);
            }
            else if (Down_Switch_Time_Pressed_in_Ticks == Duration_Of_Long_Press_in_Ticks)
            {
                KEvent_T switch_event = {.ID = KEVENT_DOWN_SWITCH_LONG_PRESSED, .Data = &Down_Switch_Time_Pressed_in_Ticks};
                Post_KEvent(&switch_event);
            }

            Down_Switch_Time_Pressed_in_Ticks += SWITCHES_TASK_PERIOD_IN_TICKS;
        }
        else
        {
            if (Down_Switch_Time_Released_in_Ticks == 0)
            {
                Down_Switch_Time_Pressed_in_Ticks = 0;
                KEvent_T switch_event = {.ID = KEVENT_DOWN_SWITCH_RELEASED, .Data = &Down_Switch_Time_Pressed_in_Ticks};
                Post_KEvent(&switch_event);
            }

            Down_Switch_Time_Released_in_Ticks += SWITCHES_TASK_PERIOD_IN_TICKS;
        }
        
       if (Cy_GPIO_Read(Pin_Forward_PORT, Pin_Forward_NUM) == 0)
        {
            if (Forward_Switch_Time_Pressed_in_Ticks == 0)
            {
                Forward_Switch_Time_Released_in_Ticks = 0;
                KEvent_T switch_event = {.ID = KEVENT_FORWARD_SWITCH_PRESSED, .Data = &Forward_Switch_Time_Released_in_Ticks};
                Post_KEvent(&switch_event);
            }
            else if (Forward_Switch_Time_Pressed_in_Ticks == Duration_Of_Long_Press_in_Ticks)
            {
                KEvent_T switch_event = {.ID = KEVENT_FORWARD_SWITCH_LONG_PRESSED, .Data = &Forward_Switch_Time_Pressed_in_Ticks};
                Post_KEvent(&switch_event);
            }

            Forward_Switch_Time_Pressed_in_Ticks += SWITCHES_TASK_PERIOD_IN_TICKS;
        }
        else
        {
            if (Forward_Switch_Time_Released_in_Ticks == 0)
            {
                Forward_Switch_Time_Pressed_in_Ticks = 0;
                KEvent_T switch_event = {.ID = KEVENT_FORWARD_SWITCH_RELEASED, .Data = &Forward_Switch_Time_Pressed_in_Ticks};
                Post_KEvent(&switch_event);
            }

            Forward_Switch_Time_Released_in_Ticks += SWITCHES_TASK_PERIOD_IN_TICKS;
        }
        
        if (Cy_GPIO_Read(Pin_Backward_PORT, Pin_Backward_NUM) == 0)
        {
            if (Backward_Switch_Time_Pressed_in_Ticks == 0)
            {
                Backward_Switch_Time_Released_in_Ticks = 0;
                KEvent_T switch_event = {.ID = KEVENT_BACKWARD_SWITCH_PRESSED, .Data = &Backward_Switch_Time_Released_in_Ticks};
                Post_KEvent(&switch_event);
            }
            else if (Backward_Switch_Time_Pressed_in_Ticks == Duration_Of_Long_Press_in_Ticks)
            {
                KEvent_T switch_event = {.ID = KEVENT_BACKWARD_SWITCH_LONG_PRESSED, .Data = &Backward_Switch_Time_Pressed_in_Ticks};
                Post_KEvent(&switch_event);
            }

            Backward_Switch_Time_Pressed_in_Ticks += SWITCHES_TASK_PERIOD_IN_TICKS;
        }
        else
        {
            if (Backward_Switch_Time_Released_in_Ticks == 0)
            {
                Backward_Switch_Time_Pressed_in_Ticks = 0;
                KEvent_T switch_event = {.ID = KEVENT_BACKWARD_SWITCH_RELEASED, .Data = &Backward_Switch_Time_Pressed_in_Ticks};
                Post_KEvent(&switch_event);
            }

            Backward_Switch_Time_Released_in_Ticks += SWITCHES_TASK_PERIOD_IN_TICKS;
        }
#elif (defined TWENTY20TPC)
        // Use the Remote Trigger pin as the Accessory input, since we never got around to using remote triggers.
        if (Cy_GPIO_Read(Pin_Remote_Trigger_PORT, Pin_Remote_Trigger_NUM) == 0)
        {
            if (Accessory_Switch_Time_Pressed_in_Ticks == 0)
            {
                Accessory_Switch_Time_Since_Last_Release_in_Ticks = Accessory_Switch_Time_Released_in_Ticks;
                KEvent_T switch_event = {.ID = KEVENT_ACCESSORY_SWITCH_PRESSED, .Data = (void *) pdTICKS_TO_MS(Accessory_Switch_Time_Since_Last_Release_in_Ticks)};
                Post_KEvent(&switch_event);
                Accessory_Switch_Time_Released_in_Ticks = 0;
            }
            if ((UINT32_MAX - Accessory_Switch_Time_Pressed_in_Ticks) > SWITCHES_TASK_PERIOD_IN_TICKS)
            {
                Accessory_Switch_Time_Pressed_in_Ticks += SWITCHES_TASK_PERIOD_IN_TICKS;
            }
        }
        else
        {
            if (Accessory_Switch_Time_Released_in_Ticks == 0)
            {
                Accessory_Switch_Total_Time_Pressed_in_Ticks = Accessory_Switch_Time_Pressed_in_Ticks;
                KEvent_T switch_event = {.ID = KEVENT_ACCESSORY_SWITCH_RELEASED, .Data = (void *) pdTICKS_TO_MS(Accessory_Switch_Total_Time_Pressed_in_Ticks)};
                Post_KEvent(&switch_event);
                Accessory_Switch_Time_Pressed_in_Ticks = 0;
            }
            if ((UINT32_MAX - Accessory_Switch_Time_Released_in_Ticks) > SWITCHES_TASK_PERIOD_IN_TICKS)
            {
                Accessory_Switch_Time_Released_in_Ticks += SWITCHES_TASK_PERIOD_IN_TICKS;
            }
        }
#endif // Model
        
        // Wait for the next cycle.
        vTaskDelayUntil(&xLastWakeTime, SWITCHES_TASK_PERIOD_IN_TICKS);
    }
}
