/*
 * @Author: ybzhou yibo.zhou@lnxall.com
 * @Date: 2025-07-16 12:47:52
 * @LastEditors: ybzhou yibo.zhou@lnxall.com
 * @LastEditTime: 2025-09-18 14:01:17
 * @FilePath: /2025.07.09/proto_forward/src/automatic_north/mqtt_create.c
 * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
 */
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/select.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <pthread.h>
#include <math.h>
#include <time.h>

#include "xlsx_api.h"
#include "mqtt_create.h"

static home_page_t _mq_home_page[] = {
	{"EMS",  0, 0, ""},
	{"PCS",  0, 0, "the maximum support is 32"},
	{"BMS", 0, 0, "the maximum support is 64"},
	{"CELL", 0, 0, "the maximum support is 64"},
	{"GRID_METER", 0, 0, "the maximum support is 64"},
	{"PCS_METER", 0, 0, "the maximum support is 64"},
	{"TRAS_LV_METER", 0, 0, "the maximum support is 64"},
	{"LOAD_METER", 0, 0, "the maximum support is 64"},
	{"PV_METER", 0, 0, "the maximum support is 64"},
	{"DG_METER", 0, 0, "the maximum support is 64"},
	{"OTHERS_METER", 0, 0, "the maximum support is 64"},
	{"DIDO", 0, 0, "the maximum support is 64"},
	{"AIRCOND", 0, 0, "the maximum support is 64"},
	{"TMS", 0, 0, "the maximum support is 64"},
	{"PV", 0, 0, "the maximum support is 64"},
	{"DG", 0, 0, "the maximum support is 64"},
	{"FIRE", 0, 0, "the maximum support is 64"},
	{"OTHERS", 0, 0, "the maximum support is 64"},
};
static int num_mq = sizeof(_mq_home_page) / sizeof(_mq_home_page[0]);

/*
       本协议适用于简捷物联科技有限公司EMS北向与云平台之间的通信。采用 Ethernet(Mqtt)通信规约。				
设备名称	设备数量	                     备注
EMS          1	
PCS	         最大支持32个（无地址）	
主控        	 最大支持32个		
电芯	         最大支持32个		
关口表	         最大支持32个     	
储能电表	     最大支持32个     	
干接点          最大支持32个        
空调           最大支持32个         
其他           最大支持32个    
*/

// MQTT无地址概念


static void mq_write_worksheet_title(lxw_worksheet *worksheet, int row, lxw_format *format) {

	write_string_cell(worksheet, row, 0, _("TAG"), format);    // TAG
	write_string_cell(worksheet, row, 1, _("Name"),   format); // 名称
	write_string_cell(worksheet, row, 2, _("Permission"), format);   // 权限
	write_string_cell(worksheet, row, 3, _("Data type"), format);    // 数据类型 
	write_string_cell(worksheet, row, 4, _("Attribute"), format);    // 属性
	write_string_cell(worksheet, row, 5, _("Description"), format);  // 描述
	write_string_cell(worksheet, row, 6, _("Is it valid (default: valid)"), format); // 是否有效（默认：有效）
}

static const char *data_type[] = {"I32", "F32"};
static int create_mq_external_xlsx(mq_xlsx_book_t *mq_xlsx_book)
{
    chdir(NORTH_EXCEL_FILE_DOWNLOAD_PATH);

    int i = 0, j = 0;
	char dev_info[128] = "";
    mq_xlsx_book->workbook = workbook_new(mq_xlsx_book->name);
    if (mq_xlsx_book->workbook == NULL) {
		ems_syslog(LOG_ERR, "Error in workbook_new()"
               "Error = %s\n", "Failed to create the workbook!!!");
		return -1;
	}

    north_info_t *north_info = get_north_info();
	xlsx_home_page(mq_xlsx_book->workbook, north_info->protocol_type, _mq_home_page, num_mq); // 首表

	lxw_format *merge_format = create_center_bold_bg_format(mq_xlsx_book->workbook, LXW_COLOR_CYAN, 12);
    lxw_format *format1 = create_left_bold_format(mq_xlsx_book->workbook, 12);
	lxw_format *format2 = create_left_format(mq_xlsx_book->workbook, 12);
	for (i = 0; i < mq_xlsx_book->num; i++) {
		mq_xlsx_sheet_t *mq_xlsx_sheet = mq_xlsx_book->mq_xlsx_sheet[i];

	    mq_xlsx_sheet->worksheet = workbook_add_worksheet(mq_xlsx_book->workbook, _(mq_xlsx_sheet->name));
		if (mq_xlsx_sheet->worksheet == NULL){
			ems_syslog(LOG_ERR, "Error in workbook_add_worksheet()"
			        "Name %s，Error = %s\n", mq_xlsx_sheet->name, "Failed to create the worksheet!!!");
			continue;
		}
		/* Make the columns wider for clarity. */
		set_column_width(mq_xlsx_sheet->worksheet, 0, 0, 30);
		set_column_width(mq_xlsx_sheet->worksheet, 1, 1, 40);
		set_column_width(mq_xlsx_sheet->worksheet, 2, 2, 20);
		set_column_width(mq_xlsx_sheet->worksheet, 3, 3, 20);
		set_column_width(mq_xlsx_sheet->worksheet, 4, 4, 20);
		set_column_width(mq_xlsx_sheet->worksheet, 5, 5, 50);
		set_column_width(mq_xlsx_sheet->worksheet, 6, 6, 50);

		for (j = 0; j < mq_xlsx_sheet->num; j++) {
			mq_xlsx_dev_t *mq_xlsx_dev = mq_xlsx_sheet->mq_xlsx_dev[j];

		    snprintf(dev_info, 128, "no:%s  name:%s", mq_xlsx_dev->no, mq_xlsx_dev->disp_name);
	        merge_cells(mq_xlsx_sheet->worksheet, mq_xlsx_sheet->cuurent_row, 0, mq_xlsx_sheet->cuurent_row, 5, dev_info, merge_format);
			mq_xlsx_sheet->cuurent_row++;
			
			mq_write_worksheet_title(mq_xlsx_sheet->worksheet, mq_xlsx_sheet->cuurent_row, format1);
			mq_xlsx_sheet->cuurent_row++;
		
			for (int m = 0; m < mq_xlsx_dev->num; m++) {
                mq_xlsx_item_t *mq_xlsx_item = mq_xlsx_dev->mq_xlsx_item[m];
					
                write_string_cell(mq_xlsx_sheet->worksheet, mq_xlsx_sheet->cuurent_row, 0, mq_xlsx_item->name, format2);
				write_string_cell(mq_xlsx_sheet->worksheet, mq_xlsx_sheet->cuurent_row, 1, mq_xlsx_item->disp_name, format2);
				write_string_cell(mq_xlsx_sheet->worksheet, mq_xlsx_sheet->cuurent_row, 2, (mq_xlsx_item->limit == 1)?"RW":"RO", format2);
				write_string_cell(mq_xlsx_sheet->worksheet, mq_xlsx_sheet->cuurent_row, 3, data_type[mq_xlsx_item->data_type], format2);
				write_string_cell(mq_xlsx_sheet->worksheet, mq_xlsx_sheet->cuurent_row, 4, property_name[mq_xlsx_item->property], format2);

				if (mq_xlsx_item->desc != NULL && strlen(mq_xlsx_item->desc) > 0){
					write_string_cell(mq_xlsx_sheet->worksheet, mq_xlsx_sheet->cuurent_row, 5, mq_xlsx_item->desc, format2);
				}
				else
				{
					char *dynamic_desc = add_dynamic_desc(mq_xlsx_item->name);
					if (dynamic_desc != NULL) {
						write_string_cell(mq_xlsx_sheet->worksheet, mq_xlsx_sheet->cuurent_row, 5, dynamic_desc, format2);
						free(dynamic_desc);
					}
				}
				if (mq_xlsx_item->active){ // 无效
					write_string_cell(mq_xlsx_sheet->worksheet, mq_xlsx_sheet->cuurent_row, 6, _("Invalid"), format2);
		            write_string_cell(mq_xlsx_sheet->worksheet, mq_xlsx_sheet->cuurent_row, 1, _("Reserved"), format2);
				}
				mq_xlsx_sheet->cuurent_row++;
			}
			mq_xlsx_sheet->cuurent_row += DEV_BETWEEN_ROW;
		}
	}   

    /* Close the workbook, save the file and free any memory. */
    lxw_error error = workbook_close(mq_xlsx_book->workbook);

    /* Check if there was any error creating the xlsx file. */
    if (error){
        ems_syslog(LOG_ERR, "Error in workbook_close().\n"
               "Error %d = %s\n", error, lxw_strerror(error));
        return error;
    }

	return 0;
}

static const char *property[] = {"realdata", "system", "alarm"};
static char *create_mq_inside_json(mq_north_inside_t *mq_north_inside)
{
    cJSON *root = NULL;
    char *string = NULL;
	int i = 0, j = 0;
    root = cJSON_CreateObject();
    if (root == NULL)
    {
        ems_syslog(LOG_NOTICE, "cJSON_CreateObject root NULL");
        goto end;
    }
    
    // Add version field only if needed
    north_info_t *north_info = get_north_info();
    if (north_info->need_add_version) {
        cJSON_AddNumberToObject(root, "version", 2);
    }
    
    cJSON *dev_class = cJSON_CreateArray();
	cJSON_AddItemToObject(root, "dev_class", dev_class);

	for (i = 0; i < mq_north_inside->num; i++) {
		mq_north_class_t *mq_north_class = mq_north_inside->mq_north_class[i];
		
        cJSON *class = cJSON_CreateObject();
        cJSON_AddStringToObject(class, "class_type", mq_north_class->class_type);
	    cJSON_AddStringToObject(class, "name", mq_north_class->name);
	    cJSON *devs = cJSON_CreateArray();
		cJSON_AddItemToObject(class, "devs", devs);
	    cJSON_AddItemToArray(dev_class, class);
		
		for (j = 0; j < mq_north_class->num; j++) {
			mq_north_dev_t *mq_north_dev = mq_north_class->mq_north_dev[j];
			
            cJSON *dev = cJSON_CreateObject();
			cJSON_AddStringToObject(dev, "no", mq_north_dev->no);
            cJSON_AddStringToObject(dev, "name", mq_north_dev->disp_name);
			cJSON *tag_info = cJSON_CreateArray();
			cJSON_AddItemToObject(dev, "tag_info", tag_info);
            cJSON_AddItemToArray(devs, dev);

			for (int m = 0; m < mq_north_dev->num; m++) {
				mq_north_tag_t *mq_north_tag = mq_north_dev->mq_north_tag[m];
				if( mq_north_tag == NULL) continue;
                cJSON *tag = cJSON_CreateArray();
				cJSON_AddItemToArray(tag, cJSON_CreateString(mq_north_tag->tag->name));
                cJSON_AddItemToArray(tag, cJSON_CreateString(property[mq_north_tag->tag->property]));
                cJSON_AddItemToArray(tag, cJSON_CreateString(data_type[mq_north_tag->tag->data_type]));
                cJSON_AddItemToArray(tag_info, tag);
			}
		}
	}

    string = cJSON_Print(root);
end:
    if (root != NULL)
    {
        cJSON_Delete(root);
    }
    //ems_syslog(LOG_NOTICE,"%s",string);
    return string;
}

char *create_mq_relate_file(mq_north_inside_t *mq_north_inside, mq_xlsx_book_t *mq_xlsx_book){
    //int ret = 0;
	char *mq_inside_json = NULL;

	mq_inside_json = create_mq_inside_json(mq_north_inside);
	if (mq_inside_json)
	{
		if (check_file_exist(MQTT_NORTH_MAP_FILE) == 0)
			write_file_data(NORTH_CONFIG_PATH"/"MQTT_NORTH_MAP_FILE, mq_inside_json, strlen(mq_inside_json));
	}
	else
	{
		ems_syslog(LOG_ERR, "create north_mqtt.json error!!!!");
	}

    if (check_file_exist(mq_xlsx_book->name) == 0)
		create_mq_external_xlsx(mq_xlsx_book);

	return mq_inside_json;	
}
