#include <cmdHelper.h>
#include <logger.h>

#include <eeprom.h>
#include <config.h>

#include <string.h>



static bool showConfigCmd(uint8_t argc, char **args) {
    bool retCode = true;

    t_configBlock configBlock;
    eepromReadConfigBlock(&configBlock);
    sendFormatString("configMagic:         %lx\n\r", configBlock.configMagic);
    sendFormatString("deviceName:          %s\n\r", configBlock.deviceName);
    sendFormatString("MAC address:         %02x:%02x:%02x:%02x:%02x:%02x\n\r", configBlock.macAddress[0], 
                                                                           configBlock.macAddress[1], 
                                                                           configBlock.macAddress[2], 
                                                                           configBlock.macAddress[3], 
                                                                           configBlock.macAddress[4], 
                                                                           configBlock.macAddress[5]);
    sendFormatString("frontend threshold:  %ld\n\r", configBlock.frontendThreshold);
    sendFormatString("broker:              %s\n\r", configBlock.brokerName);
    sendFormatString("watchdogTopic:       %s\n\r", configBlock.watchdogTopic);
    sendFormatString("startupTopic:        %s\n\r", configBlock.startupTopic);
    sendFormatString("statusTopic:         %s\n\r", configBlock.statusTopic);
    sendFormatString("mbusDataTopic:       %s\n\r", configBlock.mbusDataTopic);
    sendFormatString("syslog server:       %s\n\r", configBlock.syslogServerName);
    sendFormatString("device block cnt:    %d\n\r", configBlock.numOfDeviceBlocks);

    for (uint8_t i = 0; i < configBlock.numOfDeviceBlocks; i++) {
        t_deviceBlock tmpDeviceBlock;
        eepromReadDeviceBlock(i, &tmpDeviceBlock);
        if (tmpDeviceBlock.deviceMagic == DEVICE_MAGIC) {
            sendFormatString("device %d: \n\r", i);
            sendFormatString("  Name: %s, Address: %d, Period: %d\n\r", 
                       tmpDeviceBlock.deviceName, tmpDeviceBlock.address, tmpDeviceBlock.period);
            sendFormatString("  Considered Fields: %d %d %d %d\n\r",
                       tmpDeviceBlock.consideredField[0],
                       tmpDeviceBlock.consideredField[1],
                       tmpDeviceBlock.consideredField[2],
                       tmpDeviceBlock.consideredField[3]);
            if (tmpDeviceBlock.deviceMagic != DEVICE_MAGIC) {
                sendString("  DEVICE MAGIC DOES NOT MATCH\n\r");
            }
        }
    }

    return retCode;
}




static bool setStringParameterCmd(uint8_t argc, char **args, size_t offset) {
    bool retCode = true;

    t_configBlock configBlock;
    char *parameterName = args[1];
    char *newParameterValue = args[2];
    if (strlen(newParameterValue) >= sizeof(configBlock.deviceName)) {
        sendFormatString("given new value for %s is too long\n\r", parameterName);
        retCode = false;
    } else {
        sendFormatString("set %s to %s\n\r", parameterName, newParameterValue);

        eepromReadConfigBlock(&configBlock);
        strcpy(((char*) (*(((char*)&configBlock) + offset))), newParameterValue);
        eepromWriteConfigBlock(&configBlock);
    }

    return retCode;
}


static bool setDeviceNameCmd(uint8_t argc, char **args) {
    return setStringParameterCmd(argc, args, offsetof(t_configBlock, deviceName));
}


const static cmd_t SET_COMMANDS[] = {
    { .name = "devicename", .cmdFunc = setDeviceNameCmd,
      .help = \
        "devicename ........................... Name of this device\n\r"
    },
    { .name = "END_OF_CMDS", .help = "",.cmdFunc = NULL }
};
const static char UNKNOWN_PARAMETER[] = "unknown parameter\n\r";
const static char OK_MSG[] = "OK\n\r";
const static char FAILED_MSG[] = "Failed\n\r";

static bool setCmd(uint8_t argc, char **args) {
    bool retCode = false;
    uint8_t *messageToSend = NULL;

    char *cmd = args[1];
    if (argc >= 2) {
        if (0 == strcmp("?", cmd)) {
            sendString("You can set the following parameters:\n\r");
            retCode = true;
        } else {
            uint8_t cmdIdx = 0;
            while (true) {
                cmd_t command = SET_COMMANDS[cmdIdx];
                if (0 == strcmp("END_OF_CMDS", command.name)) {
                    messageToSend = (uint8_t*) UNKNOWN_PARAMETER;
                    break;
                }
                if (0 == strcmp(cmd, command.name)) {
                    retCode = command.cmdFunc(argc, args);
                    messageToSend =  retCode ? (uint8_t*)OK_MSG : (uint8_t*)FAILED_MSG;
                    break;
                }
                cmdIdx++;
            }
            sendString((const char*)messageToSend);
        }
    }

    return retCode;
}

static bool restartCmd(uint8_t argc, char **args) {
    HAL_NVIC_SystemReset();
    // you won't come here ...
    return true;
}



const cmd_t CONFIG_COMMANDS[] = {
    { .name = "show", .cmdFunc = showConfigCmd,
      .help = \
        "show ................................. Show the configuration\n\r"
    },
    { .name = "set", .cmdFunc = setCmd,
      .help = \
        "set .................................. Set configuration parameters\n\r" \
        "                                       Argument ? gives a list of \n\r" \
        "                                       parameters\n\r"
    },
    { .name = "restart", .cmdFunc = restartCmd,
      .help = \
        "restart .............................. Restart the system,\n\r" \
        "                                       Required to reload config\n\r"
    },
    { .name = "END_OF_CMDS", .help = "",.cmdFunc = NULL }
};



const cmd_t *getConfigCommands() {
    return CONFIG_COMMANDS;
}