/**
 * @file utility.cpp
 * @author Radim Buráň (xburan03@stud.fit.vutbr.cz)
 */

#include "utility.hpp"

/**
 * @brief Maps value to different range
 * 
 * @param x input value
 * @param in_min range - in min
 * @param in_max range - in max
 * @param out_min  range - out min
 * @param out_max range - out max
 * @return long result
 */
long map(long x, long in_min, long in_max, long out_min, long out_max) {
    if (x > in_max) {
        x = in_max;
    }
    else if (x < in_min) {
        x = in_min;
    }
    return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}

/**
 * @brief Appends two strings, will create a new one.
 * 
 * @param s1 String 1
 * @param s2 String 2
 * @return char* concatenared string. Need to free after use!
 */
char* appendStrings(char* s1, char* s2) {
    char* res;
    res = (char*)malloc(strlen(s1) + strlen(s2) + 1);
    res[0] = '\0';
    strcat(res, s1);
    strcat(res, s2);
    return res;
}

////////////// NVS //////////////
esp_err_t writeString(const char* key, const char* value) {
    esp_err_t err;
    nvs_handle_t handle;
    nvs_open("props", NVS_READWRITE, &handle);
    err = nvs_set_str(handle, key, value);
    nvs_close(handle);
    return err;
}

/**
 * @param key key
 * @return char* char array - MUST FREE!
 */
char* readString(const char* key) {
    nvs_handle_t handle;
    nvs_open("props", NVS_READONLY, &handle);

    size_t len = 0;
    esp_err_t err = nvs_get_str(handle, key, NULL, &len);

    if (err != ESP_OK || len == 0) {
        return NULL;
    }
    
    char* res = (char*)malloc(len * sizeof(char));
    nvs_get_str(handle, key, res, &len);

    nvs_close(handle);
    return res;
}

esp_err_t writeU64(const char* key, uint64_t value) {
    esp_err_t err;
    nvs_handle_t handle;
    nvs_open("props", NVS_READWRITE, &handle);

    err = nvs_set_u64(handle, key, value);

    nvs_close(handle);
    return err;
}

uint64_t readU64(const char* key) {
    nvs_handle_t handle;
    nvs_open("props", NVS_READONLY, &handle);

    uint64_t res = 0;
    nvs_get_u64(handle, key, &res);

    nvs_close(handle);
    return res;
}

esp_err_t writeU8(const char* key, uint8_t value) {
    esp_err_t err;
    nvs_handle_t handle;
    nvs_open("props", NVS_READWRITE, &handle);

    err = nvs_set_u8(handle, key, value);

    nvs_close(handle);
    return err;
}

uint8_t readU8(const char* key) {
    nvs_handle_t handle;
    nvs_open("props", NVS_READONLY, &handle);

    uint8_t res = 0;
    nvs_get_u8(handle, key, &res);

    nvs_close(handle);
    return res;
}

//////////// SLEEP //////////////
void goToSleep() {
    ESP_LOGI(LOG_TAG, "Going to sleep...");

    rtc_gpio_pullup_en(BUTTON_PIN);
    rtc_gpio_pulldown_dis(BUTTON_PIN);
    esp_sleep_enable_ext0_wakeup(BUTTON_PIN, 0);

    uint64_t sleepTimeUs = SLEEP_TIMER_US - esp_timer_get_time();
    esp_sleep_enable_timer_wakeup(sleepTimeUs);

    esp_deep_sleep_start();
}

////////////// JSON //////////////

/**
 * @brief Creates JSON obj with device ID
 * 
 * @return json root | Delete after use (cJSON_Delete(var))
 */
cJSON* createJsonTemplate() {
    cJSON* root = cJSON_CreateObject();

    char* devID = readString(KEY_NVS_DEVICE_ID);
    cJSON_AddStringToObject(root, "device", devID);
    free(devID);

    return root;
}
