#include "console_cmd.h"
#include "fram.h"
#include "fram_map.h"
#include "time.h"
#include "crc16.h"
#include "app_serv.h"
#include "version.h"
#include <stddef.h>
#include <string.h>

TFramMap *config_ram;

extern char reboot_flag;
extern CPU_INT32U app_timer_value;
extern int pre_pause_counter;
extern int out_timer_counter;

extern int ConsoleWriteStr(char* str);

///
static int GetVersion(char *str_value)
{
    strcpy(str_value, DEVICE_FW_VERSION);
    return 0;
}

///
static int SetIpAddr(char *str_value)
{
    NET_IP_ADDR  ip_addr;
    NET_ERR   err;
    ip_addr = NetASCII_Str_to_IP((CPU_CHAR*)str_value, &err);
    if (err != NET_ASCII_ERR_NONE)
    {
        return -1;
    }
    #if !defined(CONFIG_SETTINGS_IAP)
    WriteArrayFram(offsetof(TFramMap, ip), sizeof(CPU_INT32U), (unsigned char*)&ip_addr);
    #else
    config_ram->ip = ip_addr;
    #endif
    return 0;
}

///
static int GetIpAddr(char *str_value)
{
    NET_IP_ADDR  ip_addr;
    NET_ERR   err;
    #if !defined(CONFIG_SETTINGS_IAP)
    ReadArrayFram(offsetof(TFramMap, ip), sizeof(CPU_INT32U), (unsigned char*)&ip_addr);
    #else
    ip_addr = config_ram->ip;
    #endif
    NetASCII_IP_to_Str(ip_addr, (CPU_CHAR*)str_value, DEF_NO, &err);
    if (err != NET_ASCII_ERR_NONE)
    {
        return -1;
    }  
    return 0;
}

///
static int SetNetMask(char *str_value)
{
    NET_IP_ADDR  ip_addr;
    NET_ERR   err;
    ip_addr = NetASCII_Str_to_IP((CPU_CHAR*)str_value, &err);
    if (err != NET_ASCII_ERR_NONE)
    {
        return -1;
    }  
    #if !defined(CONFIG_SETTINGS_IAP)
    WriteArrayFram(offsetof(TFramMap, netmask), sizeof(CPU_INT32U), (unsigned char*)&ip_addr);
    #else
    config_ram->netmask = ip_addr;
    #endif
    return 0;
}

///
static int GetNetMask(char *str_value)
{
    NET_IP_ADDR  ip_addr;
    NET_ERR   err;
    #if !defined(CONFIG_SETTINGS_IAP)
    ReadArrayFram(offsetof(TFramMap, netmask), sizeof(CPU_INT32U), (unsigned char*)&ip_addr);
    #else
    ip_addr = config_ram->netmask;
    #endif
    NetASCII_IP_to_Str(ip_addr, (CPU_CHAR*)str_value, DEF_NO, &err);
    if (err != NET_ASCII_ERR_NONE)
    {
        return -1;
    }  
    return 0;
}

///
static int SetGateWay(char *str_value)
{
    NET_IP_ADDR  ip_addr;
    NET_ERR   err;
    ip_addr = NetASCII_Str_to_IP((CPU_CHAR*)str_value, &err);
    if (err != NET_ASCII_ERR_NONE)
    {
        return -1;
    }  
    #if !defined(CONFIG_SETTINGS_IAP)
    WriteArrayFram(offsetof(TFramMap, gateway), sizeof(CPU_INT32U), (unsigned char*)&ip_addr);
    #else
    config_ram->gateway = ip_addr;
    #endif
    return 0;
}

///
static int GetGateWay(char *str_value)
{
    NET_IP_ADDR  ip_addr;
    NET_ERR   err;
    #if !defined(CONFIG_SETTINGS_IAP)
    ReadArrayFram(offsetof(TFramMap, gateway), sizeof(CPU_INT32U), (unsigned char*)&ip_addr);
    #else
    ip_addr = config_ram->gateway;
    #endif
    NetASCII_IP_to_Str(ip_addr, (CPU_CHAR*)str_value, DEF_NO, &err);
    if (err != NET_ASCII_ERR_NONE)
    {
        return -1;
    }  
    return 0;
}

///
static int SetMacAddr(char *str_value)
{
    CPU_INT08U   mac_addr[6];
    NET_ERR   err;
    NetASCII_Str_to_MAC((CPU_CHAR*)str_value, &mac_addr[0], &err);
    if (err != NET_ASCII_ERR_NONE)
    {
        return -1;
    }
    #if !defined(CONFIG_SETTINGS_IAP)
    WriteArrayFram(offsetof(TFramMap, mac_addr), 6, (unsigned char*)&mac_addr[0]);
    #else
    config_ram->mac_addr[0] = mac_addr[0];
    config_ram->mac_addr[1] = mac_addr[1];
    config_ram->mac_addr[2] = mac_addr[2];
    config_ram->mac_addr[3] = mac_addr[3];
    config_ram->mac_addr[4] = mac_addr[4];
    config_ram->mac_addr[5] = mac_addr[5];
    #endif
    return 0;
}

///
static int GetMacAddr(char *str_value)
{
    CPU_INT08U   mac_addr[6];
    NET_ERR   err;
    #if !defined(CONFIG_SETTINGS_IAP)
    ReadArrayFram(offsetof(TFramMap, mac_addr), 6, (unsigned char*)&mac_addr[0]);
    #else
    mac_addr[0] = config_ram->mac_addr[0];
    mac_addr[1] = config_ram->mac_addr[1];
    mac_addr[2] = config_ram->mac_addr[2];
    mac_addr[3] = config_ram->mac_addr[3];
    mac_addr[4] = config_ram->mac_addr[4];
    mac_addr[5] = config_ram->mac_addr[5];
    #endif
    NetASCII_MAC_to_Str((CPU_INT08U*)&mac_addr[0], (CPU_CHAR*)str_value, DEF_NO, &err);
    if (err != NET_ASCII_ERR_NONE)
    {
        return -1;
    }  
    return 0;
}

///
static int SetIpPort(char *str_value)
{
    int port = 0;
    
    if (sscanf(str_value, "%d", &port) == 1)
    {
        if ((port > 0) && (port < 65000))
        {
            #if !defined(CONFIG_SETTINGS_IAP)
            WriteArrayFram(offsetof(TFramMap, port), sizeof(CPU_INT16U), (unsigned char*)&port);
            #else
            config_ram->port = port;
            #endif
            return 0;
        }
    }
    return -1;
}

///
static int GetIpPort(char *str_value)
{
    int port = 0;
    #if !defined(CONFIG_SETTINGS_IAP)
    ReadArrayFram(offsetof(TFramMap, port), sizeof(CPU_INT16U), (unsigned char*)&port);
    #else
    port = config_ram->port;
    #endif
    sprintf(str_value, "%d", port);
    return 0;
}

#if defined(BOARD_CENTRAL_CARWASH) || defined(BOARD_SOLARIUM_WEB) || defined(BOARD_SOLARIUM_VLAD)
static int GetDateTime(char *str_value)
{
    PrintTimeString(str_value, GetTimeSec());
    return 0;
}

static int SetDateTime(char *str_value)
{
    TRTC_Data rtc;
    ScanRTCDateTimeStringRus(str_value, &rtc);
    if (RTCCheckTime(&rtc) == 0)
    {
        RTC_SetTime(&rtc);
        return 0;
    }
    return -1;
}

static int GetPrecheckText(char *str_value)
{
    for (int i = 0; i < PRETEXT_LINE_COUNT; i++)
    {
        if (ReadPrecheckText(str_value, i) > 0)
        {
            strcat(str_value, "\n");
            ConsoleWriteStr(str_value);
        }
    }
    sprintf(str_value, "DONE");
    return 0;
}

static int SetPrecheckText(char *str_value)
{
 #if defined(BOARD_CENTRAL_CARWASH) || defined(BOARD_SOLARIUM_VLAD)
    int index;
    char text[50];

    if (strlen(str_value) > 49)
    {
        return -1;
    }
    if (sscanf(str_value, "%d,%s", &index, text) == 2)
    {
        if ((index >= 0) && (index < PRETEXT_LINE_COUNT))
        {
           WriteArrayFram((unsigned short)offsetof(TFramMap, precheck_text) + 40 * index, 40, (unsigned char *)&text[0]);
           unsigned short crc_calc = crc16_fram((unsigned short)offsetof(TFramMap, precheck_text), PRETEXT_LINE_COUNT * 40);
           WriteArrayFram((unsigned short)offsetof(TFramMap, precheck_crc), sizeof(CPU_INT16U), (unsigned char *)&crc_calc);
           return 0;
        }
    }
 #endif
    return -1;
}


#endif

#ifdef BOARD_POST_CARWASH
// формат: кол-во импульсов, длина импульса мс
static int SetPulseOut(char *str_value)
{
    int len_ms = 0, len_pause_ms = 0, count = 0, pause = 0, timer = 0;
    
    if (sscanf(str_value, "%d,%d,%d,%d,%d", &count, &len_ms, &len_pause_ms, &pause, &timer) == 5)
    {
        if ((len_ms > 0) && (len_ms <= 10000) && (len_pause_ms > 0) && (len_pause_ms <= 10000) && (count > 0) && (count < 10000))
        {
            AddOutPulses(count, len_ms, len_pause_ms);
            app_timer_value = 0;
            pre_pause_counter = pause;
            out_timer_counter = 0;
            PostUserEvent(EVENT_PULSEOUT);
        }
        return 0;
    }
    else if (sscanf(str_value, "%d,%d,%d,%d", &count, &len_ms, &pause, &timer) == 4)
    {
        AddOutPulses(count, 0, 0);
        app_timer_value = timer;
        pre_pause_counter = pause;
        out_timer_counter = 0;
        PostUserEvent(EVENT_PULSEOUT);
        return 0;
    }
    else if (sscanf(str_value, "%d,%d,%d", &count, &len_ms, &pause) == 3)
    {
        if ((len_ms > 0) && (len_ms <= 1000) && (count > 0) && (count < 10000))
        {
            AddOutPulses(count, len_ms, len_ms * 3);
            app_timer_value = 0;
            pre_pause_counter = pause;
            out_timer_counter = 0;
            PostUserEvent(EVENT_PULSEOUT);
            return 0;
        }
    }
    return -1;
}

static int SetSignal(char *str_value)
{
    int signal;
    
    if (sscanf(str_value, "%d", &signal) == 1)
    {
        if ((signal == 0) || (signal == 1) && (config_ram->signal != signal))
        {
            config_ram->signal = signal;
            reboot_flag = 1;
            return 0;
        }
    }
    return -1;
}

static int GetSignal(char *str_value)
{
    sprintf(str_value, "%d", config_ram->signal);
    return 0;
}

#endif

///
static int SetReboot(char *str_value)
{
    reboot_flag = 1;
    return 0;
}


static int GetStatus(char *str_value);

///
static const ParamDesc params[PARAM_COUNT] = 
{
    {"VERSION",     NULL,           GetVersion},
    {"MAC",         SetMacAddr,     GetMacAddr},
    {"IP",          SetIpAddr,      GetIpAddr},
    {"NETMASK",     SetNetMask,     GetNetMask},
    {"GATEWAY",     SetGateWay,     GetGateWay},
    {"PORT",        SetIpPort,      GetIpPort},

#ifdef BOARD_POST_CARWASH
    {"PULSEOUT",    SetPulseOut,      NULL},
    {"SIGNAL",      SetSignal,      GetSignal},
#else
    {"DATETIME",    SetDateTime,    GetDateTime},
    {"ADVERTISING", SetPrecheckText, GetPrecheckText},
#endif
    
    {"REBOOT",      SetReboot,      NULL},
    {"STATUS",      NULL,           GetStatus},

};


/// весь статус одним ответом
static int GetStatus(char *str_value)
{
    for (uint16_t i = 0; i < PARAM_COUNT - 1; i++)
    {
        sprintf(str_value, params[i].name);
        strcat(str_value, " ");
        if (params[i].get != NULL)
        {
            params[i].get(&str_value[strlen(str_value)]);
        }
        else
        {
            strcat(str_value, "NULL");
        }
        strcat(str_value, "\n");
        ConsoleWriteStr(str_value);
    }
    
    sprintf(str_value, "STATUS READ");
    return 0;
}

int SetParam(char *cmd)
{
    for (uint16_t i = 0; i < PARAM_COUNT; i++)
    {
        if (strstr(cmd, params[i].name) == cmd)
        {
            if (params[i].set != NULL)
            {
                if (params[i].set(&cmd[strlen(params[i].name) + 1]) == 0)
                {
                    return 0;
                }
                else
                {
                    return -2;
                }
            }
        }
    }
    
    return -1;
}

int GetParam(char *cmd, char *answer, uint16_t len)
{
    for (uint16_t i = 0; i < PARAM_COUNT; i++)
    {
        if (strstr(cmd, params[i].name) == cmd)
        {
            if (params[i].get != NULL)
            {
                if (params[i].get(&answer[0]) == 0)
                {
                    strcat(&answer[0], "\n");
                    return 0;
                }
                else
                {
                    return -2;
                }
            }
        }
    }
    
    return -1;;
}

