# -*- coding: utf-8 -*-
"""
/***************************************************************************
 MirGradDTP
                                 A QGIS plugin
 Набор инструментов для работы с материалами документации территориального планирования
 Generated by Plugin Builder: http://g-sherman.github.io/Qgis-Plugin-Builder/
                              -------------------
        copyright            : (C) 2024 by I.Bukharin/Mirproekt
        email                : iabukharin@gmail.com
 ***************************************************************************/
"""
from qgis.PyQt.QtCore import (QSettings, QTranslator, QCoreApplication, QVariant, Qt, QSize, QPoint, QUrl, QPointF)
from qgis.PyQt.QtGui import QIcon, QImage, QPainter, QFont, QPixmap, QPolygonF
from qgis.PyQt.QtWidgets import QAction, QTreeWidgetItem, QTreeWidgetItemIterator, QProgressBar
from qgis.core import (QgsGeometry, QgsPointXY, QgsCoordinateReferenceSystem, QgsFeature, QgsField, QgsProject, QgsExpressionContext, QgsVectorLayerUtils,
                       QgsExpressionContextUtils,QgsMapLayerType, QgsFields, QgsApplication, QgsRenderContext, QgsLayoutItemPolygon, QgsProperty,
                       QgsUnitTypes, QgsLayoutPoint, QgsPrintLayout, QgsLayoutItemLabel, QgsVectorDataProvider, QgsLayoutItemPolyline, QgsLayoutSize,
                       QgsLayoutItemPicture, QgsLayoutItemGroup, QgsVectorLayer, QgsCoordinateTransform, QgsExpression, Qgis, NULL, QgsFeatureRequest, QgsLayoutItem, QgsLayoutItemMarker)
from qgis.gui import QgsProjectionSelectionDialog, QgsLayerTreeViewIndicator, QgsFileWidget

from .resources import *

import json
from re import findall

from .ui.mirgrad_dtp_dialog import MirGradDTPDialog
from .ui.mirgrad_dtp_dialog_createLayers import MirGradDTPDialogCreateLayers
from .ui.mirgrad_dtp_dialog_applyStyless import MirGradDTPDialogApplyStyles
from .ui.mirgrad_dtp_dialog_import import MirGradDTPDialogImport
from .ui.mirgrad_dtp_dialog_checkLayers import MirGradDTPDialogCheckLayers
from .ui.mirgrad_dtp_dialog_searchObject import MirGradDTPDialogSearchObject
from .ui.mirgrad_dtp_dialog_checkReport import MirGradDTPDialogCheckReport
from .ui.mirgrad_dtp_dialog_select_classType import MirGradDTPDialogSelectClass
from .ui.mirgrad_dtp_dialog_chooseExportPlace import MirGradDTPchooseExportPlace
from .ui.mirgrad_dtp_dialog_chooseLayers import MirGradDTPDialogChooseLayers
from .ui.mirgrad_dtp_dialog_setupLegend import MirGradDTPDialogSetupLegend
from .ui.mirgrad_dtp_dialog_About import MirGradDTPDialogAbout
from .ui.mirgrad_dtp_dialog_setupGML import MirGradDTPDialogSetupGML
from .ui.mirgrad_dtp_dialog_coord import MirGradDTPDialogCoord
import os

from copy import deepcopy
import pandas as pd
import zipfile

from .func.parseFgistpXSD import parseFgistpXSD
from .func.applyFieldsConstrains import applyFieldConstrainsOrder10, applyStyleSymbols, delNullSymbols
from .func.createDTPlayers import createDPTlayersOrder10, getLayersName, move_to_group
from .func.checkLayersFuncs import checkLayerOnFields, checkFeatures
from .func.autoCorrectFeature import autoCorrectGlobalID, deleteFeatureWithoutGeometry, fillGeometrysAtttribs, fillOKTMO, fillZuNumber, nullIfAttrib
from .func.exportGML import createGMLstring, checkAttrValueForNull
from .func.compareFgisXSD import compareFgisXSD
from .func.getLayerClasstypeOrder10 import getLayerClassTypeOrder10_v2
from .func.licTvs import LicTvs

class MirGradDTP:
    def __init__(self, iface):
        self.iface = iface
        self.plugin_dir = os.path.dirname(__file__)
        self.actions = []
        self.menu = self.tr(u'&МирГрадЪ ДТП')
        self.dtpPluginToolbar = None

        self.first_start = None

        self.defXSD = self.plugin_dir + '/res/DTP_demo.xsd'
        self.licMngr = LicTvs(self.defXSD)
        self.simpleTypes = None
        self.complexTypes = None
        self.elementTypes = None
        self.groupDict = None
        self.baseLayersDict = dict()

        self.baseLayerIcon = QIcon(':/plugins/mirgrad_dtp/icon.png')
        list_of_qml_files = []
        for root, folder, files in os.walk(self.plugin_dir + '/res/Symbols/QML/'):
            for file in files: # For all files in folder, including files in subdirectories
                if file.endswith(('.qml', '.QML')):#, '.zip')): #Find the files
                    fullname=os.path.join(root, file) #Combine path and filename
                    list_of_qml_files.append(os.path.normpath(fullname))
        strForChange = r'C:\Users/user/AppData/Roaming/QGIS/QGIS3\profiles\default/python/plugins\mirgrad/res/Symbols'
        strForChange2 = r'C:\Users/user/AppData/Roaming/QGIS/QGIS3\profiles\default/python/plugins\mirgrad_dtp/res/Symbols'
        gifPath = self.plugin_dir + '/res/Symbols'
        for qmlPath in list_of_qml_files:
            if os.path.isfile(qmlPath):
                qmlStr = ''
                with open(qmlPath) as f:
                    qmlStr = f.read()
                if strForChange in qmlStr or strForChange2 in qmlStr:
                    with open(qmlPath, 'w') as f:
                        qmlStr = qmlStr.replace(strForChange, gifPath)
                        qmlStr = qmlStr.replace(strForChange2, gifPath)
                        f.write(qmlStr)

    # noinspection PyMethodMayBeStatic
    def tr(self, message):
        """Get the translation for a string using Qt translation API.

        We implement this ourselves since we do not inherit QObject.

        :param message: String for translation.
        :type message: str, QString

        :returns: Translated version of message.
        :rtype: QString
        """
        # noinspection PyTypeChecker,PyArgumentList,PyCallByClass
        return QCoreApplication.translate('MirGradDTP', message)

    def add_action(
        self,
        icon_path,
        text,
        callback,
        enabled_flag=True,
        add_to_menu=True,
        add_to_toolbar=True,
        status_tip=None,
        whats_this=None,
        parent=None):
        """Add a toolbar icon to the toolbar.

        :param icon_path: Path to the icon for this action. Can be a resource
            path (e.g. ':/plugins/foo/bar.png') or a normal file system path.
        :type icon_path: str

        :param text: Text that should be shown in menu items for this action.
        :type text: str

        :param callback: Function to be called when the action is triggered.
        :type callback: function

        :param enabled_flag: A flag indicating if the action should be enabled
            by default. Defaults to True.
        :type enabled_flag: bool

        :param add_to_menu: Flag indicating whether the action should also
            be added to the menu. Defaults to True.
        :type add_to_menu: bool

        :param add_to_toolbar: Flag indicating whether the action should also
            be added to the toolbar. Defaults to True.
        :type add_to_toolbar: bool

        :param status_tip: Optional text to show in a popup when mouse pointer
            hovers over the action.
        :type status_tip: str

        :param parent: Parent widget for the new action. Defaults None.
        :type parent: QWidget

        :param whats_this: Optional text to show in the status bar when the
            mouse pointer hovers over the action.

        :returns: The action that was created. Note that the action is also
            added to self.actions list.
        :rtype: QAction
        """

        icon = QIcon(icon_path)
        action = QAction(icon, text, parent)
        action.triggered.connect(callback)
        action.setEnabled(enabled_flag)

        if status_tip is not None:
            action.setStatusTip(status_tip)

        if whats_this is not None:
            action.setWhatsThis(whats_this)

        if add_to_toolbar:
            self.dtpPluginToolbar.addAction(action)

        if add_to_menu:
            self.iface.addPluginToMenu(self.menu, action)

        self.actions.append(action)
        return action

    def initGui(self):
        self.dtpPluginToolbar = self.iface.addToolBar('МирГрадЪ ДТП')
        self.dtpPluginToolbar.setObjectName('MirGradDTPtoolBar')

        self.dlgCoord = MirGradDTPDialogCoord()
        self.dlg = MirGradDTPDialog()
        self.dlg.pushButton.clicked.connect(self.licMngr.showDlgLicTvs)
        #self.dlg.mQgsFileWidget.setDefaultRoot(self.plugin_dir + '/res')

        self.dlgCreateLayers = MirGradDTPDialogCreateLayers()
        self.dlgApplyStyles = MirGradDTPDialogApplyStyles()
        self.dlgImport = MirGradDTPDialogImport()
        self.dlgImport.iface = self.iface
        self.dlgCheck = MirGradDTPDialogCheckLayers()
        self.dlgSearchObj = MirGradDTPDialogSearchObject()
        self.dlgCheckReport = MirGradDTPDialogCheckReport()
        self.dlgSelectClass = MirGradDTPDialogSelectClass()

        self.dlgchooseExportPlace = MirGradDTPchooseExportPlace()
        self.dlgchooseExportPlace.mQgsFileWidget.setDefaultRoot(self.plugin_dir)

        self.dlgChooseLayers = MirGradDTPDialogChooseLayers()
        
        self.dlgSetupLegend = MirGradDTPDialogSetupLegend()

        self.dlgSetupGML = MirGradDTPDialogSetupGML()

        self.dlgAbout = MirGradDTPDialogAbout()
        url = QUrl.fromLocalFile(self.plugin_dir + '/res/Help.md')
        self.dlgAbout.textBrowser.setSource(url)

        self.myIndicator = QgsLayerTreeViewIndicator()
        self.myIndicator.setIcon(self.baseLayerIcon)
        self.myIndicator.setToolTip('Относится к базовым слоям')

        """Create the menu entries and toolbar icons inside the QGIS GUI."""

        self.iface.addCustomActionForLayerType( self.add_action(
            ':/plugins/mirgrad_dtp/icon.png',
            text=self.tr(u'Скопировать таблицу атрибутов в буфер обмена'),
            callback=self.copyAttrTableToClipBoard,
            enabled_flag=True,
            add_to_menu=False,
            add_to_toolbar=False,
            parent=self.iface.mainWindow()), '', QgsMapLayerType.VectorLayer, True)

        icon_path = ':/plugins/mirgrad_dtp/iconSetup.png'
        self.add_action(
            icon_path,
            text=self.tr(u'Настройки'),
            callback=self.run,
            add_to_toolbar=False,
            parent=self.iface.mainWindow())
        
        icon_path = ':/plugins/mirgrad_dtp/iconCreateLayers.png'
        self.add_action(
            icon_path,
            text=self.tr(u'Создание слоев'),
            callback=self.createLayers,
            parent=self.iface.mainWindow())
        
        icon_path = ':/plugins/mirgrad_dtp/iconImport.png'
        self.add_action(
            icon_path,
            text=self.tr(u'Импорт данных'),
            callback=self.importData,
            enabled_flag=False,
            parent=self.iface.mainWindow())
        
        icon_path = ':/plugins/mirgrad_dtp/iconApplyStyles.png'
        self.add_action(
            icon_path,
            text=self.tr(u'Применение стилей'),
            callback=self.applyStyles,
            enabled_flag=False,
            parent=self.iface.mainWindow())
        
        icon_path = ':/plugins/mirgrad_dtp/iconDellNullStyles.png'
        self.add_action(
            icon_path,
            text=self.tr(u'Удалить условные обозначения отсутствующих объектов'),
            callback=self.dellUZnak,
            enabled_flag=False,
            parent=self.iface.mainWindow())
        
        icon_path = ':/plugins/mirgrad_dtp/iconCheckLayers.png'
        self.add_action(
            icon_path,
            text=self.tr(u'Проверка слоев'),
            callback=self.checkLayers,
            enabled_flag=False,
            parent=self.iface.mainWindow())
        
        icon_path = ':/plugins/mirgrad_dtp/iconExportPlanOKS.png'
        self.add_action(
            icon_path,
            text=self.tr(u'Экспорт планируемых объектов'),
            callback=self.exportPlanOKS,
            enabled_flag=False,
            parent=self.iface.mainWindow())
        
        icon_path = ':/plugins/mirgrad_dtp/iconExportGML.png'
        self.add_action(
            icon_path,
            text=self.tr(u'Экспорт в GML для ФГИС ТП'),
            callback=self.exportGMLfgis,
            enabled_flag=False,
            parent=self.iface.mainWindow())
        
        icon_path = ':/plugins/mirgrad_dtp/iconSearchGLOBALID.png'
        self.add_action(
            icon_path,
            text=self.tr(u'Поиск объекта'),
            callback=self.searchObject,
            enabled_flag=False,
            parent=self.iface.mainWindow())
        
        icon_path = ':/plugins/mirgrad_dtp/iconLegend.png'
        self.add_action(
            icon_path,
            text=self.tr(u'Построить легенду'),
            callback=self.createLegendV2,
            enabled_flag=False,
            parent=self.iface.mainWindow())
        
        icon_path = ':/plugins/mirgrad_dtp/iconCoordBound.png'
        self.add_action(
            icon_path,
            text=self.tr(u'Формирование перечня координат'),
            callback=self.createCoordList,
            add_to_toolbar=False,
            parent=self.iface.mainWindow())

        icon_path = ':/plugins/mirgrad_dtp/iconHelp.png'
        self.add_action(
            icon_path,
            text=self.tr(u'Помощь'),
            callback=self.help,
            enabled_flag=True,
            parent=self.iface.mainWindow())

        self.iface.layerTreeView().selectionModel().selectionChanged.connect(self.eventToSelectLayers)

        self.first_start = True
        #self.dlg.mQgsFileWidget.setFilePath(self.defXSD)
        self.first_start = self.initTypes(self.defXSD)
        if not self.first_start:
            self.initGuiDlgChoseLayer(baseGeomFlag=True)

    def initGuiDlgChoseLayer(self, baseGeomFlag=True):
        layersTree = dict()
        """ layersTree = {наименование группы : {
            наименование слоя: {
                'point': False,
                'polyline': False,
                'polygon': False,
                'note': 'описание',
                'baseGeom:
                }
            }} """
        for element in self.elementTypes:
            mirGroup = self.elementTypes[element].get('mirGroup', 'noneGroup')
            if mirGroup == '':
                mirGroup = 'noneGroup'
            if mirGroup not in list(layersTree.keys()):
                layersTree[mirGroup] = dict()
            elementTypeName = self.elementTypes[element]['elementType'].replace('fgistp:', '')
            if elementTypeName in list(self.complexTypes.keys()):
                complexType = self.complexTypes[elementTypeName]
                if len(complexType['geometryTypes']) > 0 and 'CLASSID' in list(complexType['attributes'].keys()):
                    layersTree[mirGroup][element] = {
                        'point': False,
                        'polyline': False,
                        'polygon': False,
                        'note': self.elementTypes[element].get('typeUserName', ''),
                        'baseGeom': ''
                    }
                    for ind, geomType in enumerate(complexType['geometryTypes']):
                        if geomType in ['gml:Polygon', 'gml:Surface', 'gml:MultiSurface']:
                            layersTree[mirGroup][element]['polygon'] = True
                            if ind == 0: layersTree[mirGroup][element]['baseGeom'] = 'polygon'
                        elif geomType in ['gml:Curve', 'gml:LineString', 'gml:MultiCurve']:
                            layersTree[mirGroup][element]['polyline'] = True
                            if ind == 0: layersTree[mirGroup][element]['baseGeom'] = 'polyline'
                        elif geomType in ['gml:Point', 'gml:MultiPoint']:
                            layersTree[mirGroup][element]['point'] = True
                            if ind == 0: layersTree[mirGroup][element]['baseGeom'] = 'point'
        for ind in range(self.dlgChooseLayers.treeWidget.topLevelItemCount() - 1, -1, -1):
            self.dlgChooseLayers.treeWidget.takeTopLevelItem(ind)
        for parentName in list(layersTree.keys()):
            parent = QTreeWidgetItem(self.dlgChooseLayers.treeWidget)
            parent.setText(0, parentName)
            parent.setFlags(parent.flags() | Qt.ItemIsTristate | Qt.ItemIsUserCheckable)
            for layersName in list(layersTree[parentName].keys()):
                child = QTreeWidgetItem(parent)
                child.setFlags(child.flags() | Qt.ItemIsUserCheckable)
                child.setText(0, layersName)
                child.setCheckState(0, Qt.Checked)
                child.setText(4, layersTree[parentName][layersName]['note'])
                if layersTree[parentName][layersName]['point']:
                    child.setText(1, "")
                    if baseGeomFlag and layersTree[parentName][layersName]['baseGeom'] == 'point' or not baseGeomFlag:
                        child.setCheckState(1, Qt.Checked)
                    else:
                        child.setCheckState(1, Qt.Unchecked)
                else:
                    child.setText(1, "")
                if layersTree[parentName][layersName]['polyline']:
                    child.setText(2, "")
                    if baseGeomFlag and layersTree[parentName][layersName]['baseGeom'] == 'polyline' or not baseGeomFlag:
                        child.setCheckState(2, Qt.Checked)
                    else:
                        child.setCheckState(2, Qt.Unchecked)
                else:
                    child.setText(2, "")
                if layersTree[parentName][layersName]['polygon']:
                    child.setText(3, "")
                    if baseGeomFlag and layersTree[parentName][layersName]['baseGeom'] == 'polygon' or not baseGeomFlag:
                        child.setCheckState(3, Qt.Checked)
                    else:
                        child.setCheckState(3, Qt.Unchecked)
                else:
                    child.setText(3, "")
        
        self.dlgChooseLayers.treeWidget.header().resizeSection(0, 300)
        self.dlgChooseLayers.treeWidget.header().resizeSection(1, 50)
        self.dlgChooseLayers.treeWidget.header().resizeSection(2, 50)
        self.dlgChooseLayers.treeWidget.header().resizeSection(3, 50)

    def unload(self):
        """Removes the plugin menu item and icon from QGIS GUI."""
        for action in self.actions:
            try:
                self.iface.removePluginMenu(self.tr(u'&МирГрадЪ ДТП'), action)
            except Exception:
                print("Не удалось удалить действие из меню: %s", action.text())
        
        if self.dtpPluginToolbar is not None:
            try:
                self.dtpPluginToolbar.deleteLater()
            except Exception:
                print("Ошибка при удалении тулбара")

        self.dlgCreateLayers.deleteLater()
        self.dlgApplyStyles.deleteLater()
        self.dlgImport.deleteLater()
        self.dlgCheck.deleteLater()
        self.dlgSearchObj.deleteLater()
        self.dlgCheckReport.deleteLater()
        self.dlgSelectClass.deleteLater()
        
        self.iface.layerTreeView().selectionModel().selectionChanged.disconnect(self.eventToSelectLayers)
        for action in self.actions:
            if action.text() in ['Скопировать таблицу атрибутов в буфер обмена']:
                self.iface.removeCustomActionForLayerType(action)
        tree = self.iface.layerTreeView()
        tree.selectAll()
        for selectedNode in  tree.selectedNodes():
            for indicator in tree.indicators(selectedNode):
                if indicator.toolTip() == 'Относится к базовым слоям':
                    tree.removeIndicator(selectedNode, indicator)
        tree.clearSelection()

    def eventToSelectLayers(self):
        selectedLayersList = self.iface.layerTreeView().selectedLayers()
        flagLayersSelected = False
        if len(selectedLayersList) > 0:
            """ for selectedLayer in selectedLayersList:
                print(selectedLayer.name()) """
            flagLayersSelected = True
        for action in self.actions:
            if action.text() in ['Импорт данных', 'Применение стилей', 'Проверка слоев', 
                                 'Удалить условные обозначения отсутствующих объектов', 'Экспорт планируемых объектов', 
                                 'Поиск объекта', 'Экспорт в GML для ФГИС ТП', 'Построить легенду', 'Формирование перечня координат']:
                action.setEnabled(flagLayersSelected)

    def initTypes(self, pathToXSD):
        looseFlag = True
        stringXSD = self.licMngr._getInitFileFromLicServer()
        parseResult = parseFgistpXSD(stringXSD)

        self.simpleTypes = parseResult['simpleTypes']
        self.complexTypes = parseResult['complexTypes']
        self.elementTypes = parseResult['elementTypes']
        self.groupDict = parseResult['groupDict']
        
        layerGeomTypes = dict()
        layerGeomTypes["layerGeomTypes"] = list(parseResult['layerGeomTypes'])

        if len(getLayersName(self.elementTypes, self.complexTypes)) > 0:
            looseFlag = False
            for action in self.actions:
                if action.text() in ['Включить/исключить в набор базовых слоев']:
                    action.setEnabled(not looseFlag)
        
        if self.dlg.checkBox_2.isChecked():
            pathToXSD = 'XSD-схемы'
            reportXSD = f'<span>файл <b>{pathToXSD}</b> содержит описание {len(self.elementTypes.keys())} элементов</span><br />'
            
            countElementsWithGeometry = 0
            elementsNoTypes = []
            elementsErrorTypes = []
            elementsWithoutGeometry =[]
            elementsWithoutAttributes =[]
            elementsWithoutCLASSID = []
            setMirGroups = set()
            setClassWithoutGroup = set()
            counrMirDepend = 0
            setMirDepend = set()
            complexTypeWithoutAttrib = []
            complexTypeWithoutGeometry = []
            setAttributeTypes = set()
            setGeometryTypes = set()

            for element in self.elementTypes:
                if len(self.elementTypes[element]['elementType']) > 0:
                    elementType = self.elementTypes[element]['elementType'].replace('fgistp:', '')
                    elementTypeName = self.elementTypes[element]['elementType']
                    if self.complexTypes.get(elementType, 'error') == 'error' and self.simpleTypes.get(elementType, 'error') == 'error':
                        elementsErrorTypes.append(elementType)
                        reportXSD += f'<span>для элемента <b>{element}</b> не найдено описание типа {elementTypeName}</span><br />'
                    else:
                        if self.simpleTypes.get(elementType, 'error') != 'error':
                            elementsWithoutGeometry.append(element)
                            elementsWithoutCLASSID.append(element)
                            reportXSD += f'<span>элемент <b>{element}</b> (тип: <b>{elementTypeName}</b>) относится к простым типам</span><br />'
                            continue
                        complexType = self.complexTypes[elementType]
                        if len(complexType.get('geometryTypes', [])) < 1:
                            elementsWithoutGeometry.append(element)
                            reportXSD += f'<span>элемент <b>{element}</b> (тип: <b>{elementTypeName}</b>) не является геометрическим элементом</span><br />'
                        else:
                            countElementsWithGeometry += 1
                        if len(complexType.get('attributes', [])) < 1:
                            elementsWithoutAttributes.append(element)
                            reportXSD += f'<span>элемент <b>{element}</b> (тип: <b>{elementTypeName}</b>) не содержит описание атрибутивных данных</span><br />'
                        else:
                            if complexType['attributes'].get('CLASSID', '') == '':
                                elementsWithoutCLASSID.append(element)
                                reportXSD += f'<span>элемент <b>{element}</b> (тип: <b>{elementTypeName}</b>) не является классом Приказа 10 (не содержит атрибута CLASSID)</span><br />'
                else:
                    elementsNoTypes.append(element)
                    reportXSD += f'<span>для элемента <b>{element}</b> отсутствует описание типа</span><br />'
                if len(self.elementTypes[element].get('mirGroup', '')) < 1:
                    if element not in [elementsWithoutCLASSID]:
                        reportXSD += f'<span>для элементf <b>{element}</b> не определена группа (MirGroup - раздел Приказа 10)</span><br />'
                else:
                    setMirGroups.add(self.elementTypes[element]['mirGroup'])
            reportXSD += f'<span>найдено <b>{len(self.elementTypes.keys()) - len(set(elementsWithoutCLASSID).union(set(elementsWithoutGeometry), set(elementsErrorTypes), set(elementsNoTypes)))}</b> элементов отнесенных к классам Приказа 10 (содержат геометрию и атрибут CLASSID)</span><br />'
            reportXSD += f'<span>найдено <b>{len(setMirGroups)}</b> групп (MirGroup - раздел Приказа 10)</span><br />'

            reportXSD += f'<span>файл <b>{pathToXSD}</b> содержит описание {len(self.complexTypes.keys())} комплексных типов</span><br />'
            for complexType in self.complexTypes:
                if len(self.complexTypes[complexType]['attributes']) < 1:
                    complexTypeWithoutAttrib.append(complexType)
                    reportXSD += f'<span>комплексный тип <b>{complexType}</b> не содержит описание атрибутов</span><br />'
                if len(self.complexTypes[complexType]['geometryTypes']) < 1:
                    complexTypeWithoutGeometry.append(complexType)
                    reportXSD += f'<span>комплексный тип <b>{complexType}</b> не содержит описание геометрии</span><br />'
                if complexType not in complexTypeWithoutAttrib and complexType not in complexTypeWithoutGeometry:
                    setGeometryTypes.update(set(self.complexTypes[complexType]['geometryTypes']))
                    for attributeName in self.complexTypes[complexType]['attributes']:
                        attributeDict = self.complexTypes[complexType]['attributes'][attributeName]
                        attributeType = attributeDict['baseType']

                        if 'fgistp:' in attributeDict['baseType']:
                            if len(self.simpleTypes.get(attributeType.replace('fgistp:', ''), [])) < 1:
                                reportXSD += f'<span>для комплексного типа <b>{complexType}</b>, для атрибита <b>{attributeName}</b> отсутствует описание типа <b>{attributeType}</b></span><br />'
                        elif attributeDict['baseType'] == '':
                            reportXSD += f'<span>для комплексного типа <b>{complexType}</b>, для атрибита <b>{attributeName}</b> отсутствует описание типа</span><br />'
                        else:
                            setAttributeTypes.add(attributeType)
                        if attributeDict.get('mirDepend', '') != '':
                            setMirDepend.add(complexType)
                            counrMirDepend += 1
            reportXSD += f'<span>типы геометрии для комплексных типов: {list(setGeometryTypes)}</span><br />'
            reportXSD += f'<span>типы атрибутов для комплексных типов: {list(setAttributeTypes)}</span><br />'
            reportXSD += f'<span>найдено <b>{counrMirDepend}</b> условно-обязательных атрибутов (MirDepend - условия для атрибутов)</span><br />'
            
            reportXSD += f'<span>файл <b>{pathToXSD}</b> содержит описание {len(self.simpleTypes.keys())} простых типов</span><br />'

            reportXSD += compareFgisXSD(self.defXSD, pathToXSD)
            outForWrite = os.path.expanduser("~") + '\Documents\Qgis'

            try:
                os.makedirs(outForWrite, exist_ok=True)
            except Exception as ex:
                print(ex)
            with open(outForWrite +'\simpleTypes.json', 'w', encoding='utf-8') as f:
                json.dump(self.simpleTypes, f, ensure_ascii=False, indent=4)
            with open(outForWrite +'\complexTypes.json', 'w', encoding='utf-8') as f:
                json.dump(self.complexTypes, f, ensure_ascii=False, indent=4)
            with open(outForWrite +'\elementTypes.json', 'w', encoding='utf-8') as f:
                json.dump(self.elementTypes, f, ensure_ascii=False, indent=4)
            with open(outForWrite +'\groupDict.json', 'w', encoding='utf-8') as f:
                json.dump(self.groupDict, f, ensure_ascii=False, indent=4)
            with open(outForWrite +'\layerGeomTypes.json', 'w', encoding='utf-8') as f:
                json.dump(layerGeomTypes, f, ensure_ascii=False, indent=4)

            for classType, values in self.complexTypes.items():
                for attribName in values.get('attributes', []):
                    if 'CLASSID'.lower() in attribName.lower():
                        self.baseLayersDict[classType] = ''

            self.dlgCheckReport.textBrowser.setHtml(reportXSD)
            self.dlgCheckReport.show()
        return looseFlag

    def getLayerClassTypeOrder10(self, order10layer, complexTypesIn, simpleTypesIn):
        if order10layer.type() != 0:
            return ''
        complexTypes = deepcopy(complexTypesIn)
        simpleTypes = deepcopy(simpleTypesIn)
        matchesClasses = {'byAllFieldsNames':set(), 'byReqFieldsNames':set(), 'byLayerNameAndAllFieldsNames':set(), 'byCLASSID':set(), 'byPartFields': set(), 'nameClassType':''}
        fieldsForCheckSet = set(order10layer.fields().names())
        
        classTypes = []
        fieldCount = 0
        for classType in complexTypes.keys():
            if classType in ['date_t', 'Zone', 'Object']:
                continue
            etalonFieldsSet = set(list(complexTypes[classType]['attributes'].keys()))
            commonFields = etalonFieldsSet.intersection(fieldsForCheckSet)
            if len(commonFields) < 2:
                continue
            if len(commonFields) == fieldCount:
                classTypes.append(classType)
            if len(commonFields) > fieldCount:
                fieldCount = len(commonFields)
                classTypes = [classType,]
        matchesClasses['byAllFieldsNames'] = set(classTypes)
        
        classTypes = []
        fieldCount = 0
        
        for classType in complexTypes.keys():
            if classType in ['date_t', 'Zone', 'Object']:
                continue
            etalonFieldsSet = set()
            for attrName in complexTypes[classType]['attributes'].keys():
                if complexTypes[classType]['attributes'][attrName].get('minOccurs', 'N') in ['Y', 'C']:
                    etalonFieldsSet.add(attrName)
            if etalonFieldsSet.issubset(fieldsForCheckSet):
                if len(etalonFieldsSet) > fieldCount:
                    fieldCount = len(etalonFieldsSet)
                    classTypes = [classType,]
                elif len(etalonFieldsSet) == fieldCount:
                    classTypes.append(classType)
        matchesClasses['byReqFieldsNames'] = set(classTypes)

        for classTypeName in matchesClasses['byAllFieldsNames']:
            if order10layer.name().find('_') == -1:
                layerName = order10layer.name().lower()
            else:
                layerName = order10layer.name().lower()[:order10layer.name().find('_')]
            if layerName == classTypeName.lower() or layerName == classTypeName.replace('_Type', '').lower():
                matchesClasses['byLayerNameAndAllFieldsNames'].add(classTypeName)
        
        classTypes = []
        if len(matchesClasses['byLayerNameAndAllFieldsNames']) == 1:
            matchesClasses['nameClassType'] = list(matchesClasses['byLayerNameAndAllFieldsNames'])[0]
        elif len(matchesClasses['byAllFieldsNames']) == 1:
            matchesClasses['nameClassType'] = list(matchesClasses['byAllFieldsNames'])[0]
        elif len(matchesClasses['byReqFieldsNames']) > 0:
            for classTypeName in matchesClasses['byReqFieldsNames']:
                if order10layer.name().find('_') == -1:
                    layerName = order10layer.name().lower()
                else:
                    layerName = order10layer.name().lower()[:order10layer.name().find('_')]
                if layerName == classTypeName.lower() or layerName == classTypeName.replace('_Type', '').lower():
                    classTypes.append(classTypeName)
            if len(classTypes) == 1:
                matchesClasses['nameClassType'] = classTypes[0]
        
        if order10layer.featureCount() > 0 and 'CLASSID' in fieldsForCheckSet:
            indxFieldClassid = order10layer.fields().indexOf('CLASSID')
            setOfCLASSID = order10layer.uniqueValues(indxFieldClassid)
            for classType in complexTypes.keys():
                if classType in ['date_t', 'Zone', 'Object'] or complexTypes[classType]['attributes'].get('CLASSID', {"baseType":'error'})["baseType"] == 'error':
                    continue
                simpleName = complexTypes[classType]['attributes']['CLASSID']['baseType'].replace('fgistp:', '')
                etalonCLASSID = set(list(simpleTypes[simpleName]['dictValues'].keys()))
                if {str(x) for x in setOfCLASSID}.issubset(etalonCLASSID):
                    matchesClasses['byCLASSID'].add(classType)
            if len(matchesClasses['byCLASSID']) == 1:# and matchesClasses['nameClassType'] == '':
                matchesClasses['nameClassType'] = list(matchesClasses['byCLASSID'])[0]
        
        classTypesPartFields = {x + '_Type' for x in self.groupDict.keys()}
        for fieldForCheck in fieldsForCheckSet:
            classesForField = set()
            for classType in complexTypes.keys():
                if classType in ['date_t', 'Zone', 'Object']:
                    continue
                etalonFieldsSet = set(list(complexTypes[classType]['attributes'].keys()))
                if fieldForCheck in etalonFieldsSet:
                    classesForField.add(classType)
            if len(classesForField) > 0:
                classTypesPartFields = classTypesPartFields.intersection(classesForField)
        if len(classTypesPartFields) > 0:
            matchesClasses['byPartFields'] = classTypesPartFields
        if matchesClasses['nameClassType'] == '' and len(classTypesPartFields) == 1:
            matchesClasses['nameClassType'] =list(matchesClasses['byPartFields'])[0]

        if matchesClasses['nameClassType'] == '' and self.dlg.checkBox.isChecked():
            self.dlgSelectClass.mMapLayerComboBox.setLayer(order10layer)
            self.dlgSelectClass.mMapLayerComboBox.setEnabled(False)
            self.dlgSelectClass.comboBox.clear()
            listOfClasses = set()
            listOfClasses = matchesClasses['byAllFieldsNames'].union(matchesClasses['byPartFields'], matchesClasses['byReqFieldsNames'], matchesClasses['byLayerNameAndAllFieldsNames'], matchesClasses['byCLASSID'])
            listOfClasses = list(listOfClasses)
            listOfClasses.append('Слой не принадлежит классу по Приказу 10')
            self.dlgSelectClass.comboBox.addItems(listOfClasses)
            self.dlgSelectClass.comboBox.setCurrentIndex(len(listOfClasses) - 1)
            self.dlgSelectClass.show()
            result = self.dlgSelectClass.exec_()
            if result and self.dlgSelectClass.comboBox.currentText() != 'Слой не принадлежит классу по Приказу 10':
                matchesClasses['nameClassType'] = self.dlgSelectClass.comboBox.currentText()
        

        my_layer_meta = order10layer.metadata()
        my_layer_meta.setAbstract(str(matchesClasses))

        order10layer.setMetadata(my_layer_meta)

        return matchesClasses
    
    def run(self):
        """Run method that performs all the real work"""

        # Create the dialog with elements (after translation) and keep reference
        # Only create GUI ONCE in callback, so that it will only load when the plugin is started

        # show the dialog
        moduleMode = self.licMngr.licMode
        self.dlg.show()
        # Run the dialog event loop
        result = self.dlg.exec_()
        # See if OK was pressed
        if moduleMode != self.licMngr.licMode:
            #pathToXSD = self.dlg.mQgsFileWidget.filePath()
            self.first_start = self.initTypes(self.defXSD)
    
    def createLayers(self):
        if not self.licMngr.showDlgDemoMode():
            return
        if self.first_start == True:
            self.first_start = self.initTypes(self.defXSD)
        if self.first_start == True:
            return
            
        
        self.dlgCreateLayers.show()
        result = self.dlgCreateLayers.exec_()
        if result:
            styleFlag = self.dlgCreateLayers.checkBox_2.isChecked()
            baseGeomFlag = self.dlgCreateLayers.checkBox.isChecked()
            attribConstrainFlag = self.dlgCreateLayers.checkBox_3.isChecked()
            groupFlag = self.dlgCreateLayers.checkBox_4.isChecked()
            chooseLayerFlag = self.dlgCreateLayers.checkBox_5.isChecked()
            if chooseLayerFlag:
                self.initGuiDlgChoseLayer(baseGeomFlag=baseGeomFlag)
                it = QTreeWidgetItemIterator(self.dlgChooseLayers.treeWidget)
                layersNamesForCreate = dict()
                self.dlgChooseLayers.show()
                result = self.dlgChooseLayers.exec_()
                if result:
                    while it.value() is not None:
                        item = it.value()
                        if item.childCount() < 1:
                            if item.checkState(0) and (item.checkState(1) or item.checkState(2) or item.checkState(3)):
                                layersNamesForCreate[item.text(0)] = []
                                if item.checkState(1):
                                    layersNamesForCreate[item.text(0)].append('Point')
                                if item.checkState(2):
                                    layersNamesForCreate[item.text(0)].append('Polyline')
                                if item.checkState(3):
                                    layersNamesForCreate[item.text(0)].append('Polygon')
                        it += 1
                else:
                    return
            else:
                layersNamesForCreate = dict()
            crsForLayers = QgsCoordinateReferenceSystem("EPSG:3857")
            mySelector = QgsProjectionSelectionDialog(self.iface.mainWindow())
            mySelector.setCrs( crsForLayers )
            if mySelector.exec():
                crsForLayers = mySelector.crs()
            listOfLayers = createDPTlayersOrder10(self.elementTypes, self.complexTypes, self.simpleTypes, CRS_for_layers=crsForLayers, baseGeometry=baseGeomFlag, layersNamesForCreate=layersNamesForCreate)
            listOfLayers.reverse()

            progressMessageBar = self.iface.messageBar().createMessage("МирГрадЪ - ДТП: Создание слоев...")
            progress = QProgressBar()
            progress.setMaximum(len(listOfLayers))
            progress.setAlignment(Qt.AlignLeft|Qt.AlignVCenter)
            progressMessageBar.layout().addWidget(progress)
            self.iface.messageBar().pushWidget(progressMessageBar, 0)

            for i, layer in enumerate(listOfLayers):
                if groupFlag:
                    lName = str(layer.name())
                    move_to_group(layer, self.groupDict.get(layer.name(), self.groupDict.get(lName[:lName.rfind('_')])), pos=0, expanded=False)
                else:
                    QgsProject.instance().addMapLayer(layer)
                    QgsProject.instance().layerTreeRoot().findLayer(layer).setExpanded(False)
                #resultClassType = self.getLayerClassTypeOrder10(layer, self.complexTypes, self.simpleTypes)
                resultClassType = getLayerClassTypeOrder10_v2(layer, self.complexTypes, self.simpleTypes)
                if attribConstrainFlag:
                    applyFieldConstrainsOrder10(layer, self.simpleTypes, self.complexTypes, resultClassType['nameClassType'])
                if styleFlag:
                    applyStyleSymbols(layer, self.simpleTypes, self.complexTypes, self.plugin_dir + '/res/Symbols', resultClassType['nameClassType'])
                    self.iface.layerTreeView().refreshLayerSymbology(layer.id())
                progress.setValue(i + 1)
            self.iface.messageBar().clearWidgets()

    def createCoordListLayer(self, objDict, coordListForClipBoard, sourceLayer, swapXyFlag):
        uri = f"Point?crs={sourceLayer.crs().authid()}"
        createdLayer = QgsVectorLayer(uri, 'Поворотные точки', "memory")

        layerAttributes = [QgsField("objName", QVariant.String),
                           QgsField("numPoint", QVariant.Int),
                           QgsField("X", QVariant.Double),
                           QgsField("Y", QVariant.Double),
                           QgsField("countPoint", QVariant.Int)]
        createdLayer.dataProvider().addAttributes(layerAttributes)
        createdLayer.updateFields()

        pointFeatures = []
        coords_counter = {}

        for indStart, value in objDict.items():
            last_idx = value.get('lastIndx', indStart)
            for indx in range(indStart, last_idx + 1):
                row_data = coordListForClipBoard[indx]

                if len(row_data) == 3:
                    if indx > indStart:
                        if isinstance(coordListForClipBoard[indx - 1][0], int):
                            if coordListForClipBoard[indx][0] < coordListForClipBoard[indx - 1][0]:
                                continue

                    point_x = float(row_data[1])
                    point_y = float(row_data[2])
                    
                    # Быстрый подсчет вхождений через словарь
                    coord_key = (point_x, point_y)
                    coords_counter[coord_key] = coords_counter.get(coord_key, 0) + 1
                    count_of_equal_rows = coords_counter[coord_key]

                    pointFeature = QgsFeature(createdLayer.fields())

                    pointFeature.setAttributes([value['mirGradNameObject'], 
                                               row_data[0], 
                                               row_data[1], 
                                               row_data[2], 
                                               count_of_equal_rows])
                    if swapXyFlag:
                        pointFeature.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(point_y, point_x)))
                    else:
                        pointFeature.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(point_x, point_y)))

                    pointFeatures.append(pointFeature)

        # Добавляем объекты в слой одним пакетом (быстрее, чем через startEditing)
        createdLayer.dataProvider().addFeatures(pointFeatures)
        createdLayer.updateExtents()
        
        # Добавляем слой в проект в самом конце
        QgsProject.instance().addMapLayer(createdLayer)
        return

    def createCoordListDocx(self, objDict, coordListForClipBoard, separateFileFlag, tableVid, outPathOrFile):
        if not os.path.isdir(outPathOrFile):
            return
        
        # 1. Загрузка шаблонов в зависимости от tableVid
        template_path = os.path.join(self.plugin_dir, "res", "boundDescribeTemplates")
        
        if tableVid == 0:
            tab_name = "coordTableMirGradTableRowTemplate.txt"
            doc_name = "documentCoordTable.txt"
        elif tableVid == 1:
            tab_name = "boundDescribeMirGradTableRowTemplate.txt"
            doc_name = "documentBoundDescribe.txt"
        else:
            return

        docxFile = os.path.join(template_path, "MirGrad_TemplateBoundDescribe.docx")

        # Читаем шаблоны с явным указанием кодировки (защита от кракозябр)
        with open(os.path.join(template_path, tab_name), "r", encoding='utf-8') as file:
            contentTabl = file.read().replace('\t', '').replace('\n', '').replace('\r', '')
        with open(os.path.join(template_path, doc_name), "r", encoding='utf-8') as file:
            contentDoc = file.read().replace('\t', '').replace('\n', '').replace('\r', '')

        filesXmlContent = list()
        objNamesList = list()

        for indStart, value in objDict.items():
            contentDocFill = contentDoc
            contentTablFill = ''

            for templateStr, valueStr in value.items():
                contentDocFill = contentDocFill.replace(templateStr, str(valueStr))

            for indx in range(indStart, value['lastIndx'] + 1):
                row_data = coordListForClipBoard[indx]

                if 'Часть' in str(row_data[0]):
                    contentTablFill = contentTablFill + contentTabl.replace('mirGradCoordNum', row_data[0])\
                        .replace('mirGradCoordX', '')\
                            .replace('mirGradCoordY', '')\
                                .replace('Аналитический', '')\
                                    .replace('0.1', '')
                if len(row_data) == 3:
                    numP = str(row_data[0])
                    
                    try:
                        coordX = f"{float(row_data[1]):.2f}"
                        coordY = f"{float(row_data[2]):.2f}"
                    except:
                        coordX, coordY = str(row_data[1]), str(row_data[2])

                    contentTablFill = contentTablFill + contentTabl.replace('mirGradCoordNum', numP).replace('mirGradCoordX', coordX).replace('mirGradCoordY', coordY)
            contentDocFill = contentDocFill.replace('MirGradTableRowTemplate', contentTablFill)
            filesXmlContent.append(contentDocFill)
            objNamesList.append(value.get('mirGradNameObject', 'Object'))

        if not separateFileFlag:
            filesXmlContent = [''.join(filesXmlContent),]

        for indx, fileContent in enumerate(filesXmlContent):
            if separateFileFlag:
                outFile = outPathOrFile + '/' + str(indx)+ '_' + str(objNamesList[indx]) + '.docx'
            else:
                outFile = outPathOrFile + '/ПереченьКоординатПоворотныхТочек.docx'

            if os.path.exists(outFile):
                # Если существует, удаляем его
                os.remove(outFile)

            with zipfile.ZipFile(docxFile) as inzip, zipfile.ZipFile(outFile, "w") as outzip:
                for inzipinfo in inzip.infolist():
                    with inzip.open(inzipinfo) as infile:
                        if inzipinfo.filename == "word/document.xml":
                            content = infile.read().decode('utf-8').replace('\t', '').replace('\n', '').replace('\r', '')
                            content = content.replace('</w:body></w:document>', fileContent+'</w:body></w:document>')
                            outzip.writestr(inzipinfo.filename, content)
                        else: # Other file, dont want to modify => just copy it
                            outzip.writestr(inzipinfo.filename, infile.read())
        return

    def createCoordList(self):
        if not self.licMngr.showDlgDemoMode():
            return
        
        # Инициализация диалога
        self.dlgCoord._initMapLayerComboBox()
        selected = self.iface.layerTreeView().selectedLayers()
        if selected:
            self.dlgCoord.mMapLayerComboBox.setLayer(selected[0])
            
        if not self.dlgCoord.exec_():
            return

        layer = self.dlgCoord.mMapLayerComboBox.currentLayer()
        if not layer:
            return

        swapXyFlag = self.dlgCoord.checkBox_2.isChecked()
        useSelectedFlag = self.dlgCoord.checkBox.isChecked()
        featuresIterator = layer.selectedFeatures() if useSelectedFlag else layer.getFeatures()

        coordListForClipBoard = list()
        objDict = dict()
        
        context = QgsExpressionContext()
        context.appendScopes(QgsExpressionContextUtils.globalProjectLayerScopes(layer))

        objNameExpression = QgsExpression(self.dlgCoord.mFieldExpressionWidget.asExpression())
        objLocationExpression = QgsExpression(self.dlgCoord.mFieldExpressionWidget_2.asExpression())

        mirGradTypeObject = self.dlgCoord.lineEdit.text()
        mirGradMSKstring = self.dlgCoord.lineEdit_2.text()

        for feat in featuresIterator:
            context.setFeature(feat)
            geom = feat.geometry()
            if geom.isEmpty():
                continue

            area = 0
            polygonFlag = False
            if geom.type() == Qgis.GeometryType.Polygon:
                polygonFlag = True
                geom = geom.forcePolygonCounterClockwise()
                area = round(geom.area(), 1)


            partsFlag = True if len(list(geom.parts())) > 1 else False
            
            objName = objNameExpression.evaluate(context)
            if str(objName) == 'None':
                objName = objNameExpression.expression()
            objLocation = objLocationExpression.evaluate(context)
            if str(objLocation) == 'None':
                objLocation = objLocationExpression.expression()

            coordListForClipBoard.append([objName, str(area)])
            currObjIndex = len(coordListForClipBoard) - 1
            objDict[currObjIndex] = {'mirGradTypeObject':mirGradTypeObject, # Тип объекта описания границ
                                    'mirGradNameObject':objName, # Наименование объекта
                                    'mirGradIndexObject':objName,
                                    'mirGradLocationObject':objLocation,
                                    'mirGradSandAccuracyObject':f'{int(round(area, 0))} +/- {int(round(3.5*0.1*(area**0.5), 0))}',
                                    'mirGradMSKstring':mirGradMSKstring}
            for partN, part in enumerate(geom.parts()):

                if partsFlag:
                    coordListForClipBoard.append([f'Часть {partN + 1}'])
                ind0 = 0


                partEnum = enumerate(part.exteriorRing().vertices()) if polygonFlag else enumerate(part.vertices())

                for ind, v in partEnum:
                    if swapXyFlag:
                        coordListForClipBoard.append([ind+1,round(v.y(), 2),round(v.x(), 2)])#,'Аналитический','0.01','',''])
                    else:
                        coordListForClipBoard.append([ind+1,round(v.x(), 2),round(v.y(), 2)])#,'Аналитический','0.01','',''])
                    #coordDict[partN].append(f'{ind+1},{round(v.y(), 2)},{round(v.x(), 2)},Аналитический,0.01,,\n')
                    #coordDict[partN][ringsN][ind+1] = [round(v.y(), 2), round(v.x(), 2)]
                else:
                    if swapXyFlag:
                        coordListForClipBoard[-1] = [ind0+1,round(v.y(), 2),round(v.x(), 2)]#,'Аналитический','0.01','','']
                    else:
                        coordListForClipBoard[-1] = [ind0+1,round(v.x(), 2),round(v.y(), 2)]#,'Аналитический','0.01','','']
                    if not polygonFlag:
                        coordListForClipBoard = coordListForClipBoard[:-1]
                    #coordDict[partN][-1]=f'{ind0+1},{round(v.y(), 2)},{round(v.x(), 2)},Аналитический,0.01,,\n'
                    ind0 = ind

                if polygonFlag:
                    partEnum = range(part.numInteriorRings())
                else:
                    partEnum = range(0)
                for numIntRing in partEnum:
                    #coordDict[partN][numIntRing + 1] = dict()
                    for ind, v in enumerate(part.interiorRing(numIntRing).vertices()):
                        if swapXyFlag:
                            coordListForClipBoard.append([ind0 + ind+1,round(v.y(), 2),round(v.x(), 2)])#,'Аналитический','0.01','',''])
                        else:
                            coordListForClipBoard.append([ind0 + ind+1,round(v.x(), 2),round(v.y(), 2)])
                        #coordDict[partN].append(f'{ind0 + ind+1},{round(v.y(), 2)},{round(v.x(), 2)},Аналитический,0.01,,\n')
                        #coordDict[partN][numIntRing + 1][ind0 + ind+1] = [round(v.y(), 2), round(v.x(), 2)]
                    else:
                        if swapXyFlag:
                            coordListForClipBoard[-1] = [ind0+1,round(v.y(), 2),round(v.x(), 2)]#,'Аналитический','0.01','','']
                        else:
                            coordListForClipBoard[-1] = [ind0+1,round(v.x(), 2),round(v.y(), 2)]
                        #coordDict[partN][-1]=f'{ind0+1},{round(v.y(), 2)},{round(v.x(), 2)},Аналитический,0.01,,\n'
                        ind0 = ind0 + ind
            objDict[currObjIndex]['lastIndx'] = len(coordListForClipBoard) - 1
        if self.dlgCoord.checkBox_3.isChecked():
            self.createCoordListLayer(objDict, coordListForClipBoard, layer, swapXyFlag)
        outputFormat = self.dlgCoord.comboBox_2.currentIndex()
        tableVid = self.dlgCoord.comboBox.currentIndex()
        outPathOrFile = self.dlgCoord.mQgsFileWidget.filePath()
        if outputFormat == 1:
            self.createCoordListDocx(objDict, coordListForClipBoard, True, tableVid, outPathOrFile)
        elif outputFormat == 2:
            self.createCoordListDocx(objDict, coordListForClipBoard, False, tableVid, outPathOrFile)
        clipboard = QgsApplication.clipboard()
        clipboard.setText('\n'.join(['\t'.join(map(str, row)) for row in coordListForClipBoard]))
        #print(objDict)
        return

    def importData(self):
        if not self.licMngr.showDlgDemoMode():
            return
        if self.first_start == True:
            self.first_start = self.initTypes(self.defXSD)

        if self.first_start == True:
            return
        self.dlgImport.exceptLayerCommon = []
        self.dlgImport.exceptAddLayerClass = []

        sourceLayer = self.iface.layerTreeView().selectedLayers()[0]
        self.dlgImport.mMapLayerComboBox_2.setLayer(sourceLayer)
        self.dlgImport.checkBox.setChecked(False)
        sourceLayerType = sourceLayer.wkbType()
        sourceLayerCrs = sourceLayer.crs()
        #sourceLayerClass = self.getLayerClassTypeOrder10(sourceLayer, self.complexTypes, self.simpleTypes)
        sourceLayerClass = getLayerClassTypeOrder10_v2(sourceLayer, self.complexTypes, self.simpleTypes)
        sourceLayerClass = self.dlgSelectClass.prepareDlg(sourceLayerClass, sourceLayer, self.dlg.checkBox.isChecked())#, flagChooseClass = True)
        countMapLayers = len(QgsProject.instance().mapLayers())

        for layerID, layer in QgsProject.instance().mapLayers().items():
            if layer.type() != 0:
                self.dlgImport.exceptLayerCommon.append(layer)
                continue
            if layer.crs() != sourceLayerCrs:
                self.dlgImport.exceptLayerCommon.append(layer)
                continue
            if layer.wkbType() != sourceLayerType:
                if sourceLayerType - 3 !=  layer.wkbType() and sourceLayerType !=  layer.wkbType()  - 3:
                    self.dlgImport.exceptLayerCommon.append(layer)
                    continue
            caps = layer.dataProvider().capabilities()
            # Выбираем источник констант в зависимости от версии QGIS
            if Qgis.QGIS_VERSION_INT >= 33900:
                # Для QGIS 3.40+
                target = Qgis.VectorProviderCapability
            else:
                # Для QGIS 3.28 и ниже
                target = QgsVectorDataProvider
            if not (caps & target.AddFeatures):
                self.dlgImport.exceptLayerCommon.append(layer)
                continue
            if not (caps & target.ChangeAttributeValues):
                self.dlgImport.exceptLayerCommon.append(layer)
                continue
        self.dlgImport.exceptLayerCommon.append(sourceLayer)
        if countMapLayers == len(self.dlgImport.exceptLayerCommon):
            return
        for layerID, layer in QgsProject.instance().mapLayers().items():
            if layer in self.dlgImport.exceptLayerCommon:
                continue
            layerClass = getLayerClassTypeOrder10_v2(layer, self.complexTypes, self.simpleTypes)
            layerClass = self.dlgSelectClass.prepareDlg(layerClass, sourceLayer, self.dlg.checkBox.isChecked())
            if layerClass["nameClassType"] != sourceLayerClass["nameClassType"]:
                self.dlgImport.exceptAddLayerClass.append(layer)
        if countMapLayers == len(self.dlgImport.exceptLayerCommon) + len(self.dlgImport.exceptAddLayerClass):
            self.dlgImport.checkBox.setEnabled(False)
        else:
            self.dlgImport.checkBox.setEnabled(True)
        if sourceLayer.selectedFeatureCount() > 0:
            self.dlgImport.checkBox_2.setChecked(False)
            self.dlgImport.checkBox_2.setEnabled(True)
        else:
            self.dlgImport.checkBox_2.setChecked(False)
            self.dlgImport.checkBox_2.setEnabled(False)
        self.dlgImport.mMapLayerComboBox.setExceptedLayerList(self.dlgImport.exceptLayerCommon)

        self.dlgImport.fieldsView.setSourceLayer(sourceLayer)
        self.dlgImport.fieldsView.setSourceFields(sourceLayer.fields())
        self.dlgImport.destLayerChanged()
        self.dlgImport.show()
        result = self.dlgImport.exec_()
        if not result:
            return
        flagOnlySelected = self.dlgImport.checkBox_2.isChecked()
        destinationLayer = self.dlgImport.mMapLayerComboBox.currentLayer()
        if flagOnlySelected:
            sourceFeatures = sourceLayer.selectedFeatures()
        else:
            sourceFeatures = sourceLayer.getFeatures()
        context = QgsExpressionContext()
        context.appendScopes(QgsExpressionContextUtils.globalProjectLayerScopes(sourceLayer))
        propertyMap = self.dlgImport.fieldsView.fieldPropertyMap()
        destFeatures = []
        destinationLayer.startEditing()
        editBuffer = destinationLayer.editBuffer()
        
        for sourceFeature in sourceFeatures:
            destFeature = QgsFeature(destinationLayer.fields())
            destFeature.setGeometry(sourceFeature.geometry())
            context.setFeature(sourceFeature)
            for destFieldName, propertyField in propertyMap.items():
                destValue = propertyField.value(context, '')[0]
                if destValue is None:
                    destValue = NULL
                elif str(destValue) in ['0', '', ' ']:
                    destValue = NULL
                destFeature[destFieldName] = destValue
                # print(destFieldName,  destFeature[destFieldName])
            destFeatures.append(destFeature)
        editBuffer.addFeatures(destFeatures)
        self.iface.mapCanvas().refresh()

    def applyStyles(self):
        if not self.licMngr.showDlgDemoMode():
            return
        if self.first_start == True:
            self.first_start = self.initTypes(self.defXSD)

        if self.first_start == True:
            return
        
        self.dlgApplyStyles.show()
        result = self.dlgApplyStyles.exec_()
        if not result:
            return
        
        selectedLayersList = self.iface.layerTreeView().selectedLayers()

        groupFlag = self.dlgApplyStyles.checkBox_4.isChecked()
        attribConstrainFlag = self.dlgApplyStyles.checkBox_2.isChecked()
        styleFlag = self.dlgApplyStyles.checkBox.isChecked()
        delNullFlag = self.dlgApplyStyles.checkBox_3.isChecked()
        
        progressMessageBar = self.iface.messageBar().createMessage("МирГрадЪ - ДТП: Применение стилей слоев...")
        progress = QProgressBar()
        progress.setMaximum(len(selectedLayersList))
        progress.setAlignment(Qt.AlignLeft|Qt.AlignVCenter)
        progressMessageBar.layout().addWidget(progress)
        self.iface.messageBar().pushWidget(progressMessageBar, 0)

        for i, layerForStyle in enumerate(selectedLayersList):
            if not isinstance(layerForStyle, QgsVectorLayer):
                progress.setValue(i + 1)
                continue
            if layerForStyle.type() != 0:
                progress.setValue(i + 1)
                continue
            #resultClassType = self.getLayerClassTypeOrder10(layerForStyle, self.complexTypes, self.simpleTypes)
            resultClassType = getLayerClassTypeOrder10_v2(layerForStyle, self.complexTypes, self.simpleTypes)
            resultClassType = self.dlgSelectClass.prepareDlg(resultClassType, layerForStyle, self.dlg.checkBox.isChecked())
            
            if groupFlag and resultClassType['nameClassType'] != '':
                lName = str(layerForStyle.name())
                move_to_group(layerForStyle, self.groupDict.get(resultClassType['nameClassType'].replace('_Type', ''), self.groupDict.get(lName[:lName.rfind('_')])), pos=0, expanded=False)

            if attribConstrainFlag:
                applyFieldConstrainsOrder10(layerForStyle, self.simpleTypes, self.complexTypes, resultClassType['nameClassType'])
            if styleFlag:
                applyStyleSymbols(layerForStyle, self.simpleTypes, self.complexTypes, self.plugin_dir + '/res/Symbols', resultClassType['nameClassType'])
                
            if delNullFlag:
                delNullSymbols(layerForStyle)

            QgsProject.instance().layerTreeRoot().findLayer(layerForStyle).setExpanded(False)
            self.iface.layerTreeView().refreshLayerSymbology(layerForStyle.id())
            progress.setValue(i + 1)
        self.iface.messageBar().clearWidgets()

    def copyAttrTableToClipBoard(self):
        tree = self.iface.layerTreeView()
        namesSortAttribute = ['STATUS', 'REG_STATUS', 'NUMBER', 'CLASSID', 'NAME']
        textForClipboard = ''
        for selectedNode in  tree.selectedLayerNodes():
            if not isinstance(selectedNode.layer(), QgsVectorLayer):
                continue
            vl = selectedNode.layer()
            df=pd.DataFrame(vl.getFeatures())
            df.columns=vl.fields().names()
            sortAttrForLayer = [attrName for attrName in namesSortAttribute if attrName in vl.fields().names()]
            df.sort_values(sortAttrForLayer, inplace=True)
            for fieldName in vl.fields().names():
                idx = vl.fields().indexFromName(fieldName)
                attrValueDict = dict()
                for dicts in vl.editorWidgetSetup(idx).config().get('map', []):
                    for key, value in dicts.items():
                        attrValueDict[int(value) if value.isdecimal() else value] = key
                df[fieldName] = df[fieldName].map(attrValueDict).fillna(df[fieldName])

            textForClipboard += vl.name() + '\n'
            textForClipboard += '\n'.join(['\t'.join([a.comment() if a.comment() != '' else a.name() for a in vl.fields()])]) + '\n' 
            textForClipboard += '\n'.join(['\t'.join(map(lambda s: s.replace('\n','').replace('\t','').replace('NULL', ''), map(str, row))) for row in df.values.tolist()])
            textForClipboard += '\n'
        if textForClipboard != '':
            clipboard = QgsApplication.clipboard()
            clipboard.setText(textForClipboard)

    def changeBaseLayersList(self):
        tree = self.iface.layerTreeView()
        
        for selectedNode in  tree.selectedLayerNodes():
            if not isinstance(selectedNode.layer(), QgsVectorLayer):
                continue
            """ removeFlag = False
            for indicator in tree.indicators(selectedNode):
                if indicator.toolTip() == 'Относится к базовым слоям':
                    tree.removeIndicator(selectedNode, indicator)
                    for key, values in self.baseLayersDict.items():
                        if values == selectedNode.layer().id():
                            self.baseLayersDict[key] = ''
                    removeFlag = True
            if removeFlag:
                continue
            layerClassTypeDict = self.getLayerClassTypeOrder10(selectedNode.layer(), self.complexTypes, self.simpleTypes)
            if layerClassTypeDict['nameClassType'] != '':
                # присвоить слою иконку, установить для класса данный слой
                tree.addIndicator(selectedNode, self.myIndicator)
                self.baseLayersDict[layerClassTypeDict['nameClassType']] = selectedNode.layer().id() """
            
        return
    
    def checkLayers_AutoCorrect(self, selectedLayersList, correctFlags):
        resultReport = f'<span style="font-size:13pt;"><b>ОТЧЕТ ПО КОРРЕКТИРОВКЕ СЛОЕВ</b> всего слоев: <b>{len(selectedLayersList)}</b></span><br />'
        
        progressMessageBar = self.iface.messageBar().createMessage("МирГрадЪ - ДТП: Автокоррекция...")
        progress = QProgressBar()
        progress.setMaximum(len(selectedLayersList))
        progress.setAlignment(Qt.AlignLeft|Qt.AlignVCenter)
        progressMessageBar.layout().addWidget(progress)
        self.iface.messageBar().pushWidget(progressMessageBar, 0)
        
        for countL, layerForCorrect in enumerate(selectedLayersList):
            if not isinstance(layerForCorrect, QgsVectorLayer):
                progress.setValue(countL + 1)
                continue
            resultReport += f'<span style="font-size:12pt;"><b>{countL + 1}</b></span><span style="font-size:10pt;"> слой: </span></span><span style="font-size:12pt;"><b>{layerForCorrect.name()}</b></span></span><span style="font-size:10pt;"> объектов в слое: </span></span><span style="font-size:12pt;"><b>{layerForCorrect.featureCount()}</b></span><br />'
            if layerForCorrect.featureCount() < 1:
                progress.setValue(countL + 1)
                continue
            if correctFlags['globalidFlag']:
                resultReport += f'<span style="font-size:10pt;"><b>-----------------------------------</b></span><br />'
                result = autoCorrectGlobalID(layerForCorrect)
                if result == -1:
                    resultReport += f'<span style="color:red;font-size:11pt;"> ошибка корректировки GLOBALID: поле GLOBALID отсутствует</span><br />'
                elif result == -2:
                    resultReport += f'<span style="color:red;font-size:11pt;"> ошибка корректировки GLOBALID: поле GLOBALID не корректного типа</span><br />'
                elif result == 0:
                    resultReport += f'<span style="font-size:10pt;"> корректировка GLOBALID: откорректировано <b>{result}</b> объектов</span><br />'
                else:
                    resultReport += f'<span style="color:green;font-size:10pt;"> корректировка GLOBALID: откорректировано <b>{result}</b> объектов</span><br />'
            if correctFlags['nullGeomFlag']:
                resultReport += f'<span style="font-size:10pt;"><b>-----------------------------------</b></span><br />'
                result = deleteFeatureWithoutGeometry(layerForCorrect)
                if result == 0:
                    resultReport += f'<span style="font-size:10pt;">  корректировка Геометрии: удалено <b>{result}</b> объектов не содержащих геометрии</span><br />'
                else:
                    resultReport += f'<span style="color:green;font-size:10pt;">  корректировка Геометрии: удалено <b>{result}</b> объектов не содержащих геометрии</span><br />'
            if correctFlags['geomParamFlag']:
                resultReport += f'<span style="font-size:10pt;"><b>-----------------------------------</b></span><br />'
                result =fillGeometrysAtttribs(layerForCorrect)
                if result == -1:
                    resultReport += f'<span style="color:orange;font-size:10pt;"> ошибка корректировки AREA/LENGTH: слой точечный</span><br />'
                elif result == -2:
                    resultReport += f'<span style="color:orange;font-size:10pt;"> ошибка корректировки AREA/LENGTH: слой не содержит атрибутов AREA/LENGTH</span><br />'
                elif result == -3:
                    resultReport += f'<span style="color:red;font-size:11pt;"> ошибка корректировки AREA/LENGTH: ошибка системы координат слоя</span><br />'
                elif result == 0:
                    resultReport += f'<span style="font-size:10pt;"> корректировка AREA/LENGTH: откорректировано <b>{result}</b> объектов</span><br />'
                else:
                    resultReport += f'<span style="color:green;font-size:10pt;"> корректировка AREA/LENGTH: откорректировано <b>{result}</b> объектов</span><br />'
            if correctFlags['nullIfFlag']:
                resultReport += f'<span style="font-size:10pt;"><b>-----------------------------------</b></span><br />'
                classTypeName = self.getLayerClassTypeOrder10(layerForCorrect, self.complexTypes, self.simpleTypes)['nameClassType']
                if classTypeName == '':
                    resultReport += f'<span style="color:red;font-size:11pt;"> ошибка корректировки значений условно-обязательных атрибутов: неопределен класс слоя по Приказу 10</span><br />'
                else:
                    complexTypeAttributesDict = self.complexTypes[classTypeName]['attributes']
                    result = nullIfAttrib(layerForCorrect, complexTypeAttributesDict)
                    if result == -1:
                        resultReport += f'<span style="color:red;font-size:11pt;"> ошибка корректировки значений условно-обязательных атрибутов: слой не содержит все требуемые атрибуты</span><br />'
                    elif result == -2:
                        resultReport += f'<span style="font-size:10pt;"> корректировки значений условно-обязательных атрибутов: класс слоя не содержит условно-обязательных атрибутов</span><br />'
                    if result == 0:
                        resultReport += f'<span style="font-size:10pt;"> корректировки значений условно-обязательных атрибутов: откорректировано <b>{result}</b> объектов</span><br />'
                    else:
                        resultReport += f'<span style="color:green;font-size:10pt;"> корректировки значений условно-обязательных атрибутов: откорректировано <b>{result}</b> объектов</span><br />'
            if correctFlags['oktmoFlag']:
                resultReport += f'<span style="font-size:10pt;"><b>-----------------------------------</b></span><br />'
                oktmoLayer = self.dlgCheck.mMapLayerComboBox_2.currentLayer()
                defOKTMO = self.dlgCheck.lineEdit.text()
                result = fillOKTMO(layerForCorrect, oktmoLayer, defOKTMO)
                if result == -1:
                    resultReport += f'<span style="color:orange;font-size:10pt;"> ошибка корректировки OKTMO: опорный слой OKTMO не является полигональным</span><br />'
                elif result == -2:
                    resultReport += f'<span style="color:red;font-size:11pt;"> ошибка корректировки OKTMO: ошибка системы координт слоя или системы координат опорного слоя</span><br />'
                elif result == 0:
                    resultReport += f'<span style="font-size:10pt;"> корректировка OKTMO: откорректировано <b>{result}</b> объектов</span><br />'
                elif result == -3:
                    resultReport += f'<span style="color:orange;font-size:10pt;"> ошибка корректировки OKTMO: слой не содержит атрибута OKTMO</span><br />'
                else:
                    resultReport += f'<span style="color:green;font-size:10pt;"> корректировка OKTMO: откорректировано <b>{result}</b> объектов</span><br />'
            if correctFlags['zuFlag']:
                resultReport += f'<span style="font-size:10pt;"><b>-----------------------------------</b></span><br />'
                parcelLayer = self.dlgCheck.mMapLayerComboBox.currentLayer()
                parcelNumAttribName = self.dlgCheck.mFieldComboBox.currentField()
                result = fillZuNumber(layerForCorrect, parcelLayer, parcelNumAttribName)
                if result == -2:
                    resultReport += f'<span style="color:orange;font-size:10pt;"> ошибка корректировки Кадастровых номеров ЗУ: опорный слой участков не является полигональным</span><br />'
                elif result == -3:
                    resultReport += f'<span style="color:red;font-size:11pt;"> ошибка корректировки Кадастровых номеров ЗУ: ошибка системы координт слоя или системы координат опорного слоя</span><br />'
                elif result == -1:
                    resultReport += f'<span style="color:orange;font-size:10pt;"> ошибка корректировки Кадастровых номеров ЗУ: слой не содержит атрибут KADASTRZU</span><br />'
                elif result == 0:
                    resultReport += f'<span style="font-size:10pt;"> корректировка Кадастровых номеров ЗУ: откорректировано <b>{result}</b> объектов</span><br />'
                else:
                    resultReport += f'<span style="color:green;font-size:10pt;"> корректировка Кадастровых номеров ЗУ: откорректировано <b>{result}</b> объектов</span><br />'
            resultReport += f'<span style="font-size:10pt;"><b>===================================</b></span><br />'
            progress.setValue(countL + 1)
        self.iface.messageBar().clearWidgets()
        return resultReport

    def checkLayers_Check(self, selectedLayersList, onlyReqFieldFlag):
        resultReport = f'<span style="font-size:13pt;"><b>ОТЧЕТ ФОРМАТНО-ЛОГИЧЕСКОГО КОНТРОЛЯ СЛОЕВ</b> всего слоев:\t {len(selectedLayersList)}</span><br />'
        if onlyReqFieldFlag:
            resultReport += '<span style="font-size:12pt;"><b>проверка только на обязательные и условно-обязательные атрибуты</b></span><br />'

        progressMessageBar = self.iface.messageBar().createMessage("МирГрадЪ - ДТП: Проверка слоев (ФЛК)...")
        progress = QProgressBar()
        progress.setMaximum(len(selectedLayersList))
        progress.setAlignment(Qt.AlignLeft|Qt.AlignVCenter)
        progressMessageBar.layout().addWidget(progress)
        self.iface.messageBar().pushWidget(progressMessageBar, 0)

        for countL, layerForCheck in enumerate(selectedLayersList):
            if not isinstance(layerForCheck, QgsVectorLayer):
                progress.setValue(countL + 1)
                continue
            resultReport += f'<span style="font-size:12pt;"><b>{countL + 1}</b></span><span style="font-size:10pt;"> слой: </span></span><span style="font-size:12pt;"><b>{layerForCheck.name()}</b></span></span><span style="font-size:10pt;"> объектов в слое: </span></span><span style="font-size:12pt;"><b>{layerForCheck.featureCount()}</b></span><br />'
            classTypeName = self.getLayerClassTypeOrder10(layerForCheck, self.complexTypes, self.simpleTypes)
            if classTypeName['nameClassType'] == '':
                resultReport += '<span style="color:red;font-size:11pt;">для слоя не удалось определить класс в соответствии с Приказом 10</span><br />'
                progress.setValue(countL + 1)
                continue
            resultReport += f'<span style="color:green;font-size:10pt;">слой определен к классу Приказа 10: <b>{classTypeName["nameClassType"]}</b></span><br />'
            layerGeomType = layerForCheck.wkbType()
            resultReport += f'<span style="font-size:10pt;"><b>-----------------------------------</b></span><br />'
            resultReport += '<span style="font-size:10pt;"><b>Проверка структуры слоя: </b></span><br />'
            fieldsReport = checkLayerOnFields(layerForCheck, self.complexTypes, self.simpleTypes, classTypeName["nameClassType"], onlyReqFieldFlag)
            if fieldsReport == '':
                resultReport += f'<span style="color:green;">Состав атрибутов слоя соответсвует требованиям Приказа 10</b></span><br />'
            else:
                resultReport += checkLayerOnFields(layerForCheck, self.complexTypes, self.simpleTypes, classTypeName["nameClassType"], onlyReqFieldFlag)
            resultReport += f'<span style="font-size:10pt;"><b>-----------------------------------</b></span><br />'
            resultReport += '<span style="font-size:10pt;"><b>Проверка объектов слоя: </b></span><br />'
            resultFeature = checkFeatures(layerForCheck, self.complexTypes, self.simpleTypes, classTypeName["nameClassType"], onlyReqFieldFlag)
            if resultFeature == '':
                resultReport += f'<span style="color:green;font-size:10pt;">объекты слоя соответствуют требованиям</span><br />'
            else:
                resultReport += resultFeature
            resultReport += f'<span style="font-size:10pt;"><b>===================================</b></span><br />'
            progress.setValue(countL + 1)
        self.iface.messageBar().clearWidgets()
        resultReport += ''
        return resultReport

    def checkLayers(self):
        if not self.licMngr.showDlgDemoMode():
            return
        if self.first_start == True:
            self.first_start = self.initTypes(self.defXSD)

        if self.first_start == True:
            return
        
        # заполняем далог значениями для ОКТМО и ЗУ
        exceptLayerForOKTMO = []
        numAllLayers = 0
        for layer in QgsProject.instance().mapLayers().values():
            numAllLayers += 1
            if not isinstance(layer, QgsVectorLayer):
                exceptLayerForOKTMO.append(layer)
                continue
            if str(layer.geometryType()).replace('GeometryType.', '') != '2':
                exceptLayerForOKTMO.append(layer)
                continue
            if 'OKTMO' not in layer.fields().names():
                exceptLayerForOKTMO.append(layer)
                continue
        if len(exceptLayerForOKTMO) >= numAllLayers:
            self.dlgCheck.checkBox_4.setCheckState(False)
            self.dlgCheck.checkBox_4.setEnabled(False)
            self.dlgCheck.mMapLayerComboBox_2.setEnabled(False)
            self.dlgCheck.lineEdit.setEnabled(False)
        else:
            self.dlgCheck.checkBox_4.setEnabled(True)
            self.dlgCheck.mMapLayerComboBox_2.setEnabled(True)
            self.dlgCheck.lineEdit.setEnabled(True)
            self.dlgCheck.mMapLayerComboBox_2.setExceptedLayerList(exceptLayerForOKTMO)

        exceptLayerForZU = []
        numAllLayers = 0
        self.dlgCheck.parcelKPT = dict()
        for layer in QgsProject.instance().mapLayers().values():
            numAllLayers += 1
            if not isinstance(layer, QgsVectorLayer):
                exceptLayerForZU.append(layer)
                continue
            if str(layer.geometryType()).replace('GeometryType.', '') != '2':
                exceptLayerForZU.append(layer)
                continue
            fieldList = list(layer.fields().names())
            if layer.featureCount() < 1:
                exceptLayerForZU.append(layer)
                continue
            for feat in layer.getFeatures():
                for field in layer.fields():
                    if field.type() != QVariant.String:
                        fieldList.remove(field.name())
                        continue
                    strValues = feat[field.name()]
                    if str(strValues) in ['NULL', 'Null']:
                        fieldList.remove(field.name())
                        continue
                    try:
                        if len(strValues) > 0:
                            if len(strValues.split(':')) != 4:
                                fieldList.remove(field.name())
                        else:
                            fieldList.remove(field.name())
                    except:
                        print('слой с ошибкой:', layer.name(), ' атрибут:', field.name(), ' ', field.type())
                if len(fieldList) < 1:
                    exceptLayerForZU.append(layer)
                else:
                    self.dlgCheck.parcelKPT[layer.id()] = QgsFields()
                    for fieldName in fieldList:
                        self.dlgCheck.parcelKPT[layer.id()].append(layer.fields()[fieldName])
                break
        if len(exceptLayerForZU) >= numAllLayers:
            self.dlgCheck.checkBox_7.setCheckState(False)
            self.dlgCheck.checkBox_7.setEnabled(False)
            self.dlgCheck.mMapLayerComboBox.setEnabled(False)
            self.dlgCheck.mFieldComboBox.setEnabled(False)
        else:
            self.dlgCheck.checkBox_7.setEnabled(True)
            self.dlgCheck.mMapLayerComboBox.setEnabled(True)
            self.dlgCheck.mFieldComboBox.setEnabled(True)
            self.dlgCheck.mMapLayerComboBox.setExceptedLayerList(exceptLayerForZU)
            self.dlgCheck.mFieldComboBox.setFields(self.dlgCheck.parcelKPT[self.dlgCheck.mMapLayerComboBox.currentLayer().id()])

        self.dlgCheck.show()
        result = self.dlgCheck.exec_()
        if not result:
            return
        
        onlyReqFieldFlag = self.dlgCheck.checkBox.isChecked()
        autoCorrectFlag = self.dlgCheck.checkBox_2.isChecked()
        correctFlags = {"globalidFlag": self.dlgCheck.checkBox_3.isChecked(),
                        "oktmoFlag": self.dlgCheck.checkBox_4.isChecked(),
                        "geomParamFlag": self.dlgCheck.checkBox_5.isChecked(),
                        "nullIfFlag": self.dlgCheck.checkBox_6.isChecked(),
                        "nullGeomFlag": self.dlgCheck.checkBox_8.isChecked(),
                        "zuFlag": self.dlgCheck.checkBox_7.isChecked(),}
        
        selectedLayersList = self.iface.layerTreeView().selectedLayers()
        rtfReport = ''

        if autoCorrectFlag:
            rtfReport += self.checkLayers_AutoCorrect(selectedLayersList, correctFlags)
            rtfReport += f'<span style="font-size:16pt;"><b>=================================</b></span><br />'
        rtfReport += self.checkLayers_Check(selectedLayersList, onlyReqFieldFlag)
        self.dlgCheckReport.textBrowser.setHtml(rtfReport)
        self.dlgCheckReport.show()
        return
    
    def dellUZnak(self):
        if not self.licMngr.showDlgDemoMode():
            return
        selectedLayersList = [l for l in self.iface.layerTreeView().selectedLayers() 
                          if isinstance(l, QgsVectorLayer)]

        if not selectedLayersList:
            return

        for layerForStyle in selectedLayersList:
            delNullSymbols(layerForStyle)

            self.iface.layerTreeView().refreshLayerSymbology(layerForStyle.id())

            layerForStyle.triggerRepaint()
        
        self.iface.statusBarIface().showMessage(f"Очистка легенды завершена для {len(selectedLayersList)} слоев", 3000)
        return
    
    def exportPlanOKS(self):
        if not self.licMngr.showDlgDemoMode():
            return
        if self.first_start == True:
            self.first_start = self.initTypes(self.defXSD)

        if self.first_start == True:
            return
        
        self.dlgchooseExportPlace.mQgsFileWidget.setStorageMode(QgsFileWidget.StorageMode.SaveFile)
        self.dlgchooseExportPlace.mQgsFileWidget.setFilter('*.csv')
        
        result = True
        # Run the dialog event loop
        if self.dlg.checkBox_3.isChecked():
            self.dlgchooseExportPlace.show()
            result = self.dlgchooseExportPlace.exec_()
        if result:
            selectedLayersList = self.iface.layerTreeView().selectedLayers()
            allList = []

            progressMessageBar = self.iface.messageBar().createMessage("МирГрадЪ - ДТП: Экспорт планироуемых ОКС...")
            progress = QProgressBar()
            progress.setMaximum(len(selectedLayersList))
            progress.setAlignment(Qt.AlignLeft|Qt.AlignVCenter)
            progressMessageBar.layout().addWidget(progress)
            self.iface.messageBar().pushWidget(progressMessageBar, 0)

            for i, layer in enumerate(selectedLayersList):
                if not isinstance(layer, QgsVectorLayer):
                    continue
                if not {'CLASSID', 'NUMBER', 'STATUS', 'REG_STATUS'}.issubset(set(layer.fields().names())):
                    continue
                classTypeName = self.getLayerClassTypeOrder10(layer, self.complexTypes, self.simpleTypes)
                if classTypeName["nameClassType"] == '':
                    continue
                reqAttrList = [AttrName for AttrName, value in self.complexTypes[classTypeName["nameClassType"]]['attributes'].items() 
                               if self.complexTypes[classTypeName["nameClassType"]]['attributes'][AttrName]['minOccurs'] == 'Y'
                               or 'STATUS=[2' in self.complexTypes[classTypeName["nameClassType"]]['attributes'][AttrName]['mirDepend'] 
                               and AttrName in layer.fields().names()]
                if len(reqAttrList) < 4:
                    continue
                objFromLayerList = []
                reqAttrList = [attr for attr in reqAttrList if attr in layer.fields().names()]
                maxLenSortAttr = 0
                
                for feature in layer.getFeatures():
                    if str(feature['STATUS']) == '1':
                        continue
                    objList = []
                    for attr in [a for a in reqAttrList if a in layer.fields().names()]:
                        baseType = self.complexTypes[classTypeName["nameClassType"]]['attributes'][attr]['baseType']
                        attrValue = ''
                        if 'fgistp:' in baseType:
                            attrDict = self.simpleTypes[baseType.replace('fgistp:', '')]['dictValues']
                            attrValue = attrDict.get(str(feature[attr]), feature[attr])
                        else:
                            attrValue = feature[attr]
                        
                        objList.append(attrValue)
                    featureNumber = ''
                    if not checkAttrValueForNull(feature['NUMBER'], feature.fields()['NUMBER']):
                        featureNumber = feature['NUMBER']
                    objList.append([int(x) for x in findall(r'\d+',featureNumber)])
                    objList[-1].extend([int(feature['REG_STATUS']), int(feature['STATUS']), int(feature['CLASSID'])])
                    if maxLenSortAttr < len(objList[-1]): maxLenSortAttr = len(objList[-1])
                    objFromLayerList.append(objList)
                for element in  objFromLayerList:
                    while len(element[-1]) < maxLenSortAttr:
                        element[-1].insert(-3, 0)
                objFromLayerList = sorted(objFromLayerList,key=lambda l:l[-1])
                objFromLayerList = [obj[:-1] for obj in objFromLayerList]
                if(len(objFromLayerList)) < 1:
                    continue
                objFromLayerList.insert(0, reqAttrList)
                allList.extend([[layer.name(),],])
                allList.extend(objFromLayerList)
                progress.setValue(i + 1)
            self.iface.messageBar().clearWidgets()
            
            if not self.dlg.checkBox_3.isChecked() or self.dlgchooseExportPlace.mQgsFileWidget.filePath() == '':
                clipboard = QgsApplication.clipboard()
                clipboard.setText('\n'.join(['\t'.join(map(str, row)) for row in allList]))
            elif self.dlgchooseExportPlace.mQgsFileWidget.filePath() != '':
                outputToFile = '\n'.join(['|'.join(map(str, row)) for row in allList])
                with open(self.dlgchooseExportPlace.mQgsFileWidget.filePath(), 'w', encoding='utf-8') as f:
                    f.write(outputToFile)
        return
    
    def searchObject(self):
        if not self.licMngr.showDlgDemoMode():
            return
        
        selectedLayersList = [l for l in self.iface.layerTreeView().selectedLayers() if isinstance(l, QgsVectorLayer)]
        if not selectedLayersList:
            return
        
        setOfFields = QgsFields()
        try:
            attribName = self.dlgSearchObj.mFieldComboBox.currentField()
        except:
            attribName = ''
        for layerForSearch in selectedLayersList:
            for field in layerForSearch.fields():
                if field not in setOfFields.toList():
                    setOfFields.append(field)
        
        self.dlgSearchObj.mFieldComboBox.setFields(setOfFields)
        if attribName in setOfFields.names():
            self.dlgSearchObj.mFieldComboBox.setField(attribName)
        elif 'GLOBALID' in setOfFields.names():
            self.dlgSearchObj.mFieldComboBox.setField('GLOBALID')

        self.dlgSearchObj.show()
        result = self.dlgSearchObj.exec_()

        if not result or self.dlgSearchObj.lineEdit.text() == '':
            return
        
        attribName = self.dlgSearchObj.mFieldComboBox.currentField()
        indxField = setOfFields.indexFromName(attribName)
        attribField = setOfFields.field(indxField)
        attribValue = self.dlgSearchObj.lineEdit.text()

        if attribField.type() == QVariant.String:
            attribValue = f"'{attribValue}'"
        else:
            attribValue = str(attribValue)
        if self.dlgSearchObj.checkBox.isChecked() and attribField.type() == QVariant.String:
            expressionForSearch = f'strpos("{attribName}", {attribValue})'
        else:
            expressionForSearch = f'"{attribName}" = {attribValue}'

        for layerForSearch in selectedLayersList:
            if layerForSearch.fields().indexFromName(attribName) == -1:
                continue

            layerForSearch.selectByExpression(expressionForSearch)

            if layerForSearch.selectedFeatureCount() > 0:
                self.iface.mapCanvas().zoomToFeatureIds(layerForSearch, layerForSearch.selectedFeatureIds())
                self.iface.setActiveLayer(layerForSearch)
                break
        return
    
    def exportGMLfgis(self):
        if not self.licMngr.showDlgDemoMode():
            return
        if self.first_start == True:
            self.first_start = self.initTypes(self.defXSD)

        if self.first_start == True:
            return
        
        selectedLayersList = self.iface.layerTreeView().selectedLayers()
        if not selectedLayersList:
            return
        
        layersTreeForGML = dict()

        for element in self.elementTypes:
            mirGroup = self.elementTypes[element].get('mirGroup', 'noneGroup')
            if mirGroup == '':
                mirGroup = 'noneGroup'
            if mirGroup not in layersTreeForGML:
                layersTreeForGML[mirGroup] = dict()
        
        layersTreeForGML['noneGroup'] = dict()

        for layer in selectedLayersList:
            if not isinstance(layer, QgsVectorLayer):
                continue
            layerClassTypeName = self.getLayerClassTypeOrder10(layer, self.complexTypes, self.simpleTypes)["nameClassType"]
            if layerClassTypeName == '':
                #                                           [0_имя слоя, 1_ПланирОКС, 2_Обосн, 3_Границ, 4_ФЗ, 5_Примечание]
                layersTreeForGML['noneGroup'][layer.id()] = [layer.name(), False, False, False, False, 'Для слоя не найден класс по Приказу 10']
                continue

            layerCRS = layer.crs()
            layerGroup = self.elementTypes[layerClassTypeName.replace('_Type', '')].get('mirGroup', 'noneGroup')

            if not layerCRS.isValid() or layerCRS.description() == 'Nonearth':
                layersTreeForGML[layerGroup][layer.id()] = [layer.name(), False, False, False, False, 'Для слоя не определена СК']
                continue

            if layer.featureCount() < 1:
                layersTreeForGML[layerGroup][layer.id()] = [layer.name(), False, False, False, False, 'Слой не содержит объектов']
                continue

            layersTreeForGML[layerGroup][layer.id()] = [layer.name(), False, False, False, False, self.elementTypes[layerClassTypeName.replace('_Type', '')].get('typeUserName', '')]
            
            if layerClassTypeName == 'FunctionalZone_Type':
                layersTreeForGML[layerGroup][layer.id()][4] = True
                continue
            if layerGroup == 'Границы субъектов Российской Федерации, муниципальных образований, населенных пунктов':
                layersTreeForGML[layerGroup][layer.id()][3] = True
                continue
            layersTreeForGML[layerGroup][layer.id()][2] = True
            if 'NUMBER' in layer.fields().names():
                layersTreeForGML[layerGroup][layer.id()][1] = True

        for ind in range(self.dlgSetupGML.treeWidget.topLevelItemCount() - 1, -1, -1):
            self.dlgSetupGML.treeWidget.takeTopLevelItem(ind)

        for parentName in list(layersTreeForGML.keys()):
            if len(list(layersTreeForGML[parentName].keys())) < 1:
                continue
            parent = QTreeWidgetItem(self.dlgSetupGML.treeWidget)
            parent.setText(0, parentName)
            parent.setFlags(parent.flags() | Qt.ItemIsTristate | Qt.ItemIsUserCheckable)
            for layersID in list(layersTreeForGML[parentName].keys()):
                layersName = layersTreeForGML[parentName][layersID][0]
                layersParam = layersTreeForGML[parentName][layersID]
                child = QTreeWidgetItem(parent)
                child.setFlags(child.flags() | Qt.ItemIsUserCheckable)
                child.setText(0, layersName)
                if any(layersParam[1:-1]):
                    child.setCheckState(0, Qt.Checked)
                else:
                    child.setCheckState(0, Qt.Unchecked)
                    child.setDisabled(True)
                child.setText(5, layersParam[5])
                child.setToolTip(0, layersID)
                if layersParam[1]:
                    child.setText(1, "")
                    child.setCheckState(1, Qt.Checked)
                else:
                    child.setCheckState(1, Qt.Unchecked)
                if layersParam[2]:
                    child.setText(2, "")
                    child.setCheckState(2, Qt.Checked)
                else:
                    child.setCheckState(2, Qt.Unchecked)
                if layersParam[3]:
                    child.setText(3, "")
                    child.setCheckState(3, Qt.Checked)
                else:
                    child.setCheckState(3, Qt.Unchecked)
                if layersParam[4]:
                    child.setText(4, "")
                    child.setCheckState(4, Qt.Checked)
                else:
                    child.setCheckState(4, Qt.Unchecked)

        self.dlgSetupGML.show()
        result = self.dlgSetupGML.exec_()
        listObjectClassTypeNamesAll = ['AdmBorder_Type', 'AdmeRF_Type', 'AdmeSRF_Type', 'AdmeMO_Type', 'AdmeNP_Type', 'Heritage_Type', 'FunctionalZone_Type', 'LandUse_Type']
        nameGmlFilesList = ['заглушка',
                            'Карта планируемого размещения объектов',
                            'Материалы по обоснованию в виде карт',
                            ]
        if result:
            pathToExport = self.dlgSetupGML.mQgsFileWidget.filePath()
            separateFileFlag = self.dlgSetupGML.checkBox.isChecked()
            exportReport = ''
            targetCRS = QgsCoordinateReferenceSystem(self.dlgSetupGML.comboBox.currentText().split(' ')[0])
            exportRegionFlag = False
            if self.dlgSetupGML.comboBox_2.currentText() == 'Регионального значения':
                exportRegionFlag = True
            stpFlag = False
            if self.dlgSetupGML.comboBox_3.currentText() == 'Схема территориального планирования':
                stpFlag = True
            if stpFlag:
                nameGmlFilesList.extend(['Карта границы муниципальных образований - городских округов, муниципальных районов, поселений, утвержденные в установленном порядке законом соответствующего субъекта Российской Федерации',
                                         'Карта функциональных зон поселения или городского округа'])
            else:
                nameGmlFilesList.extend(['Карта границ населенных пунктов (в том числе границ образуемых населенных пунктов)',
                                         'Карта функциональных зон поселения или городского округа',
                                         ])
            
            gmlFileHeaderFirst = '<?xml version="1.0" encoding="utf-8"?>\n<ogr:FeatureCollection xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ogr="http://ogr.maptools.org/" xmlns:gml="http://www.opengis.net/gml/3.2">\n'
            gmlFileHeader = f'<gml:boundedBy>\n<gml:Envelope srsName="urn:ogc:def:crs:EPSG::{targetCRS.authid().split(":")[1]}">\n'
            
            extentLayerRect = None
            gmlFilesContent = dict()
            for fileName in nameGmlFilesList:
                gmlFilesContent[fileName] = []
            it = QTreeWidgetItemIterator(self.dlgSetupGML.treeWidget)

            while it.value() is not None:
                item = it.value()
                if item.isDisabled():
                    it += 1
                    continue
                if item.childCount() < 1:

                    layer = QgsProject.instance().mapLayer(item.toolTip(0))
                    layerName = ''
                    if separateFileFlag:
                        layerName = '_'+layer.name()
                    layerCRS = layer.crs()
                    tr = QgsCoordinateTransform(layerCRS, targetCRS, QgsProject.instance())
                    try:
                        extentLayerRectLayer = tr.transformBoundingBox(layer.extent())
                    except Exception as exc:
                        self.iface.messageBar().pushMessage("Экспорт GML, Error", f"Имя слоя {layer.name()} необходимов исправить геометрию", level=2)
                        if extentLayerRect is None:
                            return
                    
                    if extentLayerRect is None:
                        extentLayerRect = extentLayerRectLayer
                    else:
                        extentLayerRectLayer = extentLayerRect.combineExtentWith(extentLayerRectLayer)
                        if extentLayerRectLayer is not None:
                            extentLayerRect = extentLayerRectLayer
                    """ if extentLayerRectLayer is None:
                        self.iface.messageBar().pushMessage("Экспорт GML, Error", f"Имя слоя {layer.name()} не определен extentRect, transform is {tr.isValid()}", level=2) """
                        
                    layerClassTypeName = self.getLayerClassTypeOrder10(layer, self.complexTypes, self.simpleTypes)["nameClassType"]
                    if layerClassTypeName == '':
                        it += 1
                        continue
                    if item.checkState(0) and (item.checkState(1) or item.checkState(2) or item.checkState(3) or item.checkState(4)):
                        if item.checkState(1): #Карта планируемых ОКС
                            expressionForPlan = ''
                            if 'STATUS' in list(layer.fields().names()):
                                expressionForPlan += '(to_int("STATUS") = 2 or to_int("STATUS") = 3)'
                            if 'REG_STATUS' in list(layer.fields().names()):
                                if exportRegionFlag:
                                    if len(expressionForPlan) > 0:
                                        expressionForPlan += ' and '
                                    expressionForPlan += 'to_int("REG_STATUS") = 2'
                                else:
                                    if len(expressionForPlan) > 0:
                                        expressionForPlan += ' and '
                                    expressionForPlan += 'to_int("REG_STATUS") > 2'
                            if expressionForPlan == '' or layerClassTypeName in listObjectClassTypeNamesAll:
                                for featForGML in layer.getFeatures():
                                    featStrGML = createGMLstring(featForGML, layerClassTypeName, self.complexTypes[layerClassTypeName], layerCRS, targetCRS)
                                    if nameGmlFilesList[1] + layerName not in gmlFilesContent.keys():
                                        gmlFilesContent[nameGmlFilesList[1] + layerName] = []
                                    gmlFilesContent[nameGmlFilesList[1] + layerName].append(featStrGML)
                            else:
                                for featForGML in layer.getFeatures(expressionForPlan):
                                    featStrGML = createGMLstring(featForGML, layerClassTypeName, self.complexTypes[layerClassTypeName], layerCRS, targetCRS)
                                    if nameGmlFilesList[1] + layerName not in gmlFilesContent.keys():
                                        gmlFilesContent[nameGmlFilesList[1] + layerName] = []
                                    gmlFilesContent[nameGmlFilesList[1] + layerName].append(featStrGML)
                        if item.checkState(2): #Материалы по обоснованию
                            expressionForPlan = ''
                            if 'STATUS' in list(layer.fields().names()) and item.checkState(1):
                                expressionForPlan += 'to_int("STATUS") != 2'
                            if 'REG_STATUS' in list(layer.fields().names()) and item.checkState(1):
                                if exportRegionFlag:
                                    if len(expressionForPlan) > 0:
                                        expressionForPlan += ' or '
                                    expressionForPlan += 'to_int("REG_STATUS") != 2'
                                else:
                                    if len(expressionForPlan) > 0:
                                        expressionForPlan += ' or '
                                    expressionForPlan += 'to_int("REG_STATUS") < 3'
                            if expressionForPlan == '' or layerClassTypeName in listObjectClassTypeNamesAll:
                                for featForGML in layer.getFeatures():
                                    if nameGmlFilesList[2] + layerName not in gmlFilesContent.keys():
                                        gmlFilesContent[nameGmlFilesList[2] + layerName] = []
                                    gmlFilesContent[nameGmlFilesList[2] + layerName].append(createGMLstring(featForGML, layerClassTypeName, self.complexTypes[layerClassTypeName], layerCRS, targetCRS))
                            else:
                                for featForGML in layer.getFeatures(expressionForPlan):
                                    if nameGmlFilesList[2] + layerName not in gmlFilesContent.keys():
                                        gmlFilesContent[nameGmlFilesList[2] + layerName] = []
                                    gmlFilesContent[nameGmlFilesList[2] + layerName].append(createGMLstring(featForGML, layerClassTypeName, self.complexTypes[layerClassTypeName], layerCRS, targetCRS))
                        if item.checkState(3): #Карта границ
                            for featForGML in layer.getFeatures():
                                if nameGmlFilesList[3] + layerName not in gmlFilesContent.keys():
                                    gmlFilesContent[nameGmlFilesList[3] + layerName] = []
                                gmlFilesContent[nameGmlFilesList[3] + layerName].append(createGMLstring(featForGML, layerClassTypeName, self.complexTypes[layerClassTypeName], layerCRS, targetCRS))
                        if item.checkState(4): #Карта ФЗ
                            expressionForPlan = ''
                            if 'STATUS' in list(layer.fields().names()):
                                expressionForPlan += 'to_int("STATUS") > 1'
                            if expressionForPlan == '' or layerClassTypeName in listObjectClassTypeNamesAll:
                                for featForGML in layer.getFeatures():
                                    featStrGML = createGMLstring(featForGML, layerClassTypeName, self.complexTypes[layerClassTypeName], layerCRS, targetCRS)
                                    if nameGmlFilesList[4] + layerName not in gmlFilesContent.keys():
                                        gmlFilesContent[nameGmlFilesList[4] + layerName] = []
                                    gmlFilesContent[nameGmlFilesList[4] + layerName].append(featStrGML)
                            else:
                                for featForGML in layer.getFeatures(expressionForPlan):
                                    featStrGML = createGMLstring(featForGML, layerClassTypeName, self.complexTypes[layerClassTypeName], layerCRS, targetCRS)
                                    if nameGmlFilesList[4] + layerName not in gmlFilesContent.keys():
                                        gmlFilesContent[nameGmlFilesList[4] + layerName] = []
                                    gmlFilesContent[nameGmlFilesList[4] + layerName].append(featStrGML)
                it += 1
            gmlFileHeader += f'<gml:lowerCorner>{extentLayerRect.xMinimum()} {extentLayerRect.yMinimum()}</gml:lowerCorner>\n'
            gmlFileHeader += f'<gml:upperCorner>{extentLayerRect.xMaximum()} {extentLayerRect.yMaximum()}</gml:upperCorner>\n'
            gmlFileHeader += '</gml:Envelope>\n</gml:boundedBy>\n'
            for gmlFileName, features in gmlFilesContent.items():
                if len(features) < 1:
                    continue
                gmlFileContent = f'<?xml version="1.0" encoding="utf-8"?>\n<ogr:FeatureCollection xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://ogr.maptools.org/{gmlFileName}.xsd" xmlns:ogr="http://ogr.maptools.org/" xmlns:gml="http://www.opengis.net/gml">\n'
                gmlFileContent += gmlFileHeader
                gmlFileContent += '\n'.join(features)
                gmlFileContent += '</ogr:FeatureCollection>'
                with open(pathToExport + '/' + gmlFileName + '.gml', 'w', encoding='utf-8') as f:
                    f.write(gmlFileContent)
            return

    def help(self):
        self.dlgAbout.show()
        result = self.dlgAbout.exec_()
        return
    
    def createLegend(self):
        if self.first_start == True:
            self.first_start = self.initTypes(self.defXSD)
        if self.first_start == True:
            return
        
        self.dlgSetupLegend.mQgsFileWidget.setStorageMode(QgsFileWidget.StorageMode.GetDirectory)
        self.dlgSetupLegend.show()
        result = self.dlgSetupLegend.exec_()
        if not result:
            return

        notOrder10SymbolFlag = True
        allSymbolFlag = self.dlgSetupLegend.checkBox.isChecked()

        selectedLayersList = self.iface.layerTreeView().selectedLayers()
        symbolsLegend = dict()

        if self.dlgSetupLegend.checkBox_2.isChecked():
            tempPath = self.dlgSetupLegend.mQgsFileWidget.filePath()
        else:
            tempPath = os.path.expanduser("~") + '\Documents\Qgis\MyLegend'
            try:
                os.makedirs(tempPath, exist_ok=True)
            except Exception as ex:
                print(ex)

        img = QImage( QSize( 201, 106 ), QImage.Format_ARGB32_Premultiplied )
        img.setDotsPerMeterY(11811)
        img.setDotsPerMeterX(11811)
        """ screen = QgsScreenProperties()
        screen.setDevicePixelRatio(1.0)
        screen.setPhysicalDpi(300.0) """
        painter = QPainter(img)
        uslZnWidth = painter.device().widthMM()
        uslZnHeight = painter.device().heightMM()
        renderContext = QgsRenderContext()
        renderContext.setExpressionContext(QgsExpressionContext())
        if len(selectedLayersList) < 1:
            return
        for layer in selectedLayersList:
            if not isinstance(layer, QgsVectorLayer):
                continue
            layerGeomType = layer.geometryType()
            layerFields = layer.fields()
            if 'CLASSID' not in list(layerFields.names()):
                continue
            classTypeName = self.getLayerClassTypeOrder10(layer, self.complexTypes, self.simpleTypes)["nameClassType"]
            
            if classTypeName == '':
                continue
            if allSymbolFlag:
                applyStyleSymbols(layer, self.simpleTypes, self.complexTypes, self.plugin_dir + '/res/Symbols',classTypeName)
            attrsForLegend = dict()
            attrType = self.complexTypes[classTypeName]['attributes']['CLASSID']["baseType"].replace('fgistp:','')
            attrsForLegend['CLASSID'] = self.simpleTypes[attrType]['dictValues']
            if 'REG_STATUS' in list(layerFields.names()) and 'REG_STATUS' in self.complexTypes[classTypeName]['attributes'].keys():
                attrType = self.complexTypes[classTypeName]['attributes']['REG_STATUS']["baseType"].replace('fgistp:','')
                attrsForLegend['REG_STATUS'] = self.simpleTypes[attrType]['dictValues']
            if 'STATUS' in list(layerFields.names()) and 'STATUS' in self.complexTypes[classTypeName]['attributes'].keys():
                attrType = self.complexTypes[classTypeName]['attributes']['STATUS']["baseType"].replace('fgistp:','')
                attrsForLegend['STATUS'] = self.simpleTypes[attrType]['dictValues']
            elif 'STATUS_ADM' in list(layerFields.names()) and 'STATUS_ADM' in self.complexTypes[classTypeName]['attributes'].keys():
                attrType = self.complexTypes[classTypeName]['attributes']['STATUS_ADM']["baseType"].replace('fgistp:','')
                attrsForLegend['STATUS_ADM'] = self.simpleTypes[attrType]['dictValues']
            else:
                attrsForLegend['STATUS'] = {'0': '0'}
            """ f_temp = open('d:/log.txt', 'w')
            f_temp.write(attrType)
            f_temp.close() """
            layerRenderer = layer.renderer().clone()

            """ f_temp = open('d:/log.txt', 'w')
            f_temp.write('        23')
            f_temp.close()
            sym_items = layerRenderer.legendSymbolItems()
            symb_dict = {s.ruleKey(): s.label() for s in sym_items} """
            """ f_temp = open('d:/log.txt', 'w')
            f_temp.write('        23')
            f_temp.close() """
            expressionForFeat = ''
            #print(sdf)
            #print(sdf)
            renderContext.expressionContext().appendScopes(QgsExpressionContextUtils.globalProjectLayerScopes(layer))          
            # добавить проверку наличия [classTypeName] в symbolsLegend, если есть не добавлять
            if symbolsLegend.get(classTypeName, None) is None:
                symbolsLegend[classTypeName] = {'className': self.elementTypes[classTypeName.replace('_Type','')]['typeUserName'].replace('Класс объектов «', '').replace('»', ''),
                                                'legendItems': dict()}
            for classid in attrsForLegend['CLASSID'].keys():
                classidName = attrsForLegend['CLASSID'][classid]
                # добавить проверку наличия [classidName] в symbolsLegend[classTypeName]['legendItems'], если есть не добавлять
                if symbolsLegend[classTypeName]['legendItems'].get(classidName, None) is None:
                    symbolsLegend[classTypeName]['legendItems'][classidName] = [[False, False, False, False], classid]
                statusList = attrsForLegend.get('STATUS', [])
                if len(statusList) > 0:
                    statusList = list(statusList.keys())
                    statusAttr = 'STATUS'
                else:
                    statusList = list(attrsForLegend['STATUS_ADM'].keys())
                    statusAttr = 'STATUS_ADM'
                for status in statusList:
                    if status == '0':
                        expressionForFeat = f'"CLASSID" = {classid}'
                    else:
                        expressionForFeat = f'"CLASSID" = {classid} and "{statusAttr}" = {status}'
                    existFeatureFlag = False
                    for feat in layer.getFeatures(expressionForFeat):
                        existFeatureFlag = True
                        break
                    
                    if existFeatureFlag or allSymbolFlag:
                        featForSymbol = QgsFeature(layerFields)
                        
                        featForSymbol["CLASSID"] = classid
                        if status != '0':
                            featForSymbol[statusAttr] = status
                        if 'REG_STATUS' in list(layer.fields().names()):
                            featForSymbol['REG_STATUS'] = 3
                        
                        renderContext.expressionContext().setFeature(featForSymbol)
                        layerRenderer.startRender(renderContext, layerFields)
                        if layerRenderer.type() == 'singleSymbol':
                            symbolFeat = [layerRenderer.symbol(),]
                            symblabels = ['pass',]
                        else:
                            symbolFeat = layerRenderer.symbolsForFeature(featForSymbol, renderContext)
                            #layerRenderer.stopRender(renderContext)
                            sym_items = layerRenderer.legendSymbolItems()
                            symb_dict = {s.ruleKey(): s.label() for s in sym_items}
                            #print(symb_dict)
                            symblabels = [symb_dict.get(key, 'empty') for key in layerRenderer.legendKeysForFeature(featForSymbol, renderContext)]
                        layerRenderer.stopRender(renderContext)
                        if '' in symblabels:
                            continue
                        if status == '0':
                            status = 1
                        if len(symbolFeat) > 0:
                            img.fill(0)
                            painter.begin(img)
                            if str(layerGeomType) == 'GeometryType.Polygon':
                                painter.translate(10, 10)
                                symbolFeat[0].drawPreviewIcon(painter, QSize(180, 85), expressionContext=renderContext.expressionContext())
                                #, screen=screen)
                            else:
                                symbolFeat[0].drawPreviewIcon(painter, QSize(201, 106), expressionContext=renderContext.expressionContext())
                                #, screen=screen)
                            painter.end()
                            img.save(tempPath + '/' + str(classid) + '_' + str(status) + '.png', 'PNG')
                            symbolsLegend[classTypeName]['legendItems'][classidName][0][int(status) - 1] = img
            renderContext.expressionContext().popScope()

        project = QgsProject.instance()
        layoutManager = project.layoutManager()
        legendLayoutName = 'МирГрадЪ - ДТП Условные обозначения'
        layoutsList = layoutManager.printLayouts()
        for layout in layoutsList:
            if layout.name() == legendLayoutName:
                layoutManager.removeLayout(layout)
        legendLayout = QgsPrintLayout(project)
        legendLayout.initializeDefaults()
        legendLayout.setName(legendLayoutName)
        layoutManager.addLayout(legendLayout)
        rowCounter = 1
        groupName = ''
        y = 5

        groupNameTitleitem = QgsLayoutItemLabel(legendLayout)
        groupNameTitleitem.setText('   Сущ.          План.      Реконстр.    Ликвид.')
        font = QFont('Times New Roman', 12)
        groupNameTitleitem.setFont(font)
        legendLayout.addLayoutItem(groupNameTitleitem)
        groupNameTitleitem.adjustSizeToText()
        groupNameTitleitem.attemptMove(QgsLayoutPoint(10, y, QgsUnitTypes.LayoutMillimeters))
        y += groupNameTitleitem.sizeWithUnits().height() + 1

        for className in self.groupDict.keys():
            if groupName != '' and groupName != self.groupDict[className]:
                groupName = ''
            if self.elementTypes[className]['elementType'].replace('fgistp:', '') not in list(symbolsLegend.keys()):
                continue
            if groupName == '':
                groupName = self.groupDict[className]
                groupNameTitleitem = QgsLayoutItemLabel(legendLayout)
                groupNameTitleitem.setText(groupName)
                font = QFont('Times New Roman', 12, QFont.Bold)
                font.setUnderline(True)
                groupNameTitleitem.setFont(font)
                legendLayout.addLayoutItem(groupNameTitleitem)
                groupNameTitleitem.adjustSizeToText()
                groupNameTitleitem.attemptMove(QgsLayoutPoint(10, y, QgsUnitTypes.LayoutMillimeters))
                y += groupNameTitleitem.sizeWithUnits().height() + 1
            classGroup = QgsLayoutItemGroup(legendLayout)
            classTypeName = self.elementTypes[className]['elementType'].replace('fgistp:', '')
            classNameTitleitem = QgsLayoutItemLabel(legendLayout)
            classNameTitleitem.setText(symbolsLegend[classTypeName]['className'])
            classGroup.setId('Группа: ' + symbolsLegend[classTypeName]['className'])
            classNameTitleitem.setFont(QFont('Times New Roman', 12, QFont.Bold))
            legendLayout.addLayoutItem(classNameTitleitem)
            classNameTitleitem.adjustSizeToText()
            classNameTitleitem.attemptMove(QgsLayoutPoint(10, y, QgsUnitTypes.LayoutMillimeters))
            y += classNameTitleitem.sizeWithUnits().height() + 1
            classGroup.addItem(classNameTitleitem)
            for legendItem in symbolsLegend[classTypeName]['legendItems']:
                x = 10
                if not any(symbolsLegend[classTypeName]['legendItems'][legendItem][0]):
                    continue
                for indx, symbolImage in enumerate(symbolsLegend[classTypeName]['legendItems'][legendItem][0]):
                    if not symbolImage:
                        x += uslZnWidth + 3
                        continue
                    symbolImageItem = QgsLayoutItemPicture(legendLayout)
                    symbolImageItem.setMode(QgsLayoutItemPicture.FormatRaster)
                    symbolImageItem.setPicturePath(tempPath + '/' + str(symbolsLegend[classTypeName]['legendItems'][legendItem][1])
                                                    + '_' + str(indx + 1) + '.png')#, 1)
                    symbolImageItem.setResizeMode(4)
                    symbolImageItem.setId(str(symbolsLegend[classTypeName]['legendItems'][legendItem][1]) + '_' + str(indx + 1))
                    legendLayout.addLayoutItem(symbolImageItem)
                    symbolImageItem.attemptMove(QgsLayoutPoint(x, y, QgsUnitTypes.LayoutMillimeters))
                    x += symbolImageItem.sizeWithUnits().width() + 3
                    classGroup.addItem(symbolImageItem)
                symbolTitleItem = QgsLayoutItemLabel(legendLayout)
                symbolTitleItem.setText(legendItem)
                symbolTitleItem.setFont(QFont('Times New Roman', 12))
                symbolTitleItem.setVAlign(Qt.AlignVCenter)
                size = symbolTitleItem.sizeWithUnits()
                size.setHeight(uslZnHeight)
                size.setWidth(size.width() + 10)
                symbolTitleItem.attemptResize(size)
                legendLayout.addLayoutItem(symbolTitleItem)
                symbolTitleItem.adjustSizeToText()
                symbolTitleItem.attemptMove(QgsLayoutPoint(x, y, QgsUnitTypes.LayoutMillimeters))
                y += uslZnHeight + 2
                classGroup.addItem(symbolTitleItem)
            legendLayout.addLayoutItem(classGroup)
            rowCounter += 1

        return
    
    def createLegendV2(self):
        if not self.licMngr.showDlgDemoMode():
            return
        if self.first_start == True:
            self.first_start = self.initTypes(self.defXSD)

        if self.first_start == True:
            return
        self.dlgSetupLegend.show()
        result = self.dlgSetupLegend.exec_()
        if not result:
            return
        
        elementTypes = self.elementTypes

        def getSymbForFeat(layer, feat):
            layerRenderer = layer.renderer()
            if not layerRenderer:
                return None
            
            renderContext = QgsRenderContext()
            exp_context = layer.createExpressionContext()
            exp_context.setFeature(feat)
            renderContext.setExpressionContext(exp_context)

            layerRenderer.startRender(renderContext, layer.fields())
            symbol = layerRenderer.symbolsForFeature(feat, renderContext)
            layerRenderer.stopRender(renderContext)

            try:
                rabSymbol = symbol[0].clone()
            except:
                return None
            
            def freeze_properties(symbol):
                """Рекурсивно превращает динамические свойства в статические"""
                for s_layer in symbol.symbolLayers():
                    # 1. Запекаем свойства самого слоя символа (размер, поворот, цвет и т.д.)
                    props = s_layer.dataDefinedProperties()
                    for key in props.propertyKeys():
                        if props.isActive(key):
                            val = props.value(key, exp_context)
                            props.setProperty(key, QgsProperty.fromValue(val))
                    
                    # 2. Если есть вложенный символ (например, маркер на линии), запекаем и его
                    if s_layer.subSymbol():
                        freeze_properties(s_layer.subSymbol())

            freeze_properties(rabSymbol)

            return rabSymbol
        
        flagRegStatus = self.dlgSetupLegend.checkBox_2.isChecked() # True - формирование условных для всех уровней объектов отдельно
        flagAllStatus = not self.dlgSetupLegend.checkBox.isChecked() #True - формирование условных для сущ, план, реконстр, ликвид, иначе только существующие
        # TODO пока не работает flagExistFeature, условные только по объектам которые присутствуют в слое
        flagExistFeature = True #True - формирование условных только для объектов присутствующих в слое
        fontName = 'Arial'

        itemsList = dict()

        selectedLayersList = self.iface.layerTreeView().selectedLayers()
        selectedLayersIds = []
        selectedLayersNames = []

        for layer in selectedLayersList:
            selectedLayersIds.append(layer.id())
            selectedLayersNames.append(layer.name())

        for layerOrderName, layerOrderParam in elementTypes.items():
            for indLayer, layer in enumerate(selectedLayersList):
                if not isinstance(layer, QgsVectorLayer):
                    continue
                fieldsNames = layer.fields().names()
                classTypeName = self.getLayerClassTypeOrder10(layer, self.complexTypes, self.simpleTypes)
                if classTypeName['nameClassType'] == '':
                    continue
                if classTypeName['nameClassType'].replace('_Type', '') != layerOrderName:
                    continue
                attrStatusName = ''
                statusList= [1,]
                if 'STATUS' in fieldsNames:
                    if flagAllStatus:
                        statusList = layer.uniqueValues(layer.fields().indexFromName('STATUS'))
                    else:
                        statusList = [1, ]
                    attrStatusName = 'STATUS'
                elif 'STATUS_ADM' in fieldsNames:
                    if flagAllStatus:
                        statusList = layer.uniqueValues(layer.fields().indexFromName('STATUS_ADM'))
                    else:
                        statusList = [1, ]
                    attrStatusName = 'STATUS_ADM'
                else:
                    attrStatusName = ''
                    statusList = [1, ]

                if 'объекты' in layerOrderParam['mirGroup'].lower() and 'природные' not in layerOrderParam['mirGroup'].lower():
                    flagOKS = True
                else:
                    flagOKS = False
                if flagRegStatus and 'REG_STATUS' in fieldsNames and flagOKS:
                    regStatusList = [1, 2, 3]
                else:
                    regStatusList = [3]
                for regStatus in regStatusList:
                    if flagRegStatus and 'REG_STATUS' in fieldsNames and flagOKS:
                        if regStatus == 1:
                            addToKey = 'ФЗ' + layerOrderParam['mirGroup']
                            classidList = sorted(set(QgsVectorLayerUtils().getValues(layer, 'if("REG_STATUS"=1, to_string("CLASSID"), to_string(0))')[0]))[1:]
                        elif regStatus == 2:
                            addToKey = 'РЗ' + layerOrderParam['mirGroup']
                            classidList = sorted(set(QgsVectorLayerUtils().getValues(layer, 'if("REG_STATUS"=2, to_string("CLASSID"), to_string(0))')[0]))[1:]
                        elif regStatus == 3:
                            addToKey = 'МЗ' + layerOrderParam['mirGroup']
                            classidList = sorted(set(QgsVectorLayerUtils().getValues(layer, 'if("REG_STATUS">2, to_string("CLASSID"), to_string(0))')[0]))[1:]
                    else:
                        addToKey = layerOrderParam['mirGroup']
                        classidList = layer.uniqueValues(layer.fields().indexFromName('CLASSID'))
                        classidList = sorted(classidList)
                    
                    if len(classidList) > 0:
                        if addToKey not in itemsList.keys():
                            itemsList[addToKey] = {'type': 'groupTitle', 
                                                    'text': layerOrderParam['mirGroup'],  
                                                    'layers': [{'text': layerOrderParam['typeUserName'].replace('Класс объектов «', '').replace('»', ''),
                                                                'statusLen': max(statusList),
                                                                'rows': []},]}
                        else:
                            itemsList[addToKey]['layers'].append({'text': layerOrderParam['typeUserName'].replace('Класс объектов «', '').replace('»', ''),
                                                                    'statusLen': max(statusList),
                                                                    'rows': []})
                    for classid in classidList:
                        clIDname = str(classid)
                        for dicts in layer.editorWidgetSetup(layer.fields().indexFromName('CLASSID')).config().get('map', []):
                            for key, value in dicts.items():
                                if str(value) == str(classid):
                                    clIDname = key
                        itemsList[addToKey]['layers'][-1]['rows'].append({'text': clIDname, 'symbols': []})
                        for statusId in range(1, itemsList[addToKey]['layers'][-1]['statusLen'] + 1):
                            featRequest = QgsFeatureRequest()
                            if flagAllStatus:
                                featRequest.setFilterExpression(f'"CLASSID"={classid} AND "{attrStatusName}" = {statusId}')
                            else:
                                featRequest.setFilterExpression(f'"CLASSID"={classid} AND "{attrStatusName}" != 2')
                            if attrStatusName == '':
                                featRequest.setFilterExpression(f'"CLASSID"={classid}')
                            for featl in layer.getFeatures(featRequest):
                                featForSymbol = QgsFeature(layer.fields())
                                featForSymbol['CLASSID'] = classid
                                if attrStatusName != '':
                                    if flagAllStatus:
                                        featForSymbol[attrStatusName] = statusId
                                    else:
                                        featForSymbol[attrStatusName] = 1
                                if 'REG_STATUS' in fieldsNames:
                                    if flagRegStatus:
                                        featForSymbol['REG_STATUS'] = regStatus
                                    else:
                                        featForSymbol['REG_STATUS'] = 3
                                itemsList[addToKey]['layers'][-1]['rows'][-1]['symbols'].append(getSymbForFeat(layer, featForSymbol))
                                break
                            else:
                                itemsList[addToKey]['layers'][-1]['rows'][-1]['symbols'].append(None)
                        if not any(itemsList[addToKey]['layers'][-1]['rows'][-1]['symbols']):
                            del itemsList[addToKey]['layers'][-1]['rows'][-1]
                if layer.id() in selectedLayersIds:
                    selectedLayersIds.remove(layer.id())
        
        for indLayer, layer in enumerate(selectedLayersList):
            if not isinstance(layer, QgsVectorLayer):
                continue
            if layer.id() in selectedLayersIds:
                addToKey = 'прочие cлои'
                layerName = layer.name()
                rendererForLayer = layer.renderer()
                legendList = rendererForLayer.legendSymbolItems()
                if addToKey not in itemsList.keys():
                    itemsList[addToKey] = {'type': 'groupTitle', 
                                            'text': '            \n           ',  
                                            'layers': [{'text': layerName,
                                                        'statusLen': 1,
                                                        'rows': []},]}
                else:
                    itemsList[addToKey]['layers'].append({'text': layerName,
                                                            'statusLen': 1,
                                                            'rows': []})
                for legendItem in legendList:
                    if legendItem.symbol() is None:
                        continue
                    itemsList[addToKey]['layers'][-1]['rows'].append({'text': legendItem.label(), 'symbols': []})
                    itemsList[addToKey]['layers'][-1]['rows'][-1]['symbols'].append(legendItem.symbol().clone())
        
        if flagRegStatus:
            firstDict = dict()
            fzDict = dict()
            rzDict = dict()
            mzDict = dict()
            lastDict = dict()
            flagReg = False
            for key, item in itemsList.items():
                if not flagReg:
                    firstDict[key] = item
                if key[:2] == 'ФЗ':
                    flagReg = True
                    fzDict[key] = item
                elif key[:2] == 'РЗ':
                    flagReg = True
                    rzDict[key] = item
                elif key[:2] == 'МЗ':
                    mzDict[key] = item
                    flagReg = True
                else:
                    lastDict[key] = item
            itemsList.clear()
            for key, item in firstDict.items():
                itemsList[key] = item
            for key, item in fzDict.items():
                itemsList[key] = item
            for key, item in rzDict.items():
                itemsList[key] = item
            for key, item in mzDict.items():
                itemsList[key] = item
            for key, item in lastDict.items():
                itemsList[key] = item
        
        uzWidth = 19
        uzHeight = 11
        x = 0
        y = 0

        def resizeLayoutLabel(label_item, max_width_mm):
            """
            Изменяет размер QgsLayoutItemLabel так, чтобы текст поместился полностью.
            Если текст короче max_width_mm, рамка сожмется под текст.
            Если длиннее — включится перенос строк.
            """
            # 1. Убираем внутренние отступы (главная причина обрезки текста)
            label_item.setMargin(0)
            
            # 2. Разрешаем перенос строк (режим HTML или обычный с автоматической высотой)
            # ModeHtml лучше обрабатывает сложные шрифты и переносы
            label_item.setMode(label_item.ModeHtml) 
            
            # 3. Задаем начальную ширину и огромную высоту "с запасом"
            # Это заставляет QGIS пересчитать перенос слов внутри этих границ
            label_item.attemptResize(QgsLayoutSize(max_width_mm, 1000, QgsUnitTypes.LayoutMillimeters))
            
            # 4. Выполняем автоматический подбор размера под контент
            label_item.adjustSizeToText()
            
            # 5. ХАК: Из-за особенностей рендеринга шрифтов (особенно Bold), 
            # добавляем микро-запас (1 мм), чтобы последняя буква точно не прилипала к краю
            current_size = label_item.sizeWithUnits()
            new_width = current_size.width() + (current_size.width() * 0.1)
            new_height = current_size.height() + 0.5
            
            # Финальная установка размера
            label_item.attemptResize(QgsLayoutSize(new_width, new_height, QgsUnitTypes.LayoutMillimeters))
            
            # Выравнивание текста сверху (чтобы не прыгал внутри рамки)
            label_item.setVAlign(Qt.AlignTop)

            label_item.setMode(label_item.ModeFont) 

        project = QgsProject.instance()
        layoutManager = project.layoutManager()
        legendLayoutName = 'МирГрадЪ - ДТП Условные обозначения2'
        layoutsList = layoutManager.printLayouts()
        for layout in layoutsList:
            if layout.name() == legendLayoutName:
                layoutManager.removeLayout(layout)
        legendLayout = QgsPrintLayout(project)
        legendLayout.initializeDefaults()
        legendLayout.setName(legendLayoutName)
        layoutManager.addLayout(legendLayout)
        #print(legendLayout.units())

        legendTitle = QgsLayoutItemLabel(legendLayout)
        legendTitle.setText('Условные обозначения'.upper())
        font = QFont(fontName, 18, QFont.Bold)
        legendTitle.setFont(font)

        legendLayout.addLayoutItem(legendTitle)
        legendTitle.attemptResize(QgsLayoutSize(1000, 1000, QgsUnitTypes.LayoutMillimeters))

        resizeLayoutLabel(legendTitle, 90)
        # 5. ХАК: Добавляем 5-10% к ширине вручную. 
        # Это "защитный интервал" для предотвращения обрезки последней буквы.
        current_width = legendTitle.sizeWithUnits().width()
        current_height = legendTitle.sizeWithUnits().height()
        # Добавляем 5 мм запаса к ширине
        legendTitle.attemptResize(QgsLayoutSize(current_width + 5, current_height, QgsUnitTypes.LayoutMillimeters))

        #print(legendTitle.sizeForText())
        legendTitle.attemptMove(QgsLayoutPoint(x, y, QgsUnitTypes.LayoutMillimeters))
        y += legendTitle.sizeWithUnits().height() + 1
        flagFZ = True
        flagRZ = True
        flagMZ = True
        for key, group in itemsList.items():
            if key[:2] == 'ФЗ' and flagFZ:
                groupNameTitleitem1 = QgsLayoutItemLabel(legendLayout)
                groupNameTitleitem1.setText('Объекты федерального значения'.upper())
                font = QFont(fontName, 14, QFont.Bold)
                groupNameTitleitem1.setFont(font)
                legendLayout.addLayoutItem(groupNameTitleitem1)
                resizeLayoutLabel(groupNameTitleitem1, 150)
                groupNameTitleitem1.attemptMove(QgsLayoutPoint(x, y, QgsUnitTypes.LayoutMillimeters))
                y += groupNameTitleitem1.sizeWithUnits().height() + 1
                flagFZ = False
            elif key[:2] == 'РЗ' and flagRZ:
                flagRZ = False
                groupNameTitleitem1 = QgsLayoutItemLabel(legendLayout)
                groupNameTitleitem1.setText('Объекты регионального значения'.upper())
                font = QFont(fontName, 14, QFont.Bold)
                groupNameTitleitem1.setFont(font)
                legendLayout.addLayoutItem(groupNameTitleitem1)
                resizeLayoutLabel(groupNameTitleitem1, 150)
                groupNameTitleitem1.attemptMove(QgsLayoutPoint(x, y, QgsUnitTypes.LayoutMillimeters))
                y += groupNameTitleitem1.sizeWithUnits().height() + 1
            elif key[:2] == 'МЗ' and flagMZ:
                #print('MЗ')
                flagMZ = False
                groupNameTitleitem1 = QgsLayoutItemLabel(legendLayout)
                groupNameTitleitem1.setText('Объекты местного значения'.upper())
                font = QFont(fontName, 14, QFont.Bold)
                groupNameTitleitem1.setFont(font)
                legendLayout.addLayoutItem(groupNameTitleitem1)
                resizeLayoutLabel(groupNameTitleitem1, 150)
                groupNameTitleitem1.attemptMove(QgsLayoutPoint(x, y, QgsUnitTypes.LayoutMillimeters))
                y += groupNameTitleitem1.sizeWithUnits().height() + 1
            groupNameTitleitem = QgsLayoutItemLabel(legendLayout)
            groupNameTitleitem.setText(group['text'].upper())
            font = QFont(fontName, 14, QFont.Bold)
            groupNameTitleitem.setFont(font)
            legendLayout.addLayoutItem(groupNameTitleitem)
            resizeLayoutLabel(groupNameTitleitem, 150)
            groupNameTitleitem.attemptMove(QgsLayoutPoint(x, y, QgsUnitTypes.LayoutMillimeters))
            y += groupNameTitleitem.sizeWithUnits().height() + 1
            for item in group['layers']:
                if item['statusLen'] < 1:
                    continue
                layerNameTitleitem = QgsLayoutItemLabel(legendLayout)
                layerNameTitleitem.setText(item['text'].upper())
                font = QFont(fontName, 14)
                layerNameTitleitem.setFont(font)
                legendLayout.addLayoutItem(layerNameTitleitem)
                resizeLayoutLabel(layerNameTitleitem, 290)
                layerNameTitleitem.attemptMove(QgsLayoutPoint(x, y, QgsUnitTypes.LayoutMillimeters))
                curSize = layerNameTitleitem.sizeWithUnits()
                if curSize.width() > 200:
                    futureSize = curSize#.clone()
                    curHeight = curSize.height()
                    numRows = (curSize.width() // 200) + 1
                    futureSize.setSize(200, curHeight * numRows)
                    layerNameTitleitem.attemptResize(futureSize)
                    layerNameTitleitem.setVAlign(Qt.AlignmentFlag.AlignVCenter)
                y += layerNameTitleitem.sizeWithUnits().height() + 1
                xLen = uzWidth + 5
                yPlus = 0
                if item['statusLen'] > 1:
                    statusList = ['сущ.', 'план.', 'реконстр.', 'ликвид.']
                    for xMult in range(item['statusLen']):
                        statusTitle = QgsLayoutItemLabel(legendLayout)
                        statusTitle.setText(statusList[xMult])
                        font = QFont(fontName, 12)
                        statusTitle.setFont(font)
                        legendLayout.addLayoutItem(statusTitle)
                        statusTitle.adjustSizeToText()
                        futureSize = statusTitle.sizeWithUnits()#.clone()
                        futureSize.setSize(uzWidth, futureSize.height())
                        statusTitle.attemptResize(futureSize)
                        statusTitle.setHAlign(Qt.AlignmentFlag.AlignHCenter)
                        
                        #statusTitle.adjustSizeToText()
                        statusTitle.attemptMove(QgsLayoutPoint(x + (xLen * xMult), y, QgsUnitTypes.LayoutMillimeters))
                        yPlus = statusTitle.sizeWithUnits().height()
                    y += yPlus + 1
                
                for rowItem in item['rows']:
                    rowTitleItem = QgsLayoutItemLabel(legendLayout)
                    rowTitleItem.setText(rowItem['text'].upper())
                    font = QFont(fontName, 12)
                    rowTitleItem.setFont(font)
                    legendLayout.addLayoutItem(rowTitleItem)
                    rowTitleItem.adjustSizeToText()
                    rowTitleItem.attemptMove(QgsLayoutPoint((xLen * item['statusLen']) + 5, y, QgsUnitTypes.LayoutMillimeters))
                    curSize = rowTitleItem.sizeWithUnits()
                    futureSize = curSize
                    curHeight = curSize.height()
                    numRows = 1
                    if curSize.width() > 145:
                        #.clone()
                        #test
                        numRows = curSize.width() // 145 + 1
                    if curHeight * numRows < uzHeight:
                        futureSize.setSize(145, uzHeight)
                    else:
                        futureSize.setSize(145, curHeight * numRows)
                    rowTitleItem.attemptResize(futureSize)
                    rowTitleItem.setVAlign(Qt.AlignmentFlag.AlignVCenter)
                        
                    y += rowTitleItem.sizeWithUnits().height() + 1
                    
                    #ySymb = y - ((rowTitleItem.sizeWithUnits().height() + 1)//2)
                    ySymb = rowTitleItem.positionAtReferencePoint(QgsLayoutItem.MiddleLeft).y()
                    for xMult in range(item['statusLen']):
                        rabSymbol = rowItem['symbols'][xMult]
                        if rabSymbol is None:
                            continue
                        elif rabSymbol.type() == 0:
                            symbolItem = QgsLayoutItemMarker(legendLayout)
                        elif rabSymbol.type() == 1:
                            polygon2 = QPolygonF()
                            polygon2.append(QPointF(0.0, uzHeight / 2))
                            polygon2.append(QPointF(uzWidth,uzHeight / 2))
                            symbolItem = QgsLayoutItemPolyline(polygon2, legendLayout)
                        elif rabSymbol.type() == 2:
                            polygon1 = QPolygonF()
                            polygon1.append(QPointF(0.0, 0.0))
                            polygon1.append(QPointF(uzWidth, 0.0))
                            polygon1.append(QPointF(uzWidth, uzHeight))
                            polygon1.append(QPointF(0.0, uzHeight))
                            symbolItem = QgsLayoutItemPolygon(polygon1, legendLayout)
                        symbolItem.setSymbol(rabSymbol.clone())
                        legendLayout.addLayoutItem(symbolItem)
                        symbolItem.setReferencePoint(QgsLayoutItem.Middle)
                        symbolItem.attemptMove(QgsLayoutPoint(x + (uzWidth / 2) + (xLen * xMult), ySymb, QgsUnitTypes.LayoutMillimeters))