#include "onestart.h"
#include "../common.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/syslog.h>
#include <time.h>
#include "define.h"
#include "deviceLayer.h"
#include "../log_module/log_module.h"
#include "jsonct.h"
#include "../multilanguage.h"
#include "define.h"
#include <math.h>
static int one_start_deinit(one_start *this_p);
static int upper(one_start_it *this_p, void *par)
{
    this_p->status = one_start_it_processing;
    int ret = 0;
    if (0 != collector_read_one_int_data(DEV_NO_EMS "." BMS_UPPER, &ret))
    {
        snprintf(this_p->message, sizeof(this_p->message), "%s", "Failed");
    }
    else
    {
        if (ret == 0)
        {
            snprintf(this_p->message, sizeof(this_p->message), "%s", "In Progress");
            collector_write_one_int_data(DEV_NO_EMS "." BMS_UPPER, 1);
        }
        else
        {
            snprintf(this_p->message, sizeof(this_p->message), "%s", "Completed");
            this_p->status = one_start_it_pass;
        }
    }
    return 0;
}

static int set_connect(one_start_it *this_p, void *par)
{
    this_p->status = one_start_it_processing;
    int ret = 0;
    if (0 != collector_read_one_int_data(DEV_NO_EMS "." SET_CONNECT, &ret))
    {
        snprintf(this_p->message, sizeof(this_p->message), "%s", "Failed");
    }
    else
    {
        if (ret == 0)
        {
            snprintf(this_p->message, sizeof(this_p->message), "%s", "In Progress");
            collector_write_one_int_data(DEV_NO_EMS "." SET_CONNECT, 1);
        }
        else
        {
            snprintf(this_p->message, sizeof(this_p->message), "%s", "Completed");
            this_p->status = one_start_it_pass;
        }
    }
    return 0;
}

static int set_on(one_start_it *this_p, void *par)
{
    this_p->status = one_start_it_processing;
    int ret = 0;
    if (0 != collector_read_one_int_data(DEV_NO_EMS "." ON_OFF_STATE, &ret))
    {
        snprintf(this_p->message, sizeof(this_p->message), "%s", "Failed");
    }
    else
    {
        if (ret == 0)
        {
            snprintf(this_p->message, sizeof(this_p->message), "%s", "In Progress");
            collector_write_one_int_data(DEV_NO_EMS "." ON_OFF_STATE, 1);
        }
        else
        {
            snprintf(this_p->message, sizeof(this_p->message), "%s", "Completed");
            this_p->status = one_start_it_pass;
        }
    }
    return 0;
}

static int set_off(one_start_it *this_p, void *par)
{
    this_p->status = one_start_it_processing;
    int ret = 0;
    if (0 != collector_read_one_int_data(DEV_NO_EMS "." ON_OFF_STATE, &ret))
    {
        snprintf(this_p->message, sizeof(this_p->message), "%s", "Failed");
    }
    else
    {
        if (ret != 0)
        {
            snprintf(this_p->message, sizeof(this_p->message), "%s", "In Progress");
            collector_write_one_int_data(DEV_NO_EMS "." ON_OFF_STATE, 0);
        }
        else
        {
            snprintf(this_p->message, sizeof(this_p->message), "%s", "Completed");
            this_p->status = one_start_it_pass;
        }
    }
    return 0;
}

static int set_0_kwh(one_start_it *this_p, void *par)
{
    this_p->status = one_start_it_processing;
    double power = 0;
    if (0 != collector_read_one_float_data(DEV_NO_EMS "." SET_ACT_POWER, &power))
    {
        snprintf(this_p->message, sizeof(this_p->message), "%s", "Failed");
    }
    else
    {
        if (IS_IDLE(power))
        {
            snprintf(this_p->message, sizeof(this_p->message), "%s", "Completed");
            this_p->status = one_start_it_pass;
        }
        else
        {
            snprintf(this_p->message, sizeof(this_p->message), "%s", "In Progress");
            collector_write_one_float_data(DEV_NO_EMS "." SET_ACT_POWER, 0.0);
        }
    }
    return 0;
}

static int set_power(one_start_it *this_p, void *par)
{
    cJSON *json = (cJSON *)par;
    double cur_power = 0;
    //
    this_p->status = one_start_it_processing;
    if (json == NULL)
    {
        snprintf(this_p->message, sizeof(this_p->message), "%s", "Parameter Error");
    }
    else
    {
        json = cJSON_GetObjectItem(json, "setpower");
        if (0 != collector_read_one_float_data(DEV_NO_EMS "." SET_ACT_POWER, &cur_power))
        {
            snprintf(this_p->message, sizeof(this_p->message), "%s", "Failed");
        }
        else
        {
            double power = json->valuedouble;
            if (fabs(cur_power - power) < 1.0)
            {
                snprintf(this_p->message, sizeof(this_p->message), "%s", "Completed");
                this_p->status = one_start_it_pass;
            }
            else
            {
                snprintf(this_p->message, sizeof(this_p->message), "%s", "In Progress");
                collector_write_one_float_data(DEV_NO_EMS "." SET_ACT_POWER, power);
            }
        }
    }
    return 0;
}

static one_start_it onestart_it[] =
    {
        {.name = "Set 0 kWh", .message = {}, .status = one_start_it_no_start, .fun = set_0_kwh},
        {.name = "PCS Set Off", .message = {}, .status = one_start_it_no_start, .fun = set_off},
        {.name = "BMS Upper", .message = {}, .status = one_start_it_no_start, .fun = upper},
        {.name = "PCS Set Connect", .message = {}, .status = one_start_it_no_start, .fun = set_connect},\
        {.name = "PCS Set On", .message = {}, .status = one_start_it_no_start, .fun = set_on},
        {.name = "Set Power", .message = {}, .status = one_start_it_no_start, .fun = set_power}};

int one_start_start(one_start *this_p, void *par)
{
    one_start_deinit(this_p);
    this_p->cur_it = this_p->it;
    this_p->status = one_start_processing;
    return 0;
}
int one_start_stop(one_start *this_p, void *par)
{
    this_p->status = one_start_stoped;
    return 0;
}

int one_start_set(one_start *this_p, void *par)
{
    if (this_p->status == one_start_processing)
    {
        if (this_p->cur_it < this_p->it + this_p->it_size)
        {
            if (this_p->cur_it->status == one_start_it_pass)
            {
                // this_p->cur_it++;
            }
            else
            {
                this_p->cur_it->fun(this_p->cur_it, par);
            }
        }
        //
        if (this_p->cur_it >= this_p->it + this_p->it_size)
        {
            this_p->status = one_start_completed;
        }
    }
    return 0;
}

int one_start_get(one_start *this_p, void *par)
{
    if (this_p->status == one_start_processing)
    {
        if (this_p->cur_it < this_p->it + this_p->it_size)
        {
            if (this_p->cur_it->status == one_start_it_pass)
            {
                this_p->cur_it++;
            }
            else
            {
                this_p->cur_it->fun(this_p->cur_it, NULL);
            }
        }
        //
        if (this_p->cur_it >= this_p->it + this_p->it_size)
        {
            this_p->status = one_start_completed;
        }
    }
    return 0;
}

static one_start_cmd onestart_cmd[] =
    {
        {.cmd = "start", .fun = one_start_start},
        {.cmd = "stop", .fun = one_start_stop},
        {.cmd = "set", .fun = one_start_set},
        {.cmd = "get", .fun = one_start_get},
};
//---------------------------------------------
static int one_start_it_init(one_start_it *it)
{
    it->status = one_start_it_no_start;
    memset(it->message, 0, sizeof(it->message));
    snprintf(it->message, sizeof(it->message), "%s", "Not Start");
    return 0;
}

static cJSON *one_start_it_to_json(one_start_it *it)
{
    cJSON *json = cJSON_CreateObject();
    if (json != NULL)
    {
        cJSON_AddItemToObject(json, "name", cJSON_CreateString(_(it->name)));
        cJSON_AddItemToObject(json, "status", cJSON_CreateNumber(it->status));
        cJSON_AddItemToObject(json, "message", cJSON_CreateString(_(it->message)));
    }

    return json;
}

//------------------------------------------------------------------

static cJSON *one_start_get_status(one_start *this_p)
{
    one_start_it *it = this_p->it;
    int it_size = this_p->it_size;
    cJSON *main_json = cJSON_CreateObject();
    cJSON *it_arr = cJSON_CreateArray();
    cJSON *tmp_json = NULL;
    cJSON_AddItemToObject(main_json, "status", cJSON_CreateNumber(this_p->status));
    for (int i = 0; i < it_size; i++)
    {
        tmp_json = one_start_it_to_json(it + i);
        if (tmp_json != NULL)
        {
            cJSON_AddItemToArray(it_arr, tmp_json);
        }
        else
        {
            ems_syslog(LOG_ERR, "%s diagnosis to json fail", it->name);
        }
    }
    cJSON_AddItemToObject(main_json, "it", it_arr);
    return main_json;
}

static one_start *one_start_new(char *name, one_start_it *it, int it_size, one_start_cmd *cmd, int cmd_size)
{
    one_start *dia = calloc(1, sizeof(one_start));
    if (dia != NULL)
    {
        dia->cur_it = it;
        dia->it = it;
        dia->it_size = it_size;
        dia->status = one_start_no_start;
        //
        dia->cmd = cmd;
        dia->cmd_size = cmd_size;
    }
    return dia;
}

static int one_start_deinit(one_start *this_p)
{
    one_start_it *it = this_p->it;
    int it_size = this_p->it_size;
    for (int i = 0; i < it_size; i++)
    {
        one_start_it_init(&it[i]);
    }
    this_p->status = one_start_no_start;
    return 0;
}

static char *one_start_creat_ack(one_start *this_p, const char *opt, int code)
{
    char *ret = NULL;
    cJSON *ack_json = (code == 0) ? one_start_get_status(this_p) : cJSON_CreateObject();
    if (ack_json != NULL)
    {
        cJSON_AddItemToObject(ack_json, "opt", cJSON_CreateString(opt));
        cJSON_AddItemToObject(ack_json, "code", cJSON_CreateNumber(code));
        ret = cJSON_Print(ack_json);
        cJSON_Delete(ack_json);
        printf("one_start_loop %s\n", ret);
        return ret;
    }
    return NULL;
}

static one_start *obj = NULL;

char *one_start_loop(const char *opt)
{
    printf("one_start_loop %s\n", opt);

    if (obj == NULL)
    {
        obj = one_start_new("onestart", onestart_it, sizeof(onestart_it) / sizeof(onestart_it[0]), onestart_cmd, sizeof(onestart_cmd) / sizeof(onestart_cmd[0]));
    }
    cJSON *root = cJSON_Parse(opt);
    if (root != NULL)
    {
        cJSON *op = cJSON_GetObjectItem(root, "opt");
        cJSON *par = cJSON_GetObjectItem(root, "par");
        if (op == NULL)
        {
            return one_start_creat_ack(obj, "opt", -100);
        }
        for (int i = 0; i < obj->cmd_size; i++)
        {
            if (strcmp(op->valuestring, obj->cmd[i].cmd) == 0)
            {
                return one_start_creat_ack(obj, op->valuestring, obj->cmd[i].fun(obj, par));
            }
        }
        return one_start_creat_ack(obj, "opt", -101);
    }
    return one_start_creat_ack(obj, "opt", -102);
}
