#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 "xlsxwriter_compat.h"
#include "xlsx_api.h"

static const char *_pro_dec_CN[] = {
	"",
	"本协议适用于简捷物联科技有限公司EMS北向与云平台之间的通信。采用 Ethernet(Mqtt)通信规约",
    "本协议适用于简捷物联科技有限公司EMS北向与Modbus主站之间的通信，默认端口：502。采用 Ethernet(Modbus TCP)通信规约，多字节统一使用大端格式，设备地址和寄存器地址(十进制)",
    "本协议适用于简捷物联科技有限公司EMS北向与104主站的通信，默认端口：2404。采用 Ethernet(IEC104规约2002版)通信规约，ASDU地址和寄存器地址(十进制)"
};

static const char *_pro_dec_US[] = {
	"",
	"This agreement applies to the communication between EMS and the cloud platform of Lnxall Technologies Ltd. It adopts the Ethernet(MQTT) communication protocol.",
    "This agreement applies to the communication between EMS and the Modbus master station. The default port is 502. It adopts the Ethernet(Modbus TCP) communication protocol. Multi-byte data uniformly uses the big-endian format, and the device addresses and register addresses are in decimal.",
    "This agreement applies to the communication between EMS and the IEC104 master station. The default port is 2404. It adopts the Ethernet(IEC104 2002 Edition) communication protocol, and the ASDU addresses and register addresses are in decimal."
};


lxw_format *create_center_format(lxw_workbook *workbook, int font_size) {  
    lxw_format *format = workbook_add_format(workbook);  
    format_set_align(format, LXW_ALIGN_CENTER);  
    format_set_align(format, LXW_ALIGN_CENTER);
    format_set_text_wrap(format);  // 设置文本自动换行
    format_set_font_size(format, font_size);  
    return format;  
}  
  
// 创建一个居中对齐且加粗的格式  
lxw_format *create_center_bold_format(lxw_workbook *workbook, int font_size) {  
    lxw_format *format = create_center_format(workbook, font_size);  
    format_set_bold(format);  
    return format;  
}  
  
// 创建一个居中对齐、加粗且带有背景色的格式  
lxw_format *create_center_bold_bg_format(lxw_workbook *workbook, lxw_color_t bg_color, int font_size) {  
    lxw_format *format = create_center_bold_format(workbook, font_size);  
    format_set_bg_color(format, bg_color);  
    return format;  
}  


lxw_format *create_left_format(lxw_workbook *workbook, int font_size) {  
    lxw_format *format = workbook_add_format(workbook);  
    format_set_align(format, LXW_ALIGN_CENTER);  
    format_set_align(format, LXW_ALIGN_LEFT);
    format_set_text_wrap(format);  // 设置文本自动换行
    format_set_font_size(format, font_size);  
    return format;  
}  
  
// 创建一个居左对齐且加粗的格式  
lxw_format *create_left_bold_format(lxw_workbook *workbook, int font_size) {  
    lxw_format *format = create_left_format(workbook, font_size);  
    format_set_bold(format);  
    return format;  
}  
#if 0  
// 创建一个居左对齐、加粗且带有背景色的格式  
lxw_format *create_left_bold_bg_format(lxw_workbook *workbook, lxw_color_t bg_color, int font_size) {  
    lxw_format *format = create_left_bold_format(workbook, font_size);  
    format_set_bg_color(format, bg_color);  
    return format;  
}
#endif

void write_string_cell(lxw_worksheet *worksheet, int row, int col, const char *string, lxw_format *format) {  
    lxw_error error = worksheet_write_string(worksheet, row, col, string, format);  
    if (error){
        ems_syslog(LOG_ERR, "Error in worksheet_write_string().\n"
               "string %s，Error %d = %s\n", string, error, lxw_strerror(error));
    }	
}  
   
void write_number_cell(lxw_worksheet *worksheet, int row, int col, double number, lxw_format *format) {  
    lxw_error error = worksheet_write_number(worksheet, row, col, number, format);  
    if (error){
        ems_syslog(LOG_ERR, "Error in worksheet_write_number().\n"
               "number %f，Error %d = %s\n", number, error, lxw_strerror(error));
    }	
}  

void set_column_width(lxw_worksheet *worksheet, int first_col, int last_col, double width) {
    lxw_error error = worksheet_set_column(worksheet, first_col, last_col, width, NULL);
    if (error){
        ems_syslog(LOG_ERR, "Error in worksheet_set_column().\n"
               "Error %d = %s\n", error, lxw_strerror(error));
    }
}

void set_row_height(lxw_worksheet *worksheet, int row, double height) {
    lxw_error error = worksheet_set_row(worksheet, row, height, NULL);
    if (error){
        ems_syslog(LOG_ERR, "Error in worksheet_set_row().\n"
               "Error %d = %s\n", error, lxw_strerror(error));
    }
}

void merge_cells(lxw_worksheet *worksheet, int first_row, int first_col, int last_row, int last_col, const char *data, lxw_format *format) {
    lxw_error error = worksheet_merge_range(worksheet, first_row, first_col, last_row, last_col, data, format);
    if (error){
        ems_syslog(LOG_ERR, "Error in worksheet_merge_range().\n"
               "Error %d = %s\n", error, lxw_strerror(error));
    }
}

// xlsx表首页
int xlsx_home_page(lxw_workbook *workbook, n_protocol_type_t type, home_page_t *home_page, int num)
{
    north_info_t *north_info = get_north_info();
	const char **_pro_dec = north_info->language ? _pro_dec_CN : _pro_dec_US;

	int ret = 0;
	lxw_worksheet *worksheet = workbook_add_worksheet(workbook, _("Address code allocation")); // 地址码分配
	if (worksheet == NULL) {
		ems_syslog(LOG_ERR, "Error in workbook_add_worksheet()"
				"Error = %s\n", "Failed to create the worksheet!!!");
		return -1;
	}

	set_column_width(worksheet, 0, 2, 30);
	set_column_width(worksheet, 3, 3, 40);
	set_row_height(worksheet, 0, 80);

	lxw_format *merge_format = create_center_bold_bg_format(workbook, LXW_COLOR_CYAN, 12);
	merge_cells(worksheet, 0, 0, 0, 3, _pro_dec[type], merge_format);

	lxw_format *format1 = create_left_bold_format(workbook, 12);
	write_string_cell(worksheet, 1, 0, _("Device name"), format1);       // 设备名称
	write_string_cell(worksheet, 1, 1, _("Start address code"), format1);// 起始地址码
	write_string_cell(worksheet, 1, 2, _("End address code"), format1);  // 结束地址码
	write_string_cell(worksheet, 1, 3, _("Remarks"), format1);           // 备注

	lxw_format *format2 = create_left_format(workbook, 12);
	int row = 2;
	for (int i = 0; i < num; i++) {
		home_page_t *home_page_item = &home_page[i];
		write_string_cell(worksheet, row, 0, _(home_page_item->name), format2);
		write_number_cell(worksheet, row, 1, home_page_item->s_addr, format2);
		write_number_cell(worksheet, row, 2, home_page_item->e_addr, format2);
		if (strlen(home_page_item->dec) > 0)
			write_string_cell(worksheet, row, 3, _(home_page_item->dec), format2);
		row++;
	}

	char buffer[64];
	char creat_tim[BOOK_NAME_LEN] = ""; 
	time_t now = time(NULL);

	struct tm target_time = {};  
    localtime_r(&now, &target_time);
    struct tm *tim = &target_time;

	strftime(buffer, 64, "%Y-%m-%d %H:%M:%S", tim);
	snprintf(creat_tim, sizeof(creat_tim), "%s: %s", _("Creation time"), buffer); // 创建时间
	merge_cells(worksheet, row, 0, row, 3, creat_tim, format2);

	return ret;
}

static const char DYN_CAP_DESC_CN[] = "动态增容模式使用";
static const char DYN_CAP_DESC_EN[] = "Use of dynamic capacity expansion mode";
static const char HB_DESC_CN[] =
	"每5秒对该点位进行0/1切换写入,当该点位1分钟未变化时,自动停机";
static const char HB_DESC_EN[] =
	"Switch the value of this point between 0 and 1 every 5 seconds. "
	"If the value remains unchanged for 1 minute, trigger an automatic shutdown.";

typedef struct {
	const char *tag;
	const char *desc_cn;
	const char *desc_en;
} dynamic_desc_entry_t;

static const dynamic_desc_entry_t g_dynamic_desc_tab[] = {
	{ "DemandStartHour",      DYN_CAP_DESC_CN, DYN_CAP_DESC_EN },
	{ "DemandStartMin",       DYN_CAP_DESC_CN, DYN_CAP_DESC_EN },
	{ "DemandEndHour",        DYN_CAP_DESC_CN, DYN_CAP_DESC_EN },
	{ "DemandEndMin",         DYN_CAP_DESC_CN, DYN_CAP_DESC_EN },
	{ "chargeStartPower",     DYN_CAP_DESC_CN, DYN_CAP_DESC_EN },
	{ "dischargeThreshold",   DYN_CAP_DESC_CN, DYN_CAP_DESC_EN },
	{ "Iec104Heartbeat",      HB_DESC_CN,      HB_DESC_EN },
	{ "ModbusTcpHeartbeat",   HB_DESC_CN,      HB_DESC_EN },
};

static char *dup_lang_desc(const char *desc_cn, const char *desc_en, int language,
			   const char *tagname)
{
	const char *desc = language ? desc_cn : desc_en;
	char *new_desc = strdup(desc);

	if (new_desc == NULL) {
		ems_syslog(LOG_ERR, "add_dynamic_desc: strdup failed for tag %s", tagname);
	}
	return new_desc;
}

char *add_dynamic_desc(const char *tagname)
{
	const north_info_t *north_info = get_north_info();

	if (tagname == NULL || tagname[0] == '\0' || north_info == NULL) {
		return NULL;
	}

	for (size_t i = 0; i < sizeof(g_dynamic_desc_tab) / sizeof(g_dynamic_desc_tab[0]); i++) {
		if (strcmp(tagname, g_dynamic_desc_tab[i].tag) != 0) {
			continue;
		}
		return dup_lang_desc(g_dynamic_desc_tab[i].desc_cn,
				     g_dynamic_desc_tab[i].desc_en,
				     north_info->language, tagname);
	}

	return NULL;
}

