#include <string.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdlib.h>

#include <main.h>
#include <usart.h>
#include <adc.h>
#include <spi.h>

#include <PontCoopScheduler.h>

#include <show.h>
#include <loopCtrl.h>
#include <mbusComm.h>
#include <logger.h>
#include <frontend.h>
#include <eeprom.h>
#include <wizHelper.h>

void my_setup_1() {
    schInit();
    logInit();
}

void my_errorHandler() {
    show(LED_RED, ON);
}


static uint8_t numOfDevices = 8;
static t_mbusDevice devices[] = {
    {
        .deviceName = "Total Power",
        .address = 80,
        .consideredField = {
            { .label = "energy", .index = 0 },
            { .label = "power", .index = 17 },
            { .label = "", .index = 0 },
            { .label = "", .index = 0 }
        },
        .requests = 0,
        .failures = 0,
        .period = 60,
        .delay = 0,
        .waiting = false
    },
    {
        .deviceName = "Computer Power",
        .address = 85,
        .consideredField = {
            { .label = "energy", .index = 0 },
            { .label = "power", .index = 4 },
            { .label = "voltage", .index = 2 },
            { .label = "current", .index = 3 }
        },
        .requests = 0,
        .failures = 0,
        .period = 60,
        .delay = 0,
        .waiting = false
    },
    {
        .deviceName = "Dryer Power",
        .address = 81,
        .consideredField = {
            { .label = "energy", .index = 0 },
            { .label = "power", .index = 4 },
            { .label = "voltage", .index = 2 },
            { .label = "current", .index = 3 }
        },
        .requests = 0,
        .failures = 0,
        .period = 60,
        .delay = 0,
        .waiting = false
    },
    {
        .deviceName = "Laundry Power",
        .address = 82,
        .consideredField = {
            { .label = "energy", .index = 0 },
            { .label = "power", .index = 4 },
            { .label = "voltage", .index = 2 },
            { .label = "current", .index = 3 }
        },
        .requests = 0,
        .failures = 0,
        .period = 60,
        .delay = 0,
        .waiting = false
    },
    {
        .deviceName = "Dishwasher Power",
        .address = 83,
        .consideredField = {
            { .label = "energy", .index = 0 },
            { .label = "power", .index = 4 },
            { .label = "voltage", .index = 2 },
            { .label = "current", .index = 3 }
        },
        .requests = 0,
        .failures = 0,
        .period = 60,
        .delay = 0,
        .waiting = false
    },
    {
        .deviceName = "Light Power",
        .address = 84,
        .consideredField = {
            { .label = "energy", .index = 0 },
            { .label = "power", .index = 4 },
            { .label = "voltage", .index = 2 },
            { .label = "current", .index = 3 }
        },
        .requests = 0,
        .failures = 0,
        .period = 15,
        .delay = 0,
        .waiting = false
    },
    {
        .deviceName = "Freezer Power",
        .address = 86,
        .consideredField = {
            { .label = "energy", .index = 0 },
            { .label = "power", .index = 4 },
            { .label = "voltage", .index = 2 },
            { .label = "current", .index = 3 }
        },
        .requests = 0,
        .failures = 0,
        .period = 60,
        .delay = 0,
        .waiting = false
    },
    {
        .deviceName = "Fridge Power",
        .address = 87,
        .consideredField = {
            { .label = "energy", .index = 0 },
            { .label = "power", .index = 4 },
            { .label = "voltage", .index = 2 },
            { .label = "current", .index = 3 }
        },
        .requests = 0,
        .failures = 0,
        .period = 60,
        .delay = 0,
        .waiting = false
    }
};


void triggerMBusRequest(void *handle) {
    static uint8_t deviceIndex = 0;

    if (devices[deviceIndex].waiting) {
        e_mbusCommRequestResult r = mbusCommRequest(&(devices[deviceIndex]));
        if (r == MBCRR_TRIGGERED) {
            devices[deviceIndex].waiting = false;
            deviceIndex++;
        }
    } else {
        deviceIndex++;
    }
    if (deviceIndex >= numOfDevices) {
        deviceIndex = 0;
    }
}

void scheduleMBusRequest(void *handle) {
    for (uint8_t i = 0; i < numOfDevices; i++) {
        devices[i].delay -= 1;
        if (devices[i].delay <= 0) {
            devices[i].delay = devices[i].period;
            devices[i].waiting = true;
            coloredMsg(LOG_GREEN, "*** Scheduled: %s", devices[i].deviceName);
        }
    }
}

void my_setup_2() {
    show(LED_RED, OFF);
    show(LED_GREEN, ON);
    coloredMsg(LOG_BLUE, "Application starting");

    eepromInit();

    wizInit();

    frontendInit();
    frontendSetThreshold(240);

    schAdd(scheduleMBusRequest, NULL, 0, 1000);
    schAdd(triggerMBusRequest, NULL, 0, 100);
}

void my_loop() {
    show(DEBUG_1, TOGGLE);

    schExec();
    logExec();
}

void SYSTICK_Callback() {
    schUpdate();
}

void HAL_GPIO_EXTI_Callback(uint16_t pin) {
    if (pin == Loop_Status_Pin) {
        loopStatusCallback();
    }
}

void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc) {
    if (hadc == &frontendAdc) {
        frontendAdcCallback(hadc);   
    }
}

void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart) {
    if (huart == &mbusUart) {
        mbusCommTxCpltCallback(huart);
    }
}

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) {
    if (huart == &mbusUart) {
        mbusCommRxCpltCallback(huart);
    }
}

void HAL_SPI_TxCpltCallback(SPI_HandleTypeDef *hspi) {
    if (hspi == &eepromSpi) {
        eepromSpiTxCpltCallback(hspi);
    }
}