#include <qthing.h>
#include "event.h"

string_callback_t log_oled_callback = NULL;
void set_oled_log_callback(string_callback_t callback) {
    log_oled_callback = callback;
}
void log_oled(const std::string& message) {
    if (log_oled_callback != NULL) {
        log_oled_callback(message);
    }
}

void update_network_connection_status();

volatile connection_status_t wlan_connection_status = uninitialized;
connection_status_callback_t wlan_connection_status_callback = NULL;
void add_wlan_connection_status_callback(connection_status_callback_t callback) {
    if (wlan_connection_status_callback == NULL) {
        wlan_connection_status_callback = callback;
    }
    else {
        connection_status_callback_t old_callback = wlan_connection_status_callback;
        wlan_connection_status_callback = [old_callback, callback](connection_status_t status){
            old_callback(status);
            callback(status);
        };
    }
}
void update_wlan_connection_status(connection_status_t status) {
    wlan_connection_status = status;
    if (wlan_connection_status_callback != NULL) {
        wlan_connection_status_callback(status);
    }

    update_network_connection_status();
}
connection_status_t get_wlan_connection_status() {
    return wlan_connection_status;
}


volatile connection_status_t eth_connection_status = uninitialized;
connection_status_callback_t eth_connection_status_callback = NULL;
void add_eth_connection_status_callback(connection_status_callback_t callback) {
    if (eth_connection_status_callback == NULL) {
        eth_connection_status_callback = callback;
    }
    else {
        connection_status_callback_t old_callback = eth_connection_status_callback;
        eth_connection_status_callback = [old_callback, callback](connection_status_t status){
            old_callback(status);
            callback(status);
        };
    }
}
void update_eth_connection_status(connection_status_t status) {
    eth_connection_status = status;
    if (eth_connection_status_callback != NULL) {
        eth_connection_status_callback(status);
    }

    update_network_connection_status();
}
connection_status_t get_eth_connection_status() {
    return eth_connection_status;
}


volatile connection_status_t network_connection_status = uninitialized;
connection_status_callback_t network_connection_status_callback = NULL;
void add_network_connection_status_callback(connection_status_callback_t callback) {
    if (network_connection_status_callback == NULL) {
        network_connection_status_callback = callback;
    }
    else {
        connection_status_callback_t old_callback = network_connection_status_callback;
        network_connection_status_callback = [old_callback, callback](connection_status_t status){
            old_callback(status);
            callback(status);
        };
    }
}
void update_network_connection_status() {
    connection_status_t wlan = get_wlan_connection_status();
    connection_status_t eth = get_eth_connection_status();

    network_connection_status = uninitialized;

    if (wlan == disconnected || eth == disconnected) network_connection_status = disconnected;
    if (wlan == connecting || eth == connecting) network_connection_status = connecting;
    if (wlan == connected || eth == connected) network_connection_status = connected;

    if (network_connection_status_callback != NULL) {
        network_connection_status_callback(network_connection_status);
    }
}
connection_status_t get_network_connection_status() {
    return network_connection_status;
}


volatile connection_status_t mqtt_connection_status = uninitialized;
connection_status_callback_t mqtt_connection_status_callback = NULL;
void add_mqtt_connection_status_callback(connection_status_callback_t callback) {
    if (mqtt_connection_status_callback == NULL) {
        mqtt_connection_status_callback = callback;
    }
    else {
        connection_status_callback_t old_callback = mqtt_connection_status_callback;
        mqtt_connection_status_callback = [old_callback, callback](connection_status_t status){
            old_callback(status);
            callback(status);
        };
    }
}
void update_mqtt_connection_status(connection_status_t status) {
    mqtt_connection_status = status;
    if (mqtt_connection_status_callback != NULL) {
        mqtt_connection_status_callback(status);
    }
}
connection_status_t get_mqtt_connection_status() {
    return mqtt_connection_status;
}

connection_status_callback_t combined_mqtt_connection_status_callback = NULL;
void update_combined_mqtt_connection_status() {
    connection_status_t status = uninitialized;
    if (network_connection_status == uninitialized) {
        status = uninitialized;
    }
    else if (network_connection_status == disconnected) {
        status = disconnected;
    }
    else if (network_connection_status == connecting || mqtt_connection_status == connecting) {
        status = connecting;
    }
    else if (mqtt_connection_status == disconnected) {
        status = disconnected;
    }
    else if (network_connection_status == connected && mqtt_connection_status == connected) {
        status = connected;
    }
    combined_mqtt_connection_status_callback(status);
}
void add_combined_mqtt_connection_status_callback(connection_status_callback_t callback) {
    if (combined_mqtt_connection_status_callback == NULL) {
        combined_mqtt_connection_status_callback = callback;
        add_network_connection_status_callback([](connection_status_t wlan_status){
            update_combined_mqtt_connection_status();
        });
    }
    else {
        connection_status_callback_t old_callback = combined_mqtt_connection_status_callback;
        combined_mqtt_connection_status_callback = [old_callback, callback](connection_status_t status){
            old_callback(status);
            callback(status);
        };
    }
}
bool is_mqtt_connected() {
    return network_connection_status == connected && mqtt_connection_status == connected;
}