#include "main.h"

// Standard includes
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// Includes
#include "system.h"
#include "btn.h"
#include "term.h"
#include "led.h"
#include "rf_rx.h"
#include "eeprom.h"
#include "cfg.h"
#include "rf_cmd.h"

#define MODE_AUTO   0
#define MODE_RF     1

const led_seq_t * const g_seq_table[] = {
    LED_SEQ_BUFF(2, LED_SEQ_BUFF_ROT_CCW, 100, ((led_color_t[]){LED_COLOR_GREEN, LED_COLOR_OFF, LED_COLOR_OFF, LED_COLOR_OFF, LED_COLOR_OFF, LED_COLOR_OFF}) ),
    LED_SEQ_BUFF(2, LED_SEQ_BUFF_ROT_CW, 100, ((led_color_t[]){LED_COLOR_GREEN, LED_COLOR_OFF, LED_COLOR_OFF, LED_COLOR_OFF, LED_COLOR_OFF, LED_COLOR_OFF}) ),
    LED_SEQ_GLOW(3, LED_COLOR_RED, LED_COLOR_OFF, 1000, 500),
    LED_SEQ_BUFF(5, LED_SEQ_BUFF_ROT_CW, 500, ((led_color_t[]){LED_COLOR_RED, LED_COLOR_GREEN, LED_COLOR_BLUE, LED_COLOR_YELLOW, LED_COLOR_CYAN, LED_COLOR_MAGENTA}) ),
    LED_SEQ_GLOW(2, LED_COLOR_GREEN, LED_COLOR_BLUE, 2000, 2000),
    LED_SEQ_BUFF(3, LED_SEQ_BUFF_ROT_CW, 300, ((led_color_t[]){LED_COLOR_RED, LED_COLOR_GREEN, LED_COLOR_RED, LED_COLOR_GREEN, LED_COLOR_RED, LED_COLOR_GREEN}) ),
    LED_SEQ_GLOW(2, LED_COLOR_BLUE, LED_COLOR_RED, 2000, 2000),
    LED_SEQ_BUFF(3, LED_SEQ_BUFF_ROT_CW, 500, ((led_color_t[]){LED_COLOR_CYAN, LED_COLOR_CYAN, LED_COLOR_CYAN, LED_COLOR_GREEN, LED_COLOR_GREEN, LED_COLOR_GREEN}) ),
    LED_SEQ_GLOW(2, LED_COLOR_MAGENTA, LED_COLOR_CYAN, 2000, 2000),
    LED_SEQ_BUFF(3, LED_SEQ_BUFF_ROT_CW, 200, ((led_color_t[]){LED_COLOR_MAGENTA, LED_COLOR_OFF, LED_COLOR_OFF, LED_COLOR_MAGENTA, LED_COLOR_OFF, LED_COLOR_OFF}) ),
    LED_SEQ_GLOW(2, LED_COLOR_YELLOW, LED_COLOR_RED, 2000, 2000),
    LED_SEQ_BUFF(3, LED_SEQ_BUFF_ROT_CW, 300, ((led_color_t[]){LED_COLOR_CYAN, LED_COLOR_YELLOW, LED_COLOR_CYAN, LED_COLOR_YELLOW, LED_COLOR_CYAN, LED_COLOR_YELLOW}) ),
    LED_SEQ_GLOW(5, LED_COLOR_BLUE, LED_COLOR_CYAN, 500, 500),
    LED_SEQ_BUFF(5, LED_SEQ_BUFF_ROT_CW, 100, ((led_color_t[]){LED_COLOR_BLUE, LED_COLOR_BLUE, LED_COLOR_MAGENTA, LED_COLOR_MAGENTA, LED_COLOR_YELLOW, LED_COLOR_YELLOW}) ),
    LED_SEQ_BLINK(3, LED_COLOR_GREEN, 100, LED_COLOR_OFF, 200),
};


int main()
{


    // System init
    system_init();

    // Terminal Init
    term_init();

    // Config Init
    cfg_init();

    // Btn Init
    btn_init();

    // Led Init
    led_init();

     // RF Init
    rf_cmd_init();
    rf_rx_init();

    // Check  for startup mode (and generate Human-Based Entropy Seed)
    uint32_t seed = 0;
    int is_long_press = 0;
    uint32_t start_tick = HAL_GetTick();
    while(BTN_IS_PRESSED()) {
        seed++;
        if ((HAL_GetTick() - start_tick) > 2000) {
            if (!is_long_press){
                is_long_press = 1;
                led_set_color(cfg.user.boot == CFG_BOOT_AUTO ? LED_COLOR_BLUE : LED_COLOR_GREEN);
            }
            if ((HAL_GetTick() - start_tick) > 5000) break;
        }
    }
    srand((HAL_GetUIDw0() ^ HAL_GetUIDw1() ^ HAL_GetUIDw2() ^ seed) * 16777619);
    term_out_str(" rand       : ");
    term_out_uint(rand());
    term_out_str("\r\n");

    // Boot mode
    int mode;
    if (is_long_press == 0){
        mode = (cfg.user.boot == CFG_BOOT_AUTO ? MODE_AUTO : MODE_RF);
    }else{
        mode = (cfg.user.boot == CFG_BOOT_AUTO ? MODE_RF : MODE_AUTO);
    }

    if (mode == MODE_RF){

        // Update cfg
        led.brightness = cfg.user.brightness;
        led.led_used   = cfg.user.led_count;

        // RADIO
        term_out_msg("Radio mode !");
        RF_RX_POWER_ON();
        RF_RX_TIM_START();


        // RF sequence
        led_set_seq(LED_SEQ_BLINK(3, (cfg.factory.addr == 0 ? LED_COLOR_RED : LED_COLOR_BLUE), 200, LED_COLOR_OFF, 200));

        while(1){

            // Timeout
            if ((HAL_GetTick() - rf_cmd.tick) > RF_KEEPALIVE_TIMEOUT_MS){
                system_shutdown();
            }

            // Handle shutdown
            if (btn_is_long_press()){
                system_shutdown();
            }

            // Handle term command
            term_task();

            // Led task
            led_task();

            // RF task
            rf_rx_task();
            rf_cmd_task();
        }

    }else{

        term_out_msg("Auto mode !");
        btn.status = BTN_STATUS_NONE;
        led_set_seq(LED_SEQ_BLINK(3, LED_COLOR_GREEN, 200, LED_COLOR_OFF, 200));

        #define SEQ_MODE_RAND           0
        #define SEQ_MODE_MANUAL         1
        uint32_t timeout_tick = HAL_GetTick();
        uint16_t seq_mode = SEQ_MODE_RAND;
        uint16_t new_id, seq_id = 0;

        while(1){

            // Timeout
            if ((HAL_GetTick() - timeout_tick) > BUILD_MODE_AUTO_TIMEOUT_MS){
                system_shutdown();
            }

            // Handle shutdown
            if (btn_is_long_press()){
                system_shutdown();

            // Handle next sequence
            }else if (btn_is_short_press()){
                // Reset timeout
                timeout_tick = HAL_GetTick();
                // Handle mode next sequence
                switch(seq_mode){
                    case SEQ_MODE_RAND:
                        seq_mode = SEQ_MODE_MANUAL;
                        seq_id = 0;
                        led_set_seq((led_seq_t*)g_seq_table[seq_id]);
                        led.seq.head.count = 0;
                        break;
                    case SEQ_MODE_MANUAL:
                        seq_id++;
                        if (seq_id >= ARRAY_SIZE(g_seq_table)){
                            seq_mode = SEQ_MODE_RAND;
                            led_set_seq(LED_SEQ_NONE());
                            seq_id = 0;
                        }else{
                            led_set_seq((led_seq_t*)g_seq_table[seq_id]);
                            led.seq.head.count = 0;
                        }
                        break;
                }

            }

            // Handle term command
            term_task();

            // Led task
            led_task();

            // Auto sequence
            if (seq_mode == SEQ_MODE_RAND && led.seq.head.type == LED_SEQ_TYPE_NONE){
                new_id = seq_id;
                while(new_id == seq_id){
                    new_id = rand() % ARRAY_SIZE(g_seq_table);
                }
                seq_id = new_id;
                led_set_seq((led_seq_t*)g_seq_table[seq_id]);
            }

        }

    }

}

