/**
 * @author Rémi Heredero (remi@heredero.ch)
 * @version. 1.0.0
 * @date 2023-06-15
 */

#include "button.h"
#include "../../mcc_generated_files/pin_manager.h"
#include "../../app/factory/factory.h"

/**
 * @brief Initialize the button
 * 
 * @param me The object to initialize
 * @param id The id of the button
 */
void BUTTON_init(BUTTON* me, uint8_t id) {
    me->id = id;
    me->state = ST_PBINIT;
    me->press.fCallBack = NULL;
    me->release.fCallBack = NULL;
}

/**
 * @brief Initialize the hardware of the button
 * 
 * @param me The object to initialize
 */
void BUTTON_initHW(BUTTON* me) {
    switch (me->id) {
        case 1:
            INPUT1_SetDigitalInput();
            break;
        case 2:
            INPUT2_SetDigitalInput();
            break;
        case 3:
            INPUT3_SetDigitalInput();
            break;
        default:
            break;
    }
}

/**
 * @brief Check if the button is pressed
 * The function returns true if the button is pressed, false otherwise
 * 
 * @param me The object to check
 * @return true if the button is pressed
 * @return false if the button is not pressed
 */
bool BUTTON_isPressed(BUTTON* me) {
    switch (me->id) {
        case 1:
            return INPUT1_GetValue();
            break;
        case 2:
            return INPUT2_GetValue();
            break;
        case 3:
            return INPUT3_GetValue();
            break;
        default:
            return false;
            break;
    }
}

void BUTTON_startBehaviour(BUTTON* me) {
    POST(me, &BUTTON_processEvent, evPBInit, 0, 0);
}

bool BUTTON_processEvent(Event * ev) {
    bool processed = false;
    BUTTON* me = (BUTTON*)Event_getTarget(ev);
    BUTTON_STATES oldState = me->state;
    evIDT evid = Event_getId(ev);
    
    switch(me->state){
        case ST_PBINIT:
            if (evid == evPBInit) {
                POST(me, &BUTTON_processEvent, evPBPoll, 0, 0);
                if(BUTTON_isPressed(me)) {
                    me->state = ST_PBPRESSED;
                } else {
                    me->state = ST_PBRELEASED;
                }
            }
            break;
        case ST_PBRELEASED:
            if(evid == evPBPoll) {
                POST(me, &BUTTON_processEvent, evPBPoll, PB_POLL_TIME, 0);
                if(BUTTON_isPressed(me)) {
                    me->state = ST_PBPRESSED;
                }
            }
            
            break;
        case ST_PBPRESSED:
            if(evid == evPBPoll) {
                POST(me, &BUTTON_processEvent, evPBPoll, PB_POLL_TIME, 0);                
                if(!BUTTON_isPressed(me)){
                    me->state = ST_PBRELEASED;
                }
                    
            }
            break;
    }
    
    if(oldState != me->state) {
        switch(me->state){
            case ST_PBINIT:
                break;
            case ST_PBRELEASED:
                if(me->release.fCallBack != NULL) me->release.fCallBack(me->release.param);
                break;
            case ST_PBPRESSED:
                if(me->press.fCallBack != NULL) me->press.fCallBack(me->press.param);
                break;
        }
        processed = true;
    }
    return processed;
}

void BUTTON_setEventFunctions(BUTTON* me, buttonCallBack fPress, buttonCallBack fRelease) {
    me->press = fPress;
    me->release = fRelease;
}

buttonCallBack BUTTON_defineCallBack(fButtonCallback f, void* param){
    buttonCallBack c;
    c.fCallBack = f;
    c.param = param;
    return c;
}