import csv
import ctypes
import os
import re
import sqlite3
from ctypes import CDLL

from qgis.PyQt.QtCore import QThread
from qgis.PyQt.QtWidgets import QFileDialog, QProgressBar
from qgis.core import QgsVectorFileWriter, QgsCoordinateTransformContext, QgsWkbTypes, QgsRenderContext, QgsFillSymbol, \
    QgsLineSymbolLayer, QgsEmbeddedSymbolRenderer, QgsGraduatedSymbolRenderer, QgsSingleSymbolRenderer, \
    QgsCategorizedSymbolRenderer

from qgis.PyQt import QtWidgets, uic, QtCore
from qgis.PyQt.QtCore import pyqtSignal

FORM_CLASS, _ = uic.loadUiType(os.path.join(
    os.path.dirname(__file__), 'cyanlove_export_tab_kml_base.ui'))


class cyanlove_export_tab_kml(QtWidgets.QDockWidget, FORM_CLASS):
    closingPlugin = pyqtSignal()

    def __init__(self, parent=None):
        super(cyanlove_export_tab_kml, self).__init__(parent)
        self.export_thread = None
        self.setupUi(self)
        self.setFloating(True)
        self.setWindowFlags(QtCore.Qt.Dialog)  # 使对话框始终在前
        # self.setWindowModality(QtCore.Qt.ApplicationModal)  # 或者使用 Qt.WindowModal
        self.btn_export_tab.clicked.connect(self.export_tab_kml)
        self.btn_export_shanqutu.clicked.connect(self.export_tab_shanqutu)
        self.btn_export_kml.clicked.connect(self.export_tab_kml)
        self.btn_export_custom_thematic_map.clicked.connect(self.export_custom_thematic_map)

    def update_label(self, value):
        self.label_show.setText(value)  # 更新值

    def update_progress(self, value):
        self.progressBar.setValue(value)  # 更新进度条的值

    def on_thread_finished(self):
        self.label_show.setText("导出完成！")
        self.progressBar.setValue(100)

    def export_tab_kml(self):
        button = self.sender()
        button_name = ""
        if button:
            # 获取按钮的文本
            button_name = button.objectName()
            print(button_name)
        options = QFileDialog.Options()  # 创建文件对话框选项
        options |= QFileDialog.ReadOnly  # 可以设置一些选项，例如只读
        filterfile = "MapInfo TAB Files (*.tab)"
        if button_name == "btn_export_kml":
            filterfile = "KML File (*.kml)"
        file_name, _ = QFileDialog.getSaveFileName(self, "选择文件", "", filterfile, options=options)

        # 检查用户是否选择了文件
        if file_name:
            selected_layer = self.mMapLayerComboBox.currentLayer()
            if selected_layer is None:
                print("未选择有效图层!")
            else:
                print(f"选择的图层: {selected_layer.name()}")
                csv_file_path = file_name
                print(f"保存的文件：{csv_file_path}")

                # 启动导出线程
                self.export_thread = ExportThread(selected_layer, csv_file_path, button_name)
                self.export_thread.updatelabel.connect(self.update_label)
                self.export_thread.finished.connect(self.on_thread_finished)  # 导出完成后连接到槽
                self.export_thread.start()  # 启动线程

        else:
            print("用户取消了文件选择")  # 处理取消选择的情况

    def export_tab_shanqutu(self):
        options = QFileDialog.Options()  # 创建文件对话框选项
        options |= QFileDialog.ReadOnly  # 可以设置一些选项，例如只读
        filterfile = "MapInfo TAB Files (*.tab)"
        file_name, _ = QFileDialog.getSaveFileName(self, "选择文件", "", filterfile, options=options)

        # 检查用户是否选择了文件
        if file_name:
            selected_layer = self.mMapLayerComboBox.currentLayer()
            if selected_layer is None:
                self.label_show.setText("未选择有效图层!")
            else:
                print(f"选择的图层: {selected_layer.name()}")
                csv_file_path = file_name
                print(f"保存的文件：{csv_file_path}")
                geom_type = selected_layer.wkbType()

                # 如果是点图层，则调用点的缓冲
                if geom_type in [QgsWkbTypes.Polygon, QgsWkbTypes.MultiPolygon]:
                    self.progressBar.setRange(0, 100)  # 设置进度条范围
                    self.progressBar.setValue(0)  # 初始化进度条值
                    self.progressBar.show()  # 显示进度条 (如果之前是隐藏状态)
                    # 启动导出线程
                    self.export_thread = ExportThread2(selected_layer, csv_file_path)
                    self.export_thread.updatelabel.connect(self.update_label)
                    self.export_thread.progress.connect(self.update_progress)  # 连接信号到槽
                    self.export_thread.start()  # 启动线程
                else:
                    self.label_show.setText("不是扇区图Polygon格式！")
        else:
            self.label_show.setText("用户取消了文件选择")  # 处理取消选择的情况

    def export_custom_thematic_map(self):
        options = QFileDialog.Options()  # 创建文件对话框选项
        options |= QFileDialog.ReadOnly  # 可以设置一些选项，例如只读
        filterfile = "MapInfo TAB Files (*.tab)"
        file_name, _ = QFileDialog.getSaveFileName(self, "选择文件", "", filterfile, options=options)

        # 检查用户是否选择了文件
        if file_name:
            selected_layer = self.mMapLayerComboBox.currentLayer()
            if selected_layer is None:
                self.label_show.setText("未选择有效图层!")
            else:
                print(f"选择的图层: {selected_layer.name()}")
                csv_file_path = file_name
                print(f"保存的文件：{csv_file_path}")
                geom_type = selected_layer.wkbType()

                # 如果是点图层，则调用点的缓冲
                if geom_type in [QgsWkbTypes.MultiPoint, QgsWkbTypes.Polygon, QgsWkbTypes.MultiPolygon]:
                    self.progressBar.setRange(0, 100)  # 设置进度条范围
                    self.progressBar.setValue(0)  # 初始化进度条值
                    self.progressBar.show()  # 显示进度条 (如果之前是隐藏状态)
                    # 启动导出线程
                    self.export_thread = ExportThread3(selected_layer, csv_file_path)
                    self.export_thread.updatelabel.connect(self.update_label)
                    self.export_thread.progress.connect(self.update_progress)  # 连接信号到槽
                    self.export_thread.start()  # 启动线程
                else:
                    self.label_show.setText("不是Polygon格式！")
        else:
            self.label_show.setText("用户取消了文件选择")  # 处理取消选择的情况


class ExportThread(QThread):
    updatelabel = pyqtSignal(str)  # 声明一个更新label新增信号
    progress = pyqtSignal(int)  # 声明一个信号

    def __init__(self, selected_layer, savpath, button_name):
        super().__init__()  # 初始化父类
        self.savpath = savpath  # 存储
        self.button_name = button_name  # 按钮名称
        self.selected_layer = selected_layer  # QGIS 图层

    def run(self):
        self.updatelabel.emit('正在导出中...')
        field_names = [f"{field.name()}" for field in self.selected_layer.fields()]
        # 导出TAB格式
        if self.button_name == "btn_export_tab":
            # 设置导出参数
            options = QgsVectorFileWriter.SaveVectorOptions()

            options.driverName = 'MapInfo File'  # 指定输出格式为MapInfo TAB
            options.fileEncoding = 'cp936'  # 设置文件编码为cp936
            options.supportsFeatureStyles = True
            transform_context = QgsCoordinateTransformContext()  # 创建坐标转换上下文
            # 执行导出
            error = QgsVectorFileWriter.writeAsVectorFormatV3(self.selected_layer, self.savpath, transform_context,
                                                              options)

            if error[0] == QgsVectorFileWriter.NoError:
                print("导出成功！")
                # 检查是否能成功调用写入函数
                try:
                    self.writertabfilecolumn_to_gbk(self.savpath, field_names)
                    self.updatelabel.emit('导出成功!')
                except Exception as e:
                    print("写入表格时出现错误:", e)
                    self.updatelabel.emit(f'写入表格失败: {e}')
            else:
                print("导出失败：", error[1])
                self.updatelabel.emit(f'导出失败{error[1]}')

        if self.button_name == "btn_export_kml":
            # 设置导出参数
            options = QgsVectorFileWriter.SaveVectorOptions()
            options.driverName = 'KML'  # 指定输出格式为MapInfo TAB
            options.fileEncoding = 'utf-8'  # 设置文件编码为cp936
            transform_context = QgsCoordinateTransformContext()  # 创建坐标转换上下文
            # 执行导出
            error = QgsVectorFileWriter.writeAsVectorFormatV3(self.selected_layer, self.savpath, transform_context,
                                                              options)

            if error[0] == QgsVectorFileWriter.NoError:
                print("导出成功！")
                self.updatelabel.emit('导出成功!')
            else:
                print("导出失败：", error[1])
                self.updatelabel.emit(f'导出失败{error[1]}')

    def writertabfilecolumn_to_gbk(self, file_path, field_names):
        print("修改表头")
        # 读取原文件内容
        fields_list = []
        try:
            with open(file_path, 'r', encoding='utf-8', errors='replace') as file:
                content = file.readlines()
        except Exception as e:
            print(f"发生错误: {e}")
            self.updatelabel.emit(f'导出失败{e}')
            content = []

        if content:
            for i, line in enumerate(content):
                if line.strip().startswith("Fields"):
                    # 提取字段类型，将其写入数组
                    fields_list.extend(self.rx_to_str(line) for line in content[i + 1:] if line.strip())
                    break  # 找到后可结束循环

        # 字段和字段类型合并
        result = list(map(lambda x: f"\"{x[0]}\" {x[1]}", zip(field_names, fields_list)))
        # 合并格式，替换
        header = ("!table\n"
                  "!version 450\n"
                  "!charset WindowsSimpChinese\n\n"
                  "Definition Table\n"
                  "  Type NATIVE Charset \"WindowsSimpChinese\"\n"
                  "  Fields {}\n").format(len(field_names))

        fields_string = ""
        for field in result:
            fields_string += "    {}\n".format(field)
        table_definition = header + fields_string
        print(table_definition)
        try:
            with open(file_path, 'w', encoding='gbk', errors='replace') as file:
                file.write(table_definition)  # 写入字符串
        except Exception as e:
            print(f"发生错误: {e}")
            self.updatelabel.emit(f'导出失败{e}')

    @staticmethod
    def rx_to_str(textstr):
        data_types = [
            "Char",
            "Integer",
            "Smallint",
            "Float",
            "Decimal",
            "Date",
            "Time",
            "DateTime",
            "Logical"
        ]
        # 将数据类型转换为小写并创建正则表达式模式
        lower_data_types = [dtype.lower() for dtype in data_types]
        pattern = r'(' + '|'.join(re.escape(dtype) for dtype in lower_data_types) + r')\s*(\([^)]*\))?\s*;'

        # 将输入字符串转为小写
        lower_textstr = textstr.lower()

        # 从右向左查找匹配
        matches = re.findall(pattern, lower_textstr)

        # 如果找到匹配，则返回匹配项
        if matches:
            last_match = matches[-1]  # 获取最后一个匹配
            return f"{last_match[0]} {last_match[1] if last_match[1] else ''} ;".strip()  # 返回数据类型和可能的长度
        return None


# 导出扇区图(包含颜色）
class ExportThread2(QThread):
    updatelabel = pyqtSignal(str)  # 声明一个更新label新增信号
    progress = pyqtSignal(int)  # 声明一个信号

    def __init__(self, selected_layer, savpath):
        super().__init__()  # 初始化父类
        self.savpath = savpath  # 存储
        self.selected_layer = selected_layer  # QGIS 图层

    def run(self):
        self.updatelabel.emit('正在导出中...')
        field_names = [f"{field.name()}" for field in self.selected_layer.fields()]
        field_info = [(field.name(), field.typeName()) for field in self.selected_layer.fields()]
        # 导出TAB格式
        self.write_polygon_file(self.savpath, "tab", field_names, field_info)

    def write_polygon_file(self, outpath, out_mif_or_tab_type, field_names, field_info):
        # 加载 mitab64.dll
        current_dir = os.path.dirname(__file__)
        relative_path = os.path.join(current_dir, 'scripts', 'mitab64.dll')
        lib = CDLL(relative_path)
        if not lib:
            print("Failed to load the DLL.")
            return
        self.setargtypes(lib)
        try:
            # 创建数据集
            dataset = lib.mitab_c_create(
                outpath.encode('gbk'),  # windows系统路径默认gbk
                out_mif_or_tab_type.encode('utf-8'),
                "CoordSys Earth Projection 1, 104".encode('utf-8'),
                90, -90, 180, -180
            )

            if dataset is None:
                print("Failed to create the file:", out_mif_or_tab_type)
                print("Error:", lib.mitab_c_getlasterrormsg().decode('utf-8'))
                return

            # 改进的字段类型映射
            for name, typefilename in field_info:
                encoded_name = name.encode('utf-8')
                typefilename_lower = typefilename.lower()

                if typefilename_lower in ["string", "text", "char"]:
                    lib.mitab_c_add_field(dataset, encoded_name, 1, 254, 0, 0, 0)
                elif typefilename_lower in ["real", "double", "float"]:
                    lib.mitab_c_add_field(dataset, encoded_name, 5, 254, 6, 0, 0)
                elif typefilename_lower in ["integer", "int", "long"]:
                    lib.mitab_c_add_field(dataset, encoded_name, 2, 254, 0, 0, 0)
                elif typefilename_lower in ["date", "datetime", "time"]:
                    lib.mitab_c_add_field(dataset, encoded_name, 6, 254, 0, 0, 0)
                elif typefilename_lower in ["boolean", "bool"]:
                    lib.mitab_c_add_field(dataset, encoded_name, 7, 254, 0, 0, 0)  # Logical
                else:
                    # 默认处理为字符串类型
                    lib.mitab_c_add_field(dataset, encoded_name, 1, 254, 0, 0, 0)

            # 获取要素总数以计算进度
            total_features = self.selected_layer.featureCount()
            renderer = self.selected_layer.renderer()

            for index, feature in enumerate(self.selected_layer.getFeatures()):
                # 创建一个多边形 (区域类型)
                boundary_wkt = feature.geometry().asWkt()
                new_feature = lib.mitab_c_create_feature(dataset, 7)  # 7 = TABFC_Region
                # 设置多边形的点坐标 (WGS84 坐标系下的多边形顶点)
                x, y = self.wkt_to_coordinates(boundary_wkt)
                # 设置多边形的点
                lib.mitab_c_set_points(new_feature, 0, len(x), x, y)

                # 设置style - 改进的样式处理
                self.set_feature_style(lib, new_feature, renderer, feature)

                # 设置字段数据
                k = 0
                for field_name, typefilename in field_info:
                    value = feature[field_name]  # 获取每个字段的值
                    if value is None:
                        value = ""

                    typefilename_lower = typefilename.lower()
                    if typefilename_lower in ["string", "text", "char"]:
                        lib.mitab_c_set_field(new_feature, k, str(value).encode('gbk'))
                    elif typefilename_lower in ["real", "double", "float"]:
                        # 对于浮点数，确保是有效的数值
                        try:
                            float_value = float(value) if value != "" else 0.0
                            lib.mitab_c_set_field(new_feature, k, str(float_value).encode('gbk'))
                        except (ValueError, TypeError):
                            lib.mitab_c_set_field(new_feature, k, "0.0".encode('gbk'))
                    elif typefilename_lower in ["integer", "int", "long"]:
                        # 对于整数，确保是有效的数值
                        try:
                            int_value = int(value) if value != "" else 0
                            lib.mitab_c_set_field(new_feature, k, str(int_value).encode('gbk'))
                        except (ValueError, TypeError):
                            lib.mitab_c_set_field(new_feature, k, "0".encode('gbk'))
                    elif typefilename_lower in ["date", "datetime", "time"]:
                        lib.mitab_c_set_field(new_feature, k, str(value).encode('gbk'))
                    elif typefilename_lower in ["boolean", "bool"]:
                        bool_value = "T" if value else "F"
                        lib.mitab_c_set_field(new_feature, k, bool_value.encode('gbk'))
                    else:
                        # 默认处理为字符串
                        lib.mitab_c_set_field(new_feature, k, str(value).encode('gbk'))
                    k += 1

                # 写入多边形要素
                lib.mitab_c_write_feature(dataset, new_feature)
                # 销毁特征对象
                lib.mitab_c_destroy_feature(new_feature)
                # 发送进度更新
                progress_value = int((index + 1) / total_features * 100)
                self.progress.emit(progress_value)

            # 关闭数据集
            lib.mitab_c_close(dataset)
            self.writertabfilecolumn_to_gbk(self.savpath, field_names)
            self.updatelabel.emit(f'导出TAB含格式颜色完毕！')

        except Exception as e:
            self.updatelabel.emit(f"导出失败: {str(e)}")
            print(f"出错B:{str(e)}")

    def set_feature_style(self, lib, new_feature, renderer, feature):
        """设置要素样式"""
        try:
            if isinstance(renderer, (QgsEmbeddedSymbolRenderer, QgsSingleSymbolRenderer)):
                render_context = QgsRenderContext()
                symbol = renderer.symbolForFeature(feature, context=render_context)
                if symbol and symbol.symbolLayers():
                    symbol_layer = symbol.symbolLayers()[0]
                    properties = symbol_layer.properties()

                    # 获取填充颜色
                    fill_color = symbol.color()
                    fill_color_hex = fill_color.name().lstrip('#')
                    rgb_decimal_fill = int(fill_color_hex, 16) if fill_color_hex else 0
                    alpha = fill_color.alpha()

                    # 获取边框颜色和宽度
                    outline_color = properties.get('outline_color', '0,0,0,255')
                    outline_width = properties.get('outline_width', '0.5')

                    # 解析边框颜色
                    try:
                        r, g, b, a = map(int, outline_color.split(','))
                        rgb_decimal_line = (r << 16) + (g << 8) + b
                    except:
                        rgb_decimal_line = 0  # 黑色

                    # 设置填充色
                    lib.mitab_c_set_brush(new_feature, rgb_decimal_fill, rgb_decimal_fill, 2, alpha)
                    # 设置边框
                    lib.mitab_c_set_pen(new_feature, max(1, round(float(outline_width))), 2, rgb_decimal_line)

        except Exception as e:
            print(f"设置样式时出错: {e}")
            # 设置默认样式
            lib.mitab_c_set_brush(new_feature, 0xFFFFFF, 0xFFFFFF, 2, 255)  # 白色填充
            lib.mitab_c_set_pen(new_feature, 1, 2, 0)  # 黑色边框

    @staticmethod
    def setargtypes(lib):
        # 设置 mitab_c_create 函数的参数类型和返回类型
        lib.mitab_c_create.argtypes = [
            ctypes.c_char_p, ctypes.c_char_p, ctypes.c_char_p,
            ctypes.c_double, ctypes.c_double, ctypes.c_double, ctypes.c_double
        ]
        lib.mitab_c_create.restype = ctypes.POINTER(ctypes.c_void_p)

        # 设置 mitab_c_add_field 函数的参数类型和返回类型
        lib.mitab_c_add_field.argtypes = [
            ctypes.POINTER(ctypes.c_void_p), ctypes.c_char_p, ctypes.c_int, ctypes.c_int,
            ctypes.c_int, ctypes.c_int, ctypes.c_int
        ]
        lib.mitab_c_add_field.restype = ctypes.c_long

        # 设置 mitab_c_create_feature 函数的参数类型和返回类型
        lib.mitab_c_create_feature.argtypes = [
            ctypes.POINTER(ctypes.c_void_p), ctypes.c_int
        ]
        lib.mitab_c_create_feature.restype = ctypes.POINTER(ctypes.c_void_p)

        # 设置 mitab_c_set_points 函数的参数类型和返回类型
        lib.mitab_c_set_points.argtypes = [
            ctypes.POINTER(ctypes.c_void_p), ctypes.c_int, ctypes.c_int, ctypes.POINTER(ctypes.c_double),
            ctypes.POINTER(ctypes.c_double)
        ]
        lib.mitab_c_set_points.restype = None

        # 设置 mitab_c_set_brush 函数的参数类型和返回类型
        lib.mitab_c_set_brush.argtypes = [
            ctypes.POINTER(ctypes.c_void_p), ctypes.c_int, ctypes.c_int, ctypes.c_int, ctypes.c_int
        ]
        lib.mitab_c_set_brush.restype = None

        # 设置 mitab_c_set_pen 函数的参数类型和返回类型
        lib.mitab_c_set_pen.argtypes = [
            ctypes.POINTER(ctypes.c_void_p), ctypes.c_int, ctypes.c_int, ctypes.c_int
        ]
        lib.mitab_c_set_pen.restype = None

        # 设置 mitab_c_set_field 函数的参数类型
        lib.mitab_c_set_field.argtypes = [ctypes.POINTER(ctypes.c_void_p), ctypes.c_int, ctypes.c_char_p]
        lib.mitab_c_set_field.restype = None

        # 设置 mitab_c_write_feature 函数的参数类型和返回类型
        lib.mitab_c_write_feature.argtypes = [
            ctypes.POINTER(ctypes.c_void_p), ctypes.POINTER(ctypes.c_void_p)
        ]
        lib.mitab_c_write_feature.restype = None

        # 设置 mitab_c_destroy_feature 函数的参数类型
        lib.mitab_c_destroy_feature.argtypes = [ctypes.POINTER(ctypes.c_void_p)]
        lib.mitab_c_destroy_feature.restype = None

        # 设置 mitab_c_close 函数的参数类型
        lib.mitab_c_close.argtypes = [ctypes.POINTER(ctypes.c_void_p)]
        lib.mitab_c_close.restype = None

        # 设置 mitab_c_getlasterrormsg 函数的参数类型和返回类型
        lib.mitab_c_getlasterrormsg.argtypes = []
        lib.mitab_c_getlasterrormsg.restype = ctypes.c_char_p

    def writertabfilecolumn_to_gbk(self, file_path, field_names):
        print("修改表头")
        # 读取原文件内容
        fields_list = []
        try:
            with open(file_path, 'r', encoding='utf-8', errors='replace') as file:
                content = file.readlines()
        except Exception as e:
            print(f"发生错误: {e}")
            self.updatelabel.emit(f'导出失败{e}')
            content = []

        if content:
            for i, line in enumerate(content):
                if line.strip().startswith("Fields"):
                    # 提取字段类型，将其写入数组
                    fields_list.extend(self.rx_to_str(line) for line in content[i + 1:] if line.strip())
                    break  # 找到后可结束循环

        # 字段和字段类型合并
        result = list(map(lambda x: f"\"{x[0]}\" {x[1]}", zip(field_names, fields_list)))
        # 合并格式，替换
        header = ("!table\n"
                  "!version 450\n"
                  "!charset WindowsSimpChinese\n\n"
                  "Definition Table\n"
                  "  Type NATIVE Charset \"WindowsSimpChinese\"\n"
                  "  Fields {}\n").format(len(field_names))

        fields_string = ""
        for field in result:
            fields_string += "    {}\n".format(field)
        table_definition = header + fields_string
        print(table_definition)
        try:
            with open(file_path, 'w', encoding='gbk', errors='replace') as file:
                file.write(table_definition)  # 写入字符串
        except Exception as e:
            print(f"发生错误: {e}")
            self.updatelabel.emit(f'导出失败{e}')

    @staticmethod
    def rx_to_str(textstr):
        data_types = [
            "Char",
            "Integer",
            "Smallint",
            "Float",
            "Decimal",
            "Date",
            "Time",
            "DateTime",
            "Logical"
        ]
        # 将数据类型转换为小写并创建正则表达式模式
        lower_data_types = [dtype.lower() for dtype in data_types]
        pattern = r'(' + '|'.join(re.escape(dtype) for dtype in lower_data_types) + r')\s*(\([^)]*\))?\s*;'

        # 将输入字符串转为小写
        lower_textstr = textstr.lower()

        # 从右向左查找匹配
        matches = re.findall(pattern, lower_textstr)

        # 如果找到匹配，则返回匹配项
        if matches:
            last_match = matches[-1]  # 获取最后一个匹配
            return f"{last_match[0]} {last_match[1] if last_match[1] else ''} ;".strip()  # 返回数据类型和可能的长度
        return None

    @staticmethod
    def wkt_to_coordinates(wkt):
        wkt = wkt.lower()
        # 正则表达式解析 WKT 多边形
        pattern = r'polygon \(\((.*?)\)\)'
        match = re.search(pattern, wkt)

        if not match:
            raise ValueError("Invalid WKT format")

        # 提取坐标字符串并分割
        coord_str = match.group(1).strip()
        points = coord_str.split(',')

        # 初始化坐标数组
        x_coords = []
        y_coords = []

        for point in points:
            # 去除空格并分割坐标
            coords = point.strip().split()
            if len(coords) == 2:
                x, y = float(coords[0]), float(coords[1])
                x_coords.append(x)
                y_coords.append(y)

        # 转换为 ctypes 类型
        x_array = (ctypes.c_double * len(x_coords))(*x_coords)
        y_array = (ctypes.c_double * len(y_coords))(*y_coords)

        return x_array, y_array


# 导出专题地图
class ExportThread3(QThread):
    updatelabel = pyqtSignal(str)  # 声明一个更新label新增信号
    progress = pyqtSignal(int)  # 声明一个信号

    def __init__(self, selected_layer, savpath):
        super().__init__()  # 初始化父类
        self.savpath = savpath  # 存储
        self.selected_layer = selected_layer  # QGIS 图层

    def run(self):
        try:
            self.updatelabel.emit('正在导出中...')
            field_names = [f"{field.name()}" for field in self.selected_layer.fields()]
            field_info = [(field.name(), field.typeName()) for field in self.selected_layer.fields()]

            # 加载 mitab64.dll
            current_dir = os.path.dirname(__file__)
            relative_path = os.path.join(current_dir, 'scripts', 'mitab64.dll')
            lib = CDLL(relative_path)
            if not lib:
                raise Exception("无法加载 mitab64.dll")

            self.setargtypes(lib)
            self.write_polygon_file(lib, self.savpath, "tab", field_names, field_info)

        except Exception as e:
            self.updatelabel.emit(f"导出失败: {str(e)}")
            print(f"导出失败: {str(e)}")

    def write_polygon_file(self, lib, outpath, out_mif_or_tab_type, field_names, field_info):
        try:
            # 创建数据集
            dataset = lib.mitab_c_create(
                outpath.encode('gbk'),  # 使用gbk编码路径
                out_mif_or_tab_type.encode('utf-8'),
                "CoordSys Earth Projection 1, 104".encode('utf-8'),
                90.0, -90.0, 180.0, -180.0
            )

            if dataset is None:
                error_msg = lib.mitab_c_getlasterrormsg()
                raise Exception(f"创建文件失败: {error_msg.decode('utf-8') if error_msg else 'Unknown error'}")

            # 添加字段 - 改进的字段类型映射
            for name, typefilename in field_info:
                encoded_name = name.encode('utf-8')
                typefilename_lower = typefilename.lower()

                if typefilename_lower in ["string", "text", "char"]:
                    lib.mitab_c_add_field(dataset, encoded_name, 1, 254, 0, 0, 0)
                elif typefilename_lower in ["real", "double", "float", "decimal"]:
                    lib.mitab_c_add_field(dataset, encoded_name, 5, 254, 6, 0, 0)
                elif typefilename_lower in ["integer", "int", "long", "smallint"]:
                    lib.mitab_c_add_field(dataset, encoded_name, 2, 254, 0, 0, 0)
                elif typefilename_lower in ["date", "datetime", "time"]:
                    lib.mitab_c_add_field(dataset, encoded_name, 6, 254, 0, 0, 0)
                elif typefilename_lower in ["boolean", "bool", "logical"]:
                    lib.mitab_c_add_field(dataset, encoded_name, 7, 254, 0, 0, 0)
                else:
                    # 默认处理为字符串类型
                    lib.mitab_c_add_field(dataset, encoded_name, 1, 254, 0, 0, 0)

            # 获取要素总数以计算进度
            total_features = self.selected_layer.featureCount()
            renderer = self.selected_layer.renderer()

            # 支持多种渲染器类型
            for index, feature in enumerate(self.selected_layer.getFeatures()):
                # 创建一个多边形 (区域类型)
                boundary_wkt = feature.geometry().asWkt()
                new_feature = lib.mitab_c_create_feature(dataset, 7)  # 7 = TABFC_Region

                # 设置多边形的点坐标
                x, y = self.wkt_to_coordinates(boundary_wkt)
                lib.mitab_c_set_points(new_feature, 0, len(x), x, y)

                # 设置样式 - 修复专题地图颜色问题
                self.set_thematic_style(lib, new_feature, renderer, feature)

                # 设置字段数据
                k = 0
                for field_name, typefilename in field_info:
                    value = feature[field_name]
                    if value is None:
                        value = ""

                    typefilename_lower = typefilename.lower()
                    if typefilename_lower in ["string", "text", "char"]:
                        lib.mitab_c_set_field(new_feature, k, str(value).encode('gbk'))
                    elif typefilename_lower in ["real", "double", "float", "decimal"]:
                        try:
                            float_value = float(value) if value != "" else 0.0
                            lib.mitab_c_set_field(new_feature, k, str(float_value).encode('gbk'))
                        except (ValueError, TypeError):
                            lib.mitab_c_set_field(new_feature, k, "0.0".encode('gbk'))
                    elif typefilename_lower in ["integer", "int", "long", "smallint"]:
                        try:
                            int_value = int(value) if value != "" else 0
                            lib.mitab_c_set_field(new_feature, k, str(int_value).encode('gbk'))
                        except (ValueError, TypeError):
                            lib.mitab_c_set_field(new_feature, k, "0".encode('gbk'))
                    elif typefilename_lower in ["date", "datetime", "time"]:
                        lib.mitab_c_set_field(new_feature, k, str(value).encode('gbk'))
                    elif typefilename_lower in ["boolean", "bool", "logical"]:
                        bool_value = "T" if value else "F"
                        lib.mitab_c_set_field(new_feature, k, bool_value.encode('gbk'))
                    else:
                        lib.mitab_c_set_field(new_feature, k, str(value).encode('gbk'))
                    k += 1

                # 写入多边形要素
                lib.mitab_c_write_feature(dataset, new_feature)
                lib.mitab_c_destroy_feature(new_feature)

                # 发送进度更新
                progress_value = int((index + 1) / total_features * 100)
                self.progress.emit(progress_value)

            # 关闭数据集
            lib.mitab_c_close(dataset)
            self.writertabfilecolumn_to_gbk(self.savpath, field_names)
            self.updatelabel.emit('导出专题地图完毕！')

        except Exception as e:
            self.updatelabel.emit(f"导出专题地图失败: {str(e)}")
            print(f"导出专题地图失败: {str(e)}")

    def set_thematic_style(self, lib, new_feature, renderer, feature):
        """设置专题地图样式 - 修复颜色问题"""
        try:
            symbol = None

            # 分级渲染器 - 修复颜色获取问题
            if isinstance(renderer, QgsGraduatedSymbolRenderer):
                # 获取渲染字段
                render_field = renderer.classAttribute()
                value = feature[render_field]

                # 使用正确的符号获取方法
                symbol = renderer.symbolForValue(value)
                if not symbol:
                    # 如果根据值获取失败，尝试使用默认符号
                    symbol = renderer.sourceSymbol()

            # 分类渲染器
            elif isinstance(renderer, QgsCategorizedSymbolRenderer):
                category = renderer.categoryForFeature(feature)
                if category:
                    symbol = category.symbol()
                else:
                    # 如果没有匹配的分类，使用默认符号
                    symbol = renderer.sourceSymbol()

            # 单符号渲染器
            elif isinstance(renderer, QgsSingleSymbolRenderer):
                symbol = renderer.symbol()

            # 嵌入式符号渲染器
            elif isinstance(renderer, QgsEmbeddedSymbolRenderer):
                render_context = QgsRenderContext()
                symbol = renderer.symbolForFeature(feature, context=render_context)

            # 设置样式 - 确保符号存在
            if symbol:

                self.set_symbol_style(lib, new_feature, symbol)
            else:
                print("未找到符号，使用默认样式")
                # 设置默认样式
                self.set_default_style(lib, new_feature)

        except Exception as e:
            print(f"设置专题样式时出错: {e}")
            # 设置默认样式
            self.set_default_style(lib, new_feature)

    def set_symbol_style(self, lib, new_feature, symbol):
        """设置符号样式 - 修复颜色设置"""
        try:
            # 获取填充颜色
            fill_color = symbol.color()


            # 将颜色转换为 RGB 十进制值
            fill_color_hex = fill_color.name().lstrip('#')
            rgb_decimal_fill = int(fill_color_hex, 16) if fill_color_hex else 0xFFFFFF
            alpha = fill_color.alpha()

            # 获取边框样式
            outline_width = 0.3  # 默认边框宽度
            outline_color_rgb = 0  # 默认黑色边框

            if symbol.symbolLayers():
                symbol_layer = symbol.symbolLayers()[0]
                properties = symbol_layer.properties()

                # 获取边框颜色
                outline_color = properties.get('outline_color', '0,0,0,255')
                outline_width = properties.get('outline_width', '0.3')

                # 解析边框颜色
                try:
                    color_parts = outline_color.split(',')
                    if len(color_parts) >= 3:
                        r, g, b = map(int, color_parts[:3])
                        outline_color_rgb = (r << 16) + (g << 8) + b
                    else:
                        outline_color_rgb = 0  # 黑色
                except Exception as e:
                    print(f"解析边框颜色失败: {e}")
                    outline_color_rgb = 0

            # 设置填充色 - 修复颜色设置
            # mitab_c_set_brush 参数: 前景色, 背景色, 图案, 透明度
            lib.mitab_c_set_brush(new_feature, rgb_decimal_fill, rgb_decimal_fill, 2, alpha)

            # 设置边框 - 修复边框设置
            # mitab_c_set_pen 参数: 宽度, 图案, 颜色
            pen_width = max(1, round(float(outline_width)))
            lib.mitab_c_set_pen(new_feature, pen_width, 2, outline_color_rgb)



        except Exception as e:
            print(f"设置符号样式时出错: {e}")
            # 设置默认样式
            self.set_default_style(lib, new_feature)

    def set_default_style(self, lib, new_feature):
        """设置默认样式"""
        try:
            # 白色填充，黑色边框
            lib.mitab_c_set_brush(new_feature, 0xFFFFFF, 0xFFFFFF, 2, 255)
            lib.mitab_c_set_pen(new_feature, 1, 2, 0)

        except Exception as e:
            print(f"设置默认样式时出错: {e}")

    @staticmethod
    def setargtypes(lib):
        # 设置 mitab_c_create 函数的参数类型和返回类型
        lib.mitab_c_create.argtypes = [
            ctypes.c_char_p, ctypes.c_char_p, ctypes.c_char_p,
            ctypes.c_double, ctypes.c_double, ctypes.c_double, ctypes.c_double
        ]
        lib.mitab_c_create.restype = ctypes.POINTER(ctypes.c_void_p)

        # 设置 mitab_c_add_field 函数的参数类型和返回类型
        lib.mitab_c_add_field.argtypes = [
            ctypes.POINTER(ctypes.c_void_p), ctypes.c_char_p, ctypes.c_int, ctypes.c_int,
            ctypes.c_int, ctypes.c_int, ctypes.c_int
        ]
        lib.mitab_c_add_field.restype = ctypes.c_long

        # 设置 mitab_c_create_feature 函数的参数类型和返回类型
        lib.mitab_c_create_feature.argtypes = [
            ctypes.POINTER(ctypes.c_void_p), ctypes.c_int
        ]
        lib.mitab_c_create_feature.restype = ctypes.POINTER(ctypes.c_void_p)

        # 设置 mitab_c_set_points 函数的参数类型和返回类型
        lib.mitab_c_set_points.argtypes = [
            ctypes.POINTER(ctypes.c_void_p), ctypes.c_int, ctypes.c_int, ctypes.POINTER(ctypes.c_double),
            ctypes.POINTER(ctypes.c_double)
        ]
        lib.mitab_c_set_points.restype = None

        # 设置 mitab_c_set_brush 函数的参数类型和返回类型
        lib.mitab_c_set_brush.argtypes = [
            ctypes.POINTER(ctypes.c_void_p), ctypes.c_int, ctypes.c_int, ctypes.c_int, ctypes.c_int
        ]
        lib.mitab_c_set_brush.restype = None

        # 设置 mitab_c_set_pen 函数的参数类型和返回类型
        lib.mitab_c_set_pen.argtypes = [
            ctypes.POINTER(ctypes.c_void_p), ctypes.c_int, ctypes.c_int, ctypes.c_int
        ]
        lib.mitab_c_set_pen.restype = None

        # 设置 mitab_c_set_field 函数的参数类型
        lib.mitab_c_set_field.argtypes = [ctypes.POINTER(ctypes.c_void_p), ctypes.c_int, ctypes.c_char_p]
        lib.mitab_c_set_field.restype = None

        # 设置 mitab_c_write_feature 函数的参数类型和返回类型
        lib.mitab_c_write_feature.argtypes = [
            ctypes.POINTER(ctypes.c_void_p), ctypes.POINTER(ctypes.c_void_p)
        ]
        lib.mitab_c_write_feature.restype = None

        # 设置 mitab_c_destroy_feature 函数的参数类型
        lib.mitab_c_destroy_feature.argtypes = [ctypes.POINTER(ctypes.c_void_p)]
        lib.mitab_c_destroy_feature.restype = None

        # 设置 mitab_c_close 函数的参数类型
        lib.mitab_c_close.argtypes = [ctypes.POINTER(ctypes.c_void_p)]
        lib.mitab_c_close.restype = None

        # 设置 mitab_c_getlasterrormsg 函数的参数类型和返回类型
        lib.mitab_c_getlasterrormsg.argtypes = []
        lib.mitab_c_getlasterrormsg.restype = ctypes.c_char_p

    def writertabfilecolumn_to_gbk(self, file_path, field_names):
        print("修改表头")
        # 读取原文件内容
        fields_list = []
        try:
            with open(file_path, 'r', encoding='utf-8', errors='replace') as file:
                content = file.readlines()
        except Exception as e:
            print(f"发生错误: {e}")
            self.updatelabel.emit(f'导出失败{e}')
            content = []

        if content:
            for i, line in enumerate(content):
                if line.strip().startswith("Fields"):
                    # 提取字段类型，将其写入数组
                    fields_list.extend(self.rx_to_str(line) for line in content[i + 1:] if line.strip())
                    break  # 找到后可结束循环

        # 字段和字段类型合并
        result = list(map(lambda x: f"\"{x[0]}\" {x[1]}", zip(field_names, fields_list)))
        # 合并格式，替换
        header = ("!table\n"
                  "!version 450\n"
                  "!charset WindowsSimpChinese\n\n"
                  "Definition Table\n"
                  "  Type NATIVE Charset \"WindowsSimpChinese\"\n"
                  "  Fields {}\n").format(len(field_names))

        fields_string = ""
        for field in result:
            fields_string += "    {}\n".format(field)
        table_definition = header + fields_string
        print(table_definition)
        try:
            with open(file_path, 'w', encoding='gbk', errors='replace') as file:
                file.write(table_definition)  # 写入字符串
        except Exception as e:
            print(f"发生错误: {e}")
            self.updatelabel.emit(f'导出失败{e}')

    @staticmethod
    def rx_to_str(textstr):
        data_types = [
            "Char",
            "Integer",
            "Smallint",
            "Float",
            "Decimal",
            "Date",
            "Time",
            "DateTime",
            "Logical"
        ]
        # 将数据类型转换为小写并创建正则表达式模式
        lower_data_types = [dtype.lower() for dtype in data_types]
        pattern = r'(' + '|'.join(re.escape(dtype) for dtype in lower_data_types) + r')\s*(\([^)]*\))?\s*;'

        # 将输入字符串转为小写
        lower_textstr = textstr.lower()

        # 从右向左查找匹配
        matches = re.findall(pattern, lower_textstr)

        # 如果找到匹配，则返回匹配项
        if matches:
            last_match = matches[-1]  # 获取最后一个匹配
            return f"{last_match[0]} {last_match[1] if last_match[1] else ''} ;".strip()  # 返回数据类型和可能的长度
        return None

    @staticmethod
    def wkt_to_coordinates(wkt):
        wkt = wkt.lower()
        # 正则表达式解析 WKT 多边形
        pattern = r'polygon \(\((.*?)\)\)'
        match = re.search(pattern, wkt)

        if not match:
            raise ValueError("Invalid WKT format")

        # 提取坐标字符串并分割
        coord_str = match.group(1).strip()
        points = coord_str.split(',')

        # 初始化坐标数组
        x_coords = []
        y_coords = []

        for point in points:
            # 去除空格并分割坐标
            coords = point.strip().split()
            if len(coords) == 2:
                x, y = float(coords[0]), float(coords[1])
                x_coords.append(x)
                y_coords.append(y)

        # 转换为 ctypes 类型
        x_array = (ctypes.c_double * len(x_coords))(*x_coords)
        y_array = (ctypes.c_double * len(y_coords))(*y_coords)

        return x_array, y_array