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

#include <helpers.h>
#include <config.h>
#include <logger.h>
#include <confini.h>

#define CONFINI_IS_KEY(SECTION, KEY) \
    (ini_array_match(SECTION, disp->append_to, '.', disp->format) && \
     ini_string_match_ii(KEY, disp->data, disp->format))

static int
config_load_log_level(IniDispatch *disp, config_t *config)
{
    if(strcasecmp(disp->value, "debug") == 0)
    {
        setlogmask(LOG_UPTO(LOG_DEBUG));
        config->log_level = LOG_DEBUG;
        return 0;
    }
    if(strcasecmp(disp->value, "info") == 0)
    {
        setlogmask(LOG_UPTO(LOG_INFO));
        config->log_level = LOG_INFO;
        return 0;
    }
    if(strcasecmp(disp->value, "notice") == 0)
    {
        setlogmask(LOG_UPTO(LOG_NOTICE));
        config->log_level = LOG_NOTICE;
        return 0;
    }
    if(strcasecmp(disp->value, "warning") == 0)
    {
        setlogmask(LOG_UPTO(LOG_WARNING));
        config->log_level = LOG_WARNING;
        return 0;
    }
    if(strcasecmp(disp->value, "err") == 0)
    {
        setlogmask(LOG_UPTO(LOG_ERR));
        config->log_level = LOG_ERR;
        return 0;
    }
    if(strcasecmp(disp->value, "crit") == 0)
    {
        setlogmask(LOG_UPTO(LOG_CRIT));
        config->log_level = LOG_CRIT;
        return 0;
    }
    if(strcasecmp(disp->value, "emerg") == 0)
    {
        setlogmask(LOG_UPTO(LOG_EMERG));
        config->log_level = LOG_EMERG;
        return 0;
    }
    LOGGER_WARNING("invalid log-level '%s'\n", disp->value);
    return 0;
}

static int
config_load_log_file(IniDispatch *disp, config_t *config)
{
    if(strcasecmp(disp->value, "stdout") == 0)
    {
        config->log_file = stdout;
        return 0;
    }
    if(strcasecmp(disp->value, "stderr") == 0)
    {
        config->log_file = stderr;
        return 0;
    }
    config->log_file = fopen(disp->value, "a+");
    return 0;
}

int
config_load(IniDispatch *disp, void *config_void)
{
    config_t *config = (config_t*)config_void;
    char relay_section_name[10]; // "relay-255\0" is longest name 

    if(disp->type == INI_KEY)
    {
        if(CONFINI_IS_KEY("controller", "name"))
        {
            strncpy(config->name, disp->value, MAX_NAME_LENGTH);
            config->name[MAX_NAME_LENGTH] = '\0';
            return 0;
        }
        if(CONFINI_IS_KEY("controller", "database"))
        {
            strcpy(config->database, disp->value);
            return 0;
        }
        if(CONFINI_IS_KEY("controller", "user"))
        {
            strcpy(config->user, disp->value);
            return 0;
        }
        if(CONFINI_IS_KEY("controller", "group"))
        {
            strcpy(config->group, disp->value);
            return 0;
        }
        if(CONFINI_IS_KEY("controller", "log-level"))
        {
            return config_load_log_level(disp, config);
        }
        if(CONFINI_IS_KEY("controller", "log-file"))
        {
            return config_load_log_file(disp, config);
        }
        if(CONFINI_IS_KEY("controller", "discovery-port"))
        {
            config->discovery_port = atoi(disp->value);
            return 0;
        }
        if(CONFINI_IS_KEY("controller", "mqtt-port"))
        {
            config->mqtt_port = atoi(disp->value);
            return 0;
        }
        if(CONFINI_IS_KEY("controller", "mqtt-host"))
        {
            strcpy(config->mqtt_host, disp->value);
            return 0;
        }
        if(CONFINI_IS_KEY("controller", "relays-init"))
        {
            config->relays_init = atoi(disp->value);
            return 0;
        }
        if(CONFINI_IS_KEY("controller", "relay-count"))
        {
            config->relay_count = atoi(disp->value);
            config->relay_configs = malloc(sizeof(config_relay_t) * config->relay_count);
            for(uint8_t i = 0; i < config->relay_count; ++i)
            {
                config->relay_configs[i].driver = RELAY_DRIVER_NONE;
                config->relay_configs[i].inverted = 0;
                config->relay_configs[i].init = -1;
                config->relay_configs[i].pin = 0;
                config->relay_configs[i].pulse_duration = 0;
            }
            return 0;
        }
        for(uint8_t i = 0; i < config->relay_count; ++i)
        {
            sprintf(relay_section_name, "relay-%u", i);
            if(CONFINI_IS_KEY(relay_section_name, "pin"))
            {
                config->relay_configs[i].pin = atoi(disp->value);
                return 0;
            }
            if(CONFINI_IS_KEY(relay_section_name, "inverted"))
            {
                config->relay_configs[i].inverted = atoi(disp->value);
                return 0;
            }
            if(CONFINI_IS_KEY(relay_section_name, "init"))
            {
                config->relay_configs[i].init = atoi(disp->value);
                return 0;
            }
            if(CONFINI_IS_KEY(relay_section_name, "pulse-duration"))
            {
                config->relay_configs[i].pulse_duration = atoi(disp->value);
                return 0;
            }
            if(CONFINI_IS_KEY(relay_section_name, "driver"))
            {
                if(strcasecmp(disp->value, "gpio") == 0)
                {
                    config->relay_configs[i].driver = RELAY_DRIVER_GPIO;
                    return 0;
                }
                if(strcasecmp(disp->value, "piface") == 0)
                {
                    config->relay_configs[i].driver = RELAY_DRIVER_PIFACE;
                    return 0;
                }
                LOGGER_WARNING("invalid driver '%s' in section '%s'\n", disp->value, relay_section_name);
                return 0;
            }
        }
    }
    return 0;
}