# -*- coding: utf-8 -*-
"""
/***************************************************************************
 walidatorPlikowGML
                                 A QGIS plugin
 Walidacja i kontrola plików GML baz: BDOO, BDOT10k, PRNG, RCN, GESUT, EGiB, BDOT500, MGR, KARTO10k
 Generated by Plugin Builder: http://g-sherman.github.io/Qgis-Plugin-Builder/
                              -------------------
        begin                : 2022-12-23
        git sha              : $Format:%H$
        copyright            : (C) 2024 by Marcin Lebiecki - Główny Urząd Geodezji i Kartografii
        email                : marcin.lebiecki@gugik.gov.pl
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 ***************************************************************************/
"""
import os
import subprocess
import pathlib
import re
import time
import hashlib
import binascii
import logging
import gc
import tracemalloc
import itertools
import zipfile
import xml.etree.ElementTree as et


from collections import namedtuple, Counter
from datetime import datetime
from time import sleep


import pandas as pd
import matplotlib.pyplot
import lxml
import xlwt
import sip


from osgeo import ogr,gdal
from qgis.PyQt.QtCore import *
from qgis.PyQt.QtGui import *
from qgis.PyQt.QtWidgets import (
    QFileDialog, 
    QProgressBar, 
    QMessageBox, 
    QAction, 
    QLabel
)


from qgis.core import *
from qgis.gui import *
from qgis.utils import *


from openpyxl import Workbook
from openpyxl.styles import(
    Alignment, 
    Border, 
    Side, 
    Font, 
    PatternFill
)
from lxml.etree import (
    parse, 
    XMLSchema, 
    ElementTree
)

from .resources import *
from .utils import *
from .walidatorPlikowGML_EGIB import *


class walidatorPlikowGML(WalidatorEGIB):

    def __init__(self, iface):
        self.iface = iface
        self.plugin_dir = os.path.dirname(__file__)
        locale = QSettings().value('locale/userLocale')[0:2]
        locale_path = os.path.join(
            self.plugin_dir,
            'i18n','walidatorPlikowGML_{}.qm'.format(locale)
        )
        super().__init__()
        self.dlg = None
        self.filewidgets_initialized = False
        self.first_start = True
        self.modelKontroli = None
        self.plikiZparsowane = []
        self.slownikBledow = {}
        self.liczbaKontroliDoWykonania = 0
        self.liczbaKontroliWykonanych = 0
        self.kontrolaZWynikiemPozytywnym = 0
        self.listaBledow = {}
        self.idkontroli_LiczbaBledow = {}
        self.progress = QProgressBar()
        if os.path.exists(locale_path):
            self.translator = QTranslator()
            self.translator.load(locale_path)
            QCoreApplication.installTranslator(self.translator)
        self.actions = []
        self.menu = self.tr(u'&Walidator plików GML')
        self.first_start = None
        global mainPath, config, dlg, version, blokady, sciezkiPlikowZrodlowych
        os.environ['QT_AUTO_SCREEN_SCALE_FACTOR'] = '1'
        mainPath = (
            pathlib.Path(QgsApplication.qgisSettingsDirPath())
            /"python/plugins/Walidator_plikow_gml/"
        )
        ui_path = os.path.join(mainPath, 'walidatorPlikowGML_dialog_base.ui')
        config = configparser.ConfigParser()
        config.read(os.path.join(mainPath,'Walidator_plikow_gml.ini'))
        metadata_path = os.path.join(mainPath, 'metadata.txt')
        blokady = [
            0, 0, 0, 
            0, 0, 0,
            0, 0, 0, 
            0, 0
        ]
        sciezkiPlikowZrodlowych = []
        # Odczytanie wersji wtyczki z pliku metadata.txt
        version = ""
        if os.path.exists(metadata_path):
           with open(metadata_path, 'r') as metadata_file:
               for line in metadata_file:
                   if line.startswith('version='):
                       version = line.split('=')[1].strip()
                       break
        tree = et.parse(ui_path)
        root = tree.getroot()
        for widget in root.iter('widget'):
            if widget.get('name') == 'label_14':
                text_property = widget.find('property[@name="text"]')
                if text_property is not None:
                    text_property.find('string').text = version
                    
        # Zapisz zmodyfikowany plik
        tree.write(ui_path)
        
        
    def tr(self, message):
        return QCoreApplication.translate('walidatorPlikowGML', 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):
        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.iface.addToolBarIcon(action)
            
        if add_to_menu:
            self.iface.addPluginToMenu(
                self.menu,
                action)
        self.actions.append(action)
        return action


    def initGui(self):
        icon_path = ':/plugins/walidatorPlikowGML/icon.png'
        self.add_action(
            icon_path,
            text=self.tr(u'walidatorPlikowGML'),
            callback=self.run,
            parent=self.iface.mainWindow())
            
        self.first_start = True


    def unload(self):
        """Removes the plugin menu item and icon from QGIS GUI."""
        for action in self.actions:
        # spróbuj odpiąć wszystkie sygnały z action
            try:
                action.triggered.disconnect()
            except TypeError:
                pass

            try:
                self.iface.removePluginMenu(self.menu,action) 
            except Exception:
                pass

            try:
                self.iface.removeToolBarIcon(action)
            except Exception:
                pass
        self.actions.clear()
        if hasattr(self, "dlg") and self.dlg is not None:
            try:
                self.dlg.close()
            except Exception:
                pass
            try:
                self.dlg.deleteLater()
            except Exception:
                pass
            self.dlg = None
        try:
            self.iface.messageBar().clearWidgets()
        except Exception:
            pass
        
        global modelKontroli
        modelKontroli = None

        global warstwyZbledamiWalidacji
        warstwyZbledamiWalidacji = []

        global warstwyBledowKontroliAtrybutow
        warstwyBledowKontroliAtrybutow = []

        global warstwyZbledamiGeometrii
        warstwyZbledamiGeometrii = []

        global progress
        progress = None 


    def run(self):
        global walidowanaBaza
        walidowanaBaza = [
            'EGIB','GESUT','BDOT500',
            'RCN','PRNG','BDOT10k',
            'BDOO','MGR','KARTO10k'
        ]
        formatRaportu = [
            'xls', 'xlsx', 'pdf',
            'txt', 'shp', 'gpkg'
        ]
        if self.dlg is None:
            from .walidatorPlikowGML_dialog import walidatorPlikowGMLDialog
            self.dlg = walidatorPlikowGMLDialog()
            self.dlg.comboBox.addItems(walidowanaBaza)
            self.dlg.mComboBox.addItems(formatRaportu)
            self.dlg.mComboBox.setCheckedItems(['xls'])
            self.dlg.pushButton.clicked.connect(self.zaznaczKontroleNaPodstawieDanych)
            self.dlg.pushButton_1.clicked.connect(self.zaznaczWszystkieKontrole)
            self.dlg.pushButton_2.clicked.connect(self.odznaczWszystkieKontrole)
            self.dlg.comboBox.currentIndexChanged.connect(self.uzupelnienieWyboruXSD)
            self.dlg.comboBox_xsd.currentIndexChanged.connect(self.zmianaXSD)
            self.dlg.comboBox.currentIndexChanged.connect(self.szarzenieNieBDOT)
            self.dlg.pushButton.setEnabled(False)
            self.uzupelnienieWyboruXSD(0)
        self.walidacjaIKontrolaAtrybutow()
        
    def szarzenieNieBDOT(self):
         """Dezaktywacja przycisku gdy jest wybrana opcja inna niż BDOT10k"""
         wybranaBaza = self.dlg.comboBox.currentText()
         if wybranaBaza != 'BDOT10k':
             self.dlg.pushButton.setEnabled(False)
         else:
             self.dlg.pushButton.setEnabled(True)


    def wczytanieWersjiSzablonow(self, nazwaBazyDanych):
        self.dlg.comboBox_2.currentIndexChanged.disconnect()
        szablonPath = os.path.join(mainPath, 'SzablonyKontroli', nazwaBazyDanych)
        self.dlg.comboBox_2.clear()
        for file in sorted(os.listdir(szablonPath),reverse = True):
            if file.endswith('.xml'):
                wersjaSzablonuKontroli = et.parse(
                    os.path.join(szablonPath, file)
                ).getroot().get('version')
                self.dlg.comboBox_2.addItem(wersjaSzablonuKontroli)
        self.dlg.comboBox_2.setCurrentIndex(0)
        self.wczytanieSzablonuKontroli()
        self.dlg.comboBox_2.currentIndexChanged.connect(self.wczytanieSzablonuKontroli)
        self.kontrolaIstnieniaPlikowGranicDlaBDOT10k()


    def sciezkaDoWskazanegoSzablonuKontroli(self, wskazanaWersjaSzablonu, nazwaBazyDanych):
        szablonPath = os.path.join(mainPath, 'SzablonyKontroli', nazwaBazyDanych)
        for file in sorted(os.listdir(szablonPath), reverse = True):
            if file.endswith('.xml'):
                wersjaSzablonuKontroli = et.parse(
                    os.path.join(szablonPath, file)
                ).getroot().get('version')
                if wersjaSzablonuKontroli == wskazanaWersjaSzablonu:
                    return os.path.join(szablonPath, file)


    def uzupelnienieWyboruXSD(self, txt):
        global xsdPath
        nazwaBazyDanych = walidowanaBaza[txt]
        xsdPath_tmp = os.path.join(mainPath, 'XSD', nazwaBazyDanych)
        self.dlg.comboBox_xsd.clear()
        for file in sorted(os.listdir(xsdPath_tmp), reverse = True):
            if file.lower().endswith('.xsd'):
                self.dlg.comboBox_xsd.addItem(file)


    def zmianaXSD(self):
        global xsdPath, wersjaSchematu
        xsdPath_tmp = os.path.join(mainPath, 'XSD', self.dlg.comboBox.currentText())
        xsdPath = os.path.join(xsdPath_tmp, self.dlg.comboBox_xsd.currentText())
        filename = os.path.basename(xsdPath)
        if filename != '':
            tree = et.parse(xsdPath)
            root = tree.getroot()
            wersjaSchematu = root.get('version')


    def sprawdz_zip_i_wyodrebnij_zwiniete(self, lista_sciezek):
        """
        Sprawdza, czy którykolwiek plik .gml/.xml w ZIP zawiera zwinięte rekordy.
        Jeśli tak, pokazuje ostrzeżenie. Zwraca pierwszą wypakowaną ścieżkę do walidacji.
        """
        try:
            bledne_pliki = []
            for pelna_sciezka in lista_sciezek:
                if not self.sprawdz_dlugosc_linii(pelna_sciezka, tylko_sprawdzaj=True):
                    bledne_pliki.append(os.path.basename(pelna_sciezka))
                    
            if bledne_pliki:
                if len(bledne_pliki) == 1:
                    tekst = (
                        f"Znaleziono zwinięty rekord lub rekordy w następującym pliku:\n\n"
                        "{bledne_pliki[0]}"
                    )
                else:
                    tekst =( 
                        "Znaleziono zwinięte rekord lub rekordy w następujących plikach:\n\n" 
                        + "\n".join(bledne_pliki)
                    )
                tekst += (
                    "\n\nW przypadku błędu może zostać wskazany nieprawidłowy"
                    " numer wiersza w raporcie XLS.\n\nCzy chcesz kontynuować?"
                )
                try:
                    ret = QMessageBox.warning(
                        QMessageBox(), 
                        "Ostrzeżenie", 
                        tekst, 
                        QMessageBox.Ok | QMessageBox.Cancel
                        )
                    if ret != QMessageBox.Ok:
                        return False
                except Exception as e:
                    QMessageBox.critical(QMessageBox(), 'Błąd', 
                                         f'Błąd podczas wyświetlania komunikatu ostrzegawczego: {e}', 
                                         QMessageBox.Ok
                                         )
                    return False
                    
            return lista_sciezek[0]  # Pierwszy do walidacji
            
        except Exception as e:
            QMessageBox.critical(QMessageBox(), 
                                 'Uwaga!',
                                 f'Błąd rozpakowywania ZIP: {e}', 
                                 QMessageBox.Ok
                                 )
            return None


    def sprawdz_dlugosc_linii(self, input_path, tylko_sprawdzaj=False):
          if not input_path.lower().endswith(('.xml', '.gml')):
            return True
          try:
              licznik_zwinietych = 0
              try:
                  with open(input_path, 'r', encoding='utf-8') as f:
                      linie = f.readlines()
              except UnicodeDecodeError:
                  with open(input_path, 'r', encoding='windows-1250') as f:
                      linie = f.readlines()
              for linia in linie:
                  if '</gml:featureMember>' in linia and linia.count('><') >= 1:
                      licznik_zwinietych += 1
                      if licznik_zwinietych >= 1: # liczba_zbitek:
                          break
              if licznik_zwinietych >= 1: # liczba_zbitek:
                   if tylko_sprawdzaj:
                      return False
                   try:
                       ret = QMessageBox.warning(
                           QMessageBox(),
                           'Ostrzeżenie',
                           (
                               'Plik zawiera zwinięty przynajmniej jeden rekord!\n\n'
                               'W przypadku błędu może zostać wskazany nieprawidłowy numer wiersza w raporcie XLS.'
                               '\n\nCzy chcesz kontynuować?'
                           ),
                           QMessageBox.Ok | QMessageBox.Cancel
                       )
                       if ret != QMessageBox.Ok:
                           return False
                   except Exception as e:
                         QMessageBox.critical(
                             QMessageBox(), 
                             'Błąd', 
                             f'Błąd podczas wyświetlania komunikatu ostrzegawczego: {e}', 
                             QMessageBox.Ok
                         )
                         return False
              return True
          
          except Exception as e:
              QMessageBox.critical(
                  QMessageBox(), 
                  'Błąd', 
                  f'Błąd sprawdzania pliku: {e}',
                  QMessageBox.Ok
              )
          return False


    def wyborPliku(self, txt):
        global files, plikZIP, blokady, plikDoWeryfikacji, wypakowane_sciezki
        files = []
        wypakowane_sciezki = []
        plikDoWeryfikacji = None
        if os.path.isfile(txt):
            if self.dlg.mQgsFileWidget_dz.filePath() == self.dlg.mQgsFileWidget.filePath():
                QMessageBox.critical(
                    QMessageBox(),
                    'Uwaga!',
                    'Wybrano ten sam plik co w zakładce "Dane źródłowe".',
                    QMessageBox.Ok
                )
            self.dlg.button_box.buttons()[0].setEnabled(True)
            if zipfile.is_zipfile(txt):
                try:
                    plikZIP = zipfile.ZipFile(txt,'r')
                except:
                    self.iface.messageBar().pushMessage(
                        "Uwaga!", 
                        "Niepoprawny plik zip.", 
                        level = Qgis.Critical
                    )
                    return
                files = [
                    f for f in plikZIP.namelist() 
                    if (
                        f.endswith('.gml') 
                        or f.endswith('.xml') 
                        or f.endswith('.GML') 
                        or f.endswith('.XML')
                    )
                ]
                if files:
                    nazwaPlikuLubPlikow = ''.join(files)
            else:
                files.append(txt)
                nazwaPlikuLubPlikow = pathlib.Path(files[0]).name
            
            if not zipfile.is_zipfile(txt):
                plikDoWeryfikacji = open(txt, 'r', encoding='utf-8')
            else:
                try:
                    for f in files:
                        pelna_sciezka = plikZIP.extract(f, os.path.dirname(txt))
                        wypakowane_sciezki.append(pelna_sciezka) 
                        # przekazanie sciezek do kontroli zwiniecia
                    sciezka_rozpakowanego = wypakowane_sciezki[0]
                    plikDoWeryfikacji = open(sciezka_rozpakowanego, 'r', encoding='utf-8')
                except:
                    QMessageBox.critical(
                        QMessageBox(),
                        'Uwaga!',
                        'Brak uprawnień do zapisu w katalogu wskazanego pliku.', 
                         QMessageBox.Ok
                    )
            combo = self.dlg.comboBox
            for i in range(50):
                try:
                    line = plikDoWeryfikacji.readline().strip()
                except:
                    line = ''
                if 'BDOT10k_BDOO' in line:
                    combo.setCurrentIndex( combo.findText('BDOT10k'))
                    break
                elif '<ges2021:GES_' in line or '<ges:GES' in line:
                    combo.setCurrentIndex( combo.findText('GESUT'))
                    break
                elif 'MapaGlebowoRolnicza.xsd' in line:
                    combo.setCurrentIndex( combo.findText('MGR'))
                    break
                elif '<ok:OK' in line or 'urn:gugik:specyfikacje:gmlas:karto:1.0' in line:
                    combo.setCurrentIndex( combo.findText('KARTO10k'))
                    break
                elif '<ot2021:OT_' in line or '<ot:OT_' in line:
                    combo.setCurrentIndex( combo.findText('BDOT500'))
                    break
                else:
                    match = re.search(r"EGIB[-_]?1[._](\d+)[._]XSD", line.upper())
                    if match:
                        combo.setCurrentIndex( combo.findText('EGIB'))
                        n = int(match.group(1))
                        if 6 <= n <= 11:
                            self.dlg.comboBox_xsd.setCurrentIndex(
                                self.dlg.comboBox_xsd
                                .findText(f'EGIB_1.{n}.xsd')
                            )
            self.wczytanieWersjiSzablonow(self.dlg.comboBox.currentText())
            blokady[0] = 0
            if sum(blokady) == 0:
                self.dlg.button_box.buttons()[0].setEnabled(True)
            else:
                self.dlg.button_box.buttons()[0].setEnabled(False)
        else:
            blokady[0] = 1
            self.dlg.button_box.buttons()[0].setEnabled(False)


    def wyborPlikuPRNGmiejscowosci(self, txt):
        global sciezkiPlikowZrodlowych
        if os.path.isfile(txt):
            if self.dlg.mQgsFileWidget_prng_m.filePath() == self.dlg.mQgsFileWidget.filePath():
                QMessageBox.critical(
                    QMessageBox(),
                    'Uwaga!',
                    'Wybrano ten sam plik co w zakładce "Walidacja plików GML".', 
                    QMessageBox.Ok
                )
            if os.path.isfile(txt) and os.path.splitext(txt)[1].lower() == '.xml':
                 sciezkiPlikowZrodlowych.append(txt)
            blokady[6] = 0
        try:
              for i in range(modelKontroli.rowCount()):
                  item = modelKontroli.item(i)
                  if item.checkState() in (2,1):
                      for c in range(item.rowCount()):
                          if (
                              item.child(c).checkState() == 2 
                              and item.child(c).data(6)
                              .__contains__('prng_miejscowosci')
                          ):
                              if os.path.isfile(txt):
                                  if sum(blokady) == 0:
                                      self.dlg.button_box.buttons()[0].setEnabled(True)
                              else:
                                  self.dlg.button_box.buttons()[0].setEnabled(False)
        except Exception as e:
            print('Błąd w funkcji wyborPlikuPRNGmiejscowosci:', e)
        config.set('DEFAULT', 'prng_miejscowosci', txt)
        with open(str(mainPath) + '/Walidator_plikow_gml.ini', 'w') as configfile:
            config.write(configfile)


    def wyborPlikuPRNGobiektowfizjograficznych(self, txt):
        global sciezkiPlikowZrodlowych
        if os.path.isfile(txt):
            if self.dlg.mQgsFileWidget_prng_o.filePath() == self.dlg.mQgsFileWidget.filePath():
                QMessageBox.critical(
                    QMessageBox(), 
                    'Uwaga!', 
                    'Wybrano ten sam plik co w zakładce "Walidacja plików GML".', 
                    QMessageBox.Ok
                )
            if os.path.isfile(txt) and os.path.splitext(txt)[1].lower() == '.xml':
                 sciezkiPlikowZrodlowych.append(txt)
            blokady[7] = 0
        try:
              for i in range(modelKontroli.rowCount()):
                  item = modelKontroli.item(i)
                  if item.checkState() in (2,1):
                      for c in range(item.rowCount()):
                          if (
                              item.child(c).checkState() == 2 
                              and item.child(c).data(6)
                              .__contains__('prng_obiektyfizjograficzne')
                              ):
                              if os.path.isfile(txt):
                                  if sum(blokady) == 0:
                                      self.dlg.button_box.buttons()[0].setEnabled(True)
                              else:
                                  self.dlg.button_box.buttons()[0].setEnabled(False)
        except Exception as e:
            print('Błąd w funkcji wyborPlikuPRNGobiektowfizjograficznych:',e)
        config.set('DEFAULT', 'prng_obiektyfizjograficzne', txt)
        with open(str(mainPath)+'/Walidator_plikow_gml.ini', 'w') as configfile:
            config.write(configfile)


    def wyborPlikuTerenyChronione(self, txt):
        global sciezkiPlikowZrodlowych, plikZIPzrodlowy
        if os.path.isfile(txt):
            if self.dlg.mQgsFileWidget_tc.filePath() == self.dlg.mQgsFileWidget.filePath():
                QMessageBox.critical(
                    QMessageBox(),
                    'Uwaga!',
                    'Wybrano ten sam plik co w zakładce "Walidacja plików GML".', 
                    QMessageBox.Ok
                )
            if zipfile.is_zipfile(txt):
                    try:
                        plikZIPzrodlowy = zipfile.ZipFile(txt,'r')
                    except:
                        self.iface.messageBar().pushMessage(
                            "Uwaga!", 
                            "Niepoprawny plik zip.", 
                            level = Qgis.Critical
                        )
                        return
                    pliki = plikZIPzrodlowy.namelist()
                    for plik in pliki:
                        if os.path.splitext(plik)[1].lower() == '.shp':
                            sciezkiPlikowZrodlowych.append(plik)
            else:
                 if os.path.isfile(txt) and os.path.splitext(txt)[1].lower() == '.shp':
                  sciezkiPlikowZrodlowych.append(txt)
            blokady[9] = 0
        try:
              for i in range(modelKontroli.rowCount()):
                  item = modelKontroli.item(i)
                  if item.checkState() in (2, 1):
                      for c in range(item.rowCount()):
                          if (
                              item.child(c).checkState() == 2 
                              and item.child(c).data(6)
                              .__contains__('tereny_chronione')
                          ):
                              if os.path.isfile(txt):
                                  if sum(blokady) == 0:
                                      self.dlg.button_box.buttons()[0].setEnabled(True)
                              else:
                                  self.dlg.button_box.buttons()[0].setEnabled(False)
        except Exception as e:
            print('Błąd w funkcji wyborPlikuTerenyChronione:',e)
        config.set('DEFAULT', 'tereny_chronione', txt)
        with open(str(mainPath)+'/Walidator_plikow_gml.ini', 'w') as configfile:
            config.write(configfile)


    def wyborPlikuULIC(self, txt):
        global sciezkiPlikowZrodlowych
        if os.path.isfile(txt):
            if os.path.isfile(txt) and os.path.splitext(txt)[1].lower() == '.csv':
                  sciezkiPlikowZrodlowych.append(txt)
            blokady[8] = 0
        try:
             for i in range(modelKontroli.rowCount()):
                 item = modelKontroli.item(i)
                 if item.checkState() in (2,1):
                     for c in range(item.rowCount()):
                         if (
                             item.child(c).checkState() == 2 
                             and item.child(c).data(6)
                             .__contains__('ulic_gus')
                          ):
                             if os.path.isfile(txt):
                                 if sum(blokady) == 0:
                                     self.dlg.button_box.buttons()[0].setEnabled(True)
                             else:
                                 self.dlg.button_box.buttons()[0].setEnabled(False)
        except Exception as e:
             print('Błąd w funkcji wyborPlikuULIC:',e)
        config.set('DEFAULT', 'ulic_gus', txt)
        with open(str(mainPath)+'/Walidator_plikow_gml.ini', 'w') as configfile:
            config.write(configfile)


    def wyborPlikuSIMC(self, txt):
        global sciezkiPlikowZrodlowych
        if os.path.isfile(txt):
            if os.path.splitext(txt)[1].lower() == '.csv':
                if self.dlg.mQgsFileWidget_ulic.filePath() == txt:
                    QMessageBox.critical(
                        QMessageBox(), 
                        'Uwaga!', 
                        'Wybrano ten sam plik co w Dane ULIC.', 
                        QMessageBox.Ok
                    )
                else:
                    sciezkiPlikowZrodlowych.append(txt)
            blokady[10] = 0
        try:
             for i in range(modelKontroli.rowCount()):
                 item = modelKontroli.item(i)
                 if item.checkState() in (2,1):
                     for c in range(item.rowCount()):
                         if (
                             item.child(c).checkState() == 2 
                             and item.child(c).data(6)
                             .__contains__('simc_gus')
                          ):
                             if os.path.isfile(txt):
                                 if sum(blokady) == 0:
                                     self.dlg.button_box.buttons()[0].setEnabled(True)
                             else:
                                 self.dlg.button_box.buttons()[0].setEnabled(False)
        except Exception as e:
             print('Błąd w funkcji wyborPlikuSIMC:', e)
        config.set('DEFAULT', 'simc_gus', txt)
        with open(str(mainPath) + '/Walidator_plikow_gml.ini', 'w') as configfile:
            config.write(configfile)


    def wyborPlikuGranicPowiatow(self, txt):
        global sciezkiPlikowZrodlowych
        if os.path.isfile(txt):
            if self.dlg.mQgsFileWidget_gp.filePath() == self.dlg.mQgsFileWidget.filePath():
                QMessageBox.critical(
                    QMessageBox(),
                    'Uwaga!',
                    'Wybrano ten sam plik co w zakładce "Walidacja plików GML".',
                    QMessageBox.Ok
                )
            if os.path.isfile(txt) and os.path.splitext(txt)[1].lower() == '.gml':
                  sciezkiPlikowZrodlowych.append(txt)
            blokady[2] = 0
        try:
             for i in range(modelKontroli.rowCount()):
                 item = modelKontroli.item(i)
                 if item.checkState() in (2,1):
                     for c in range(item.rowCount()):
                         if (
                            item.child(c).checkState() == 2 
                             and any(
                                 keyword in item.data(6) 
                                 for keyword in ["Granice_powiatow", 
                                                 "czyObiektyWewnatrzPowiatu", 
                                                 "minimalna", 
                                                 "minDlugosc", 
                                                 "kontrolaZgodnosciZDanymiGDOS"
                                                ]
                                 )
                             ):
                             if os.path.isfile(txt):
                                 if sum(blokady) == 0:
                                     self.dlg.button_box.buttons()[0].setEnabled(True)
                             else:
                                 self.dlg.button_box.buttons()[0].setEnabled(False)
        except Exception as e:
             print('Błąd w funkcji wyborPlikuGranicPowiatow:',e)
        config.set('DEFAULT', 'granicePowiatow', txt)
        with open(str(mainPath)+'/Walidator_plikow_gml.ini', 'w') as configfile:
            config.write(configfile)
        self.kontrolaIstnieniaPlikowGranicDlaBDOT10k()


    def wyborPlikuGranicGmin(self, txt):
        config.set('DEFAULT', 'graniceGmin', txt)
        with open(str(mainPath)+'/Walidator_plikow_gml.ini', 'w') as configfile:
            config.write(configfile)
        self.kontrolaIstnieniaPlikowGranicDlaBDOT10k()


    def wyborPlikuGranicJednostekEwidencyjnych(self, txt):
        config.set('DEFAULT', 'graniceJednostekEwidencyjnych', txt)
        with open(str(mainPath)+'/Walidator_plikow_gml.ini', 'w') as configfile:
            config.write(configfile)
        self.kontrolaIstnieniaPlikowGranicDlaBDOT10k()


    def wyborPlikuZrodlowego(self, txt):
        global sciezkiPlikowZrodlowych, plikZIPzrodlowy
        if os.path.isfile(txt):
            if self.dlg.mQgsFileWidget_dz.filePath() == self.dlg.mQgsFileWidget.filePath():
                QMessageBox.critical(
                    QMessageBox(),
                    'Uwaga!',
                    'Wybrano ten sam plik co w zakładce "Walidacja plików GML".',
                    QMessageBox.Ok
                )
            if zipfile.is_zipfile(txt):
                try:
                    plikZIPzrodlowy = zipfile.ZipFile(txt,'r')
                except:
                    self.iface.messageBar().pushMessage(
                        "Uwaga!", 
                        "Niepoprawny plik zip.", 
                        level = Qgis.Critical
                    )
                    return
                pliki = plikZIPzrodlowy.namelist()
                for plik in pliki:
                    if os.path.splitext(plik)[1].lower() in ['.xml','.gml']:
                        sciezkiPlikowZrodlowych.append(plik)
            else:
                if os.path.isfile(txt) and os.path.splitext(txt)[1].lower() in ['.xml','.gml']:
                    sciezkiPlikowZrodlowych.append(txt)
            blokady[5] = 0
        try:
            for i in range(modelKontroli.rowCount()):
                item = modelKontroli.item(i)
                if item.checkState() in (2,1):
                    for c in range(item.rowCount()):
                        if (
                            item.child(c).checkState() == 2 
                            and item.child(c).data(6)
                            .__contains__('(gml,gml)')
                         ):
                            if os.path.isfile(txt):
                                if sum(blokady) == 0:
                                    self.dlg.button_box.buttons()[0].setEnabled(True)
                            else:
                                self.dlg.button_box.buttons()[0].setEnabled(False)
        except Exception as e:
             print('Błąd w funkcji wyborPlikuZrodlowego:',e)


    def kontrolaIstnieniaPlikowGranicDlaBDOT10k(self):
        if self.dlg.comboBox.currentText() == 'BDOT10k':
            granicePowiatow = config['DEFAULT']['granicePowiatow']
            graniceGmin = config['DEFAULT']['graniceGmin']
            graniceJednostekEwidencyjnych = config['DEFAULT']['graniceJednostekEwidencyjnych']
            
            if granicePowiatow == "":
                for i in range(modelKontroli.rowCount()):
                    item = modelKontroli.item(i)
                    if item.checkState() in (1,2):
                        for child in range(item.rowCount()):
                            if (item.child(child).checkState() == 2 
                                and (item.child(child).data(6)
                                     .__contains__("czyObiektyWewnatrzPowiatu") 
                                     or item.child(child).data(6)
                                     .__contains__("Granice_powiatow") 
                                     or item.child(child).data(6)
                                     .__contains__("minimalna") 
                                     or item.child(child).data(6)
                                     .__contains__("minDlugosc") 
                                     or item.child(child).data(6)
                                     .__contains__("fullCoverage") 
                                     or item.child(child).data(6)
                                     .__contains__("kontrolaZgodnosciZDanymiGDOS"))
                                ):
                                blokady[2] = 1
                                self.dlg.button_box.buttons()[0].setEnabled(False)
                                return
                            else:
                                blokady[2] = 0
            if graniceGmin == "":
                for i in range(modelKontroli.rowCount()):
                    item = modelKontroli.item(i)
                    if item.checkState() in (1,2):
                        for child in range(item.rowCount()):
                            if (
                                item.child(child).checkState() == 2 
                                and item.child(child).data(6)
                                .__contains__("Granice_gmin")
                             ):
                                blokady[3] = 1
                                self.dlg.button_box.buttons()[0].setEnabled(False)
                                return
                            else:
                                blokady[3] = 0
            if graniceJednostekEwidencyjnych == "":
                for i in range(modelKontroli.rowCount()):
                    item = modelKontroli.item(i)
                    if item.checkState() in (1, 2):
                        for child in range(item.rowCount()):
                            if (
                                item.child(child).checkState() == 2 
                                and item.child(child).data(6)
                                .__contains__("Granice_jednostek_ewidencyjnych")
                             ):
                                blokady[4] = 1
                                self.dlg.button_box.buttons()[0].setEnabled(False)
                                return
                            else:
                                blokady[4] = 0
            
            if self.dlg.mQgsFileWidget.filePath() != '':
                self.dlg.button_box.buttons()[0].setEnabled(True)


    # wskazanie pliku i zlecenie walidacji
    def walidacjaIKontrolaAtrybutow(self):
        global pliki, sciezkaGML, files, plik, path, plikRaportu, walidacjaZWynikiemPozytywnym
        global kontrolaZWynikiemPozytywnym, xmlschema, formatPlikuRaportu, dataFrame
        global walidowanePliki_df, wiersze_df, opisyBledow_df, komunikatyBledow_df
        global gmlid_df_w, grupyKontroli_df, kontrolowanePliki_df, klasy_df, gmlid_df_k
        global komunikatyBledowKontroli_df, plikiZparsowane, slownikBledow
        global warstwyBledowKontroliAtrybutow, warstwyBledowWalidacji, sumaKontrolaPlikWalidowany
        global progress, liczbaKontroliWykonanych, nazwy, unikalny_id, nazwa_pliku
        global timestr, version, idkontroli_LiczbaBledow, idkontroli
        global granicePowiatow, graniceGmin, graniceJednostekEwidencyjnych
        global kontroleWykonaniePojedyncze, plikZIP, pathSHP, pathGPKG
        global ulic_gus, simc_gus, prng_obiektyfizjograficzne, prng_miejscowosci, tereny_chronione
        
        sciezkaGML_ini = config['DEFAULT']['sciezkagml']
        granicePowiatow = config['DEFAULT']['granicePowiatow']
        graniceGmin = config['DEFAULT']['graniceGmin']
        graniceJednostekEwidencyjnych = config['DEFAULT']['graniceJednostekEwidencyjnych']
        ulic_gus = config['DEFAULT']['ulic_gus']
        simc_gus = config['DEFAULT']['simc_gus']
        prng_miejscowosci  = config['DEFAULT']['prng_miejscowosci']
        prng_obiektyfizjograficzne  = config['DEFAULT']['prng_obiektyfizjograficzne']
        tereny_chronione = config['DEFAULT']['tereny_chronione']
        kontroleWykonaniePojedyncze = {"topo_e3_k6":False,"topo_e5_k1":False}
        
        self.dlg.mQgsFileWidget.setFilter("Plik GML (*.gml);;Plik XML (*.xml);;Plik skompresowany (*.zip)")
        self.dlg.mQgsFileWidget_gp.setFilter("Plik GML (*.gml)")
        self.dlg.mQgsFileWidget_gg.setFilter("Plik GML (*.gml)")
        self.dlg.mQgsFileWidget_gje.setFilter("Plik GML (*.gml)")
        self.dlg.mQgsFileWidget_dz.setFilter("Plik skompresowany (*.zip);;Plik GML (*.gml);;Plik XML (*.xml)")
        self.dlg.mQgsFileWidget_prng_m.setFilter("Plik XML (*.xml)")
        self.dlg.mQgsFileWidget_prng_o.setFilter("Plik XML (*.xml)")
        self.dlg.mQgsFileWidget_tc.setFilter("Plik ZIP (*.zip)")
        self.dlg.mQgsFileWidget_ulic.setFilter("Plik CSV (*.csv)")
        self.dlg.mQgsFileWidget_simc.setFilter("Plik CSV (*.csv)")
        self.dlg.mQgsFileWidget_gp.setFilePath(granicePowiatow)
        self.dlg.mQgsFileWidget_gg.setFilePath(graniceGmin)
        self.dlg.mQgsFileWidget_gje.setFilePath(graniceJednostekEwidencyjnych)
        self.dlg.mQgsFileWidget_prng_m.setFilePath(prng_miejscowosci)
        self.dlg.mQgsFileWidget_prng_o.setFilePath(prng_obiektyfizjograficzne)
        self.dlg.mQgsFileWidget_ulic.setFilePath(ulic_gus)
        self.dlg.mQgsFileWidget_simc.setFilePath(simc_gus)
        self.dlg.mQgsFileWidget_tc.setFilePath(tereny_chronione)
        self.dlg.mQgsFileWidget.setDialogTitle("Wskaż plik z danymi do walidacji")
        self.dlg.mQgsFileWidget_gp.setDialogTitle("Wskaż plik z granicami powiatów")
        self.dlg.mQgsFileWidget_gg.setDialogTitle("Wskaż plik z granicami gmin")
        self.dlg.mQgsFileWidget_gje.setDialogTitle("Wskaż plik z granicami jednostek ewidencyjnych")
        self.dlg.mQgsFileWidget_dz.setDialogTitle("Wskaż plik z danymi źródłowymi")
        self.dlg.mQgsFileWidget_prng_m.setDialogTitle("Wskaż plik z PRNG miejscowości")
        self.dlg.mQgsFileWidget_prng_o.setDialogTitle("Wskaż plik z PRNG obiektów fizjograficznych")
        self.dlg.mQgsFileWidget_ulic.setDialogTitle("Wskaż plik z TERYT ULIC")
        self.dlg.mQgsFileWidget_simc.setDialogTitle("Wskaż plik z TERYT SIMC")
        self.dlg.mQgsFileWidget_tc.setDialogTitle("Wskaż plik ZIP z danymi SHP w zakresie terenów chronionych")
        self.dlg.mQgsFileWidget.setDefaultRoot(sciezkaGML_ini)
        if not self.filewidgets_initialized:
            self.dlg.mQgsFileWidget.fileChanged.connect(self.wyborPliku)
            self.dlg.mQgsFileWidget_gp.fileChanged.connect(self.wyborPlikuGranicPowiatow)
            self.dlg.mQgsFileWidget_gg.fileChanged.connect(self.wyborPlikuGranicGmin)
            self.dlg.mQgsFileWidget_gje.fileChanged.connect(self.wyborPlikuGranicJednostekEwidencyjnych)
            self.dlg.mQgsFileWidget_dz.fileChanged.connect(self.wyborPlikuZrodlowego)
            self.dlg.mQgsFileWidget_prng_m.fileChanged.connect(self.wyborPlikuPRNGmiejscowosci)
            self.dlg.mQgsFileWidget_prng_o.fileChanged.connect(self.wyborPlikuPRNGobiektowfizjograficznych)
            self.dlg.mQgsFileWidget_ulic.fileChanged.connect(self.wyborPlikuULIC)
            self.dlg.mQgsFileWidget_simc.fileChanged.connect(self.wyborPlikuSIMC)
            self.dlg.mQgsFileWidget_tc.fileChanged.connect(self.wyborPlikuTerenyChronione)
        
            self.dlg.comboBox.currentIndexChanged.connect(lambda: self.wczytanieWersjiSzablonow(self.dlg.comboBox.currentText()))
            self.dlg.comboBox_2.currentIndexChanged.connect(self.wczytanieSzablonuKontroli)
            self.dlg.mComboBox.checkedItemsChanged.connect(self.kontrolaWybranychFormatowRaportow)
            self.filewidgets_initialized = True
        
        result = self.dlg.exec()
        if not result:
            return
        # Sprawdzenie, czy plik nie zawiera długiej linii lub zwiniętych znaczników
        sciezka_wejsciowa = self.dlg.mQgsFileWidget.filePath()
        plik = [sciezka_wejsciowa, self.dlg.mQgsFileWidget.filter()]
        sciezkaGML = str(pathlib.Path(plik[0]).parent)
        
        if zipfile.is_zipfile(sciezka_wejsciowa):
            sciezka_do_walidacji = self.sprawdz_zip_i_wyodrebnij_zwiniete(wypakowane_sciezki)
        else:
            sciezka_do_walidacji = (
                sciezka_wejsciowa 
                if self.sprawdz_dlugosc_linii(sciezka_wejsciowa) 
                else None
                )
            
        if not sciezka_do_walidacji:
            return  # Błąd lub brak GML/XML
        
        if sciezkaGML == '.':
            QMessageBox.critical(
                QMessageBox(), 
                'Uwaga!', 
                'Nie wskazano pliku.', 
                QMessageBox.Ok
            )
            return
            
        try:
            if not os.access(sciezkaGML, os.W_OK):
                self.iface.messageBar().pushMessage(
                    "Uwaga!", 
                    "Brak uprawnień do zapisu raportu.", 
                    level=Qgis.Critical
                )
                return
            nazwa_pliku = pathlib.Path(plik[0]).name[:-4]
            if sciezkaGML != sciezkaGML_ini:
                config.set('DEFAULT', 'sciezkagml', sciezkaGML)
                with open(str(mainPath)+'/Walidator_plikow_gml.ini', 'w') as configfile:
                    config.write(configfile)
        except Exception as inst:
            if inst.args[0] == 13:
                self.iface.messageBar().pushMessage(
                    "Uwaga!", 
                    inst.args[1], 
                    level=Qgis.Critical
                )
            else:
                print(f"bład w funkcji walidacjaIKontrolaAtrybutow: {inst}")
            return
        
        crc = 0
        with open(str(pathlib.Path(plik[0])), 'rb') as f:
              while True:
                  data = f.read(65536)
                  if not data:
                      break
                  crc = binascii.crc32(data, crc)
        sumaKontrolaPlikWalidowany = "%08X" % (crc & 0xFFFFFFFF)
        
        sumaKontrolnaDaneZrodlowe = 'nie dotyczy' # domyslna definicja zmiennej
        dane_zrodlowe = self.dlg.mQgsFileWidget_dz.filePath()
        if dane_zrodlowe != '':
            plikZrodlowy = [dane_zrodlowe, self.dlg.mQgsFileWidget_dz.filter()]
            with open(str(pathlib.Path(plikZrodlowy[0])), 'rb') as f:
              while True:
                  data = f.read(65536)
                  if not data:
                      break
                  crc = binascii.crc32(data, crc)
            sumaKontrolnaDaneZrodlowe = "%08X" % (crc & 0xFFFFFFFF)
        
        if result and self.dlg.mComboBox.currentText() != '':
            nazwa = f"Walidacja pliku {str(pathlib.Path(plik[0]).name)} rozpoczęta ..."
            self.iface.messageBar().pushMessage(nazwa, level=Qgis.Info)
            
            timestr = time.strftime("%Y-%m-%d_%H.%M")
            base = f"RaportBledow_{nazwa_pliku}_{timestr}"
            pathPDF = os.path.join(sciezkaGML, f"{base}.pdf")
            pathXLS = os.path.join(sciezkaGML, f"{base}.xls")
            pathXLSX = os.path.join(sciezkaGML, f"{base}.xlsx")
            pathTXT = os.path.join(sciezkaGML, f"{base}.txt")
            # pathPDF = sciezkaGML + "/RaportBledow_" + str(nazwa_pliku) + "_" + timestr + ".pdf"
            # pathXLS = sciezkaGML + "/RaportBledow_" + str(nazwa_pliku) + "_" + timestr + ".xls"
            # pathXLSX = sciezkaGML + "/RaportBledow_" + str(nazwa_pliku) + "_" + timestr + ".xlsx"
            # pathTXT = sciezkaGML + "/RaportBledow_" + str(nazwa_pliku) + "_" + timestr + ".txt"
        else:
            return
        
        pliki = []
        plikiZparsowane = []
        walidowanePliki_df = []
        wiersze_df = []
        opisyBledow_df = []
        komunikatyBledow_df = []
        unikalny_id = set()
        kontrolowanePliki_df = []
        klasy_df = []
        gmlid_df_w = []
        gmlid_df_k = []
        komunikatyBledowKontroli_df = []
        grupyKontroli_df = []
        slownikBledow = {}
        slownikWalidacji = {}
        idkontroli_LiczbaBledow = {}
        if self.dlg.comboBox.currentText() == 'EGIB': # przenoszenie zmiennych do EGiB
            self.komunikatyBledowKontroli_df = komunikatyBledowKontroli_df
            self.kontrolowanePliki_df = kontrolowanePliki_df
            self.klasy_df = klasy_df
            self.gmlid_df_w = gmlid_df_w
            self.gmlid_df_k = gmlid_df_k
            self.grupyKontroli_df = grupyKontroli_df
            self.idkontroli_LiczbaBledow = idkontroli_LiczbaBledow
        kontrole_doInterpretacji = ['topo_e1_k2_8_1', 'topo_e1_k20', 
                                    'topo_e1_k23', 'topo_e1_k123_7', 
                                    'topo_e1_k123_8', 'topo_e1_k123_9', 
                                    'topo_e1_k123_10', 'topo_e3_k7_1',
                                     'topo_e3_k5', 'topo_e3_k159', 
                                     'topo_e3_k175', 'topo_e3_k176', 
                                     'topo_e3_k177', 'topo_e3_k178', 
                                     'topo_e3_k179', 'topo_e3_k180', 
                                      'topo_e3_k181', 'topo_e3_k182', 
                                      'topo_e3_k183', 'topo_e4_k25', 
                                      'topo_e4_k27', 'topo_e5_k4'
                                    ]
        slownik_liczba_bledow = {}
        slownik_grupa = {}
        i = 0
        walidacjaZWynikiemPozytywnym = True
        kontrolaZWynikiemPozytywnym = True
        namespace = self.dlg.comboBox.currentText()
        try:
            with open(xsdPath, 'rb') as schema_file:
                schema_root = etree.XML(schema_file.read())
                xmlschema = XMLSchema(schema_root)
        except Exception as a:
            print(a)
            self.iface.messageBar().pushMessage(
                "Uwaga!",
                ("Występuje problem z pobraniem schematu ze strony http://schemas.opengis.net."
                "Proszę sprawdzić czy jest dostępu do internetu."), 
                level = Qgis.Critical)
            return
        
        for file in files:
            if '.zip' in str(plik[0]):
                try:
                    plikGML = plikZIP.extract(file, sciezkaGML)
                except:
                    self.iface.messageBar().pushMessage(
                        "Uwaga!", 
                        "Problem z rozpakowaniem pliku zip.", 
                        level = Qgis.Critical
                    )
                    return
            else:
                plikGML = file
            if plikGML[-3:] in ['xml','gml','XML','GML'] and not plikGML.__contains__("Uzytkownik"):
                pliki.append(plikGML)
                if self.dlg.comboBox.currentText() != 'EGIB':
                    loop = QEventLoop()
                    def on_finished_wrapper(*args, **kwargs):
                        try:
                            # Przekazujemy wszystko dokładnie tak,
                            # jak QGIS woła oryginalne on_finished:
                                self.wynikiWalidacji(*args, **kwargs)
                        finally:
                            # Niezależnie od tego, czy wynikiWalidacji rzuci wyjątek,
                            # pętla i tak się zakończy.
                            loop.quit()
                    task = QgsTask.fromFunction(
                        str(i), 
                        self.walidacja, 
                        on_finished=on_finished_wrapper, 
                        flags = QgsTask.CanCancel
                    )
                    QgsApplication.taskManager().addTask(task)
                    loop.exec()
                else:
                   exception = None
                   result = None
                   class _FakeTask:
                       def __init__(self, desc):
                           self._desc = str(desc)
                       def description(self):
                          return self._desc

                   fake_task = _FakeTask(i)
                   try:
                       # jeśli twoja walidacja normalnie przyjmuje (task),
                       # to tu możesz spokojnie przekazać None:
                           result = self.walidacja(fake_task)
                   except Exception as e:
                       exception = e

                # wywołujemy tę samą funkcję, która normalnie jest on_finished
                   self.wynikiWalidacji(exception, result)
                i += 1
        
        if not walidacjaZWynikiemPozytywnym:
            msgBox = QMessageBox()
            msgBox.setText(
                "W pliku gml występują błędy zgodności ze schematem aplikacyjnym"
                " i dlatego dalsze kontrole atrybutowe i geometryczne"
                " mogą się nie wykonać poprawnie - czy chcesz  kontynuować?"
            )
            msgBox.setStandardButtons(QMessageBox.Yes | QMessageBox.No)
            odp = msgBox.exec()
            nazwy = ''
        else:
            odp = 0
        
        liczbaKontroliDoWykonania = 0
        liczbaKontroliWykonanych = 0
        nazwy = []
        epsg = 'epsg:2180'
        
        QgsMessageLog.logMessage(
            f'--------- Kontrole atrybutów dla pliku:{str(pathlib.Path(plik[0]).name)}---------', 
            tag="Walidator plików GML", 
            level=Qgis.Info
            )
        
        # sprawdzenie liczby kontroli do wykonania
        for i in range(modelKontroli.rowCount()):
            parent = modelKontroli.item(i)
            if parent.checkState() in (1,2):
                for j in range(parent.rowCount()):
                    if parent.child(j).checkState() == 2:
                        if parent.child(j).data(3) == "OT":
                            liczbaKontroliDoWykonania += 69 # bez klas RT
                        else:
                            liczbaKontroliDoWykonania += 1
                        nazwy.append((parent.child(j).data(1),parent.child(j).data(2)))
        
        if not walidacjaZWynikiemPozytywnym or liczbaKontroliDoWykonania > 0:
            mainGroup = os.path.splitext(os.path.basename(plik[0]))[0]
            root = QgsProject.instance().layerTreeRoot()
            groupaGlowna = next(
                (group 
                 for group in root.children() 
                 if group.name() == mainGroup), 
                None,
            )
            if groupaGlowna:
               # Jeśli grupa istnieje, sprawdzamy czy jest usunięta, jeśli tak - tworzymy nową
                   root.removeChildNode(groupaGlowna)
            groupaGlowna = root.addGroup(mainGroup)
            self.groupaGlowna = groupaGlowna
            if self.dlg.comboBox.currentText() == 'EGIB':
                self.groupaGlowna = groupaGlowna
            for plikZparsowany in plikiZparsowane:
                self.importGML(plikZparsowany)
        
        warstwyBledowKontroliAtrybutow = {
            'Point': QgsVectorLayer(f"Point?crs={epsg}", "błędy z kontroli atrybutów", "memory"),
            'LineString': QgsVectorLayer(f"LineString?crs={epsg}", "błędy z kontroli atrybutów", "memory"),
            'Polygon': QgsVectorLayer(f"Polygon?crs={epsg}", "błędy z kontroli atrybutów", "memory")
        }
        warstwyBledowWalidacji = {
            'Point': QgsVectorLayer(f"Point?crs={epsg}", "błędy z walidacji", "memory"),
            'LineString': QgsVectorLayer(f"LineString?crs={epsg}", "błędy z walidacji", "memory"),
            'Polygon': QgsVectorLayer(f"Polygon?crs={epsg}", "błędy z walidacji", "memory")
        }
        for layer in warstwyBledowKontroliAtrybutow.values():
            provider = layer.dataProvider()
            provider.addAttributes([
                QgsField('gml_id', QVariant.String),
                QgsField('nazwaKlasy', QVariant.String),
                QgsField('trescBledu', QVariant.String)
                ])
            layer.updateFields()
        for layer in warstwyBledowWalidacji.values():
            provider = layer.dataProvider()
            provider.addAttributes([
                QgsField('walidowanyPlik', QVariant.String),
                QgsField('wiersz', QVariant.String),
                QgsField('opisBledu', QVariant.String),
                QgsField('komunikatBledu', QVariant.String)
                ])
            layer.updateFields()
        
        if odp == 16384 or odp == 0:
            progress = QProgressBar()
            
            progressMessageBar = iface.messageBar().createMessage(
                "Postęp wykonania kontroli dodatkowych"
            )
            progress.setMaximum(liczbaKontroliDoWykonania)
            progress.setAlignment(Qt.AlignLeft|Qt.AlignVCenter)
            progressMessageBar.layout().addWidget(progress)
            iface.messageBar().pushWidget(progressMessageBar, Qgis.Info)
            self.kontrolaAtrybutow()
            
            if liczbaKontroliWykonanych != liczbaKontroliDoWykonania:
                progress.setValue(progress.maximum())
            iface.messageBar().clearWidgets()
            # statystyki
            listaBledow = {k: v for k, v in idkontroli_LiczbaBledow.items() if v > 0}
            if self.dlg.comboBox.currentText() == 'EGIB':
                self.listaBledow = listaBledow
            grupy = {}
            grupa_map = {}
            for i in range(modelKontroli.rowCount()):
                item = modelKontroli.item(i)
                grupa_nazwa = item.data(2)
                if item.rowCount() > 0:
                    for j in range(item.rowCount()):
                        child = item.child(j)
                        kontrola_id = child.data(1)
                        kontrola_name = child.data(2)
                        fraza = kontrola_id.split('_')[1][:2]
                        klucz_grupy = '_'.join(kontrola_id.split('_')[:2])
                        if fraza not in grupa_map:
                            grupa_map[fraza] = grupa_nazwa
                        if kontrola_id in idkontroli_LiczbaBledow:
                           wartosc = idkontroli_LiczbaBledow[kontrola_id]
                           if wartosc > 0:
                               slownik_liczba_bledow[kontrola_id] = (wartosc, 
                                                                     kontrola_name
                                                                     )
            for klucz, wartosc in idkontroli_LiczbaBledow.items():
                fraza = klucz.split('_')[1][:2]
                klucz_grupy = '_'.join(klucz.split('_')[:2])
                if klucz_grupy in grupy:
                    grupy[klucz_grupy] += wartosc
                else:
                    grupy[klucz_grupy] = wartosc
            for klucz, suma in grupy.items():
                nazwa_grupy = grupa_map.get(klucz.split('_')[1][:2], "Brak nazwy")
                if suma > 0:
                    slownik_grupa[klucz] = (suma, nazwa_grupy)
            slownik_liczba_bledow = dict(sorted(slownik_liczba_bledow.items()))
            slownik_grupa = dict(sorted(slownik_grupa.items()))
            
        if not walidacjaZWynikiemPozytywnym:
            # Ustawienia paska postępu
            progressWalidacjaWyniki = QProgressBar()
            progressWalidacjaWynikiMessageBar = iface.messageBar().createMessage(
                "Postęp generowania warstw z błędami walidacji"
            )
            progressWalidacjaWyniki.setMaximum(len(groupaGlowna.findLayers()))
            progressWalidacjaWyniki.setAlignment(Qt.AlignLeft|Qt.AlignVCenter)
            progressWalidacjaWynikiMessageBar.layout().addWidget(progressWalidacjaWyniki)
            iface.messageBar().pushWidget(progressWalidacjaWynikiMessageBar, Qgis.Info)
            
            expression = '"gml_id" IN ({})'.format(",".join(f"'{gml_id}'" for gml_id in gmlid_df_w))
            request = QgsFeatureRequest().setFilterExpression(expression)
            warstwyZbledamiWalidacji = []
            for index, lyr in enumerate(groupaGlowna.findLayers()):
                lyr = lyr.layer()
                geometry_type = QgsWkbTypes.displayString(lyr.wkbType())
                new_features = [feature for feature in lyr.getFeatures(request)]
                if len(new_features) > 0:
                    new_layer = QgsVectorLayer(f"{geometry_type}?crs={lyr.crs().authid()}", 
                                               f"{lyr.name()} błędy z walidacji",
                                               "memory"
                                )
                    new_layer_data_provider = new_layer.dataProvider()
                    new_layer_data_provider.addAttributes(
                        [QgsField("gml_id", QVariant.String),
                         QgsField("wiersz", QVariant.String),
                         QgsField("opisBledu", QVariant.String),
                         QgsField("komunikatBledu", QVariant.String)]
                    )
                    new_layer.updateFields()
                    for feature in new_features:
                        new_feature = QgsFeature(feature)
                        new_feature.setFields(new_layer.fields())
                        gmlid_df_w_idx = gmlid_df_w.index(feature['gml_id'])
                        new_feature.setAttribute(0, QVariant(feature['gml_id']))
                        new_feature.setAttribute(1, QVariant(wiersze_df[gmlid_df_w_idx]))
                        new_feature.setAttribute(2, QVariant(opisyBledow_df[gmlid_df_w_idx]))
                        new_feature.setAttribute(3, QVariant(komunikatyBledow_df[gmlid_df_w_idx]))
                        new_layer_data_provider.addFeature(new_feature)
                    
                    QgsProject.instance().addMapLayer(new_layer)
                    warstwyZbledamiWalidacji.append(new_layer)
                progressWalidacjaWyniki.setValue(index)
            progressWalidacjaWyniki.reset()
        kontrolaZWynikiemPozytywnym = True
        if listaBledow:
             for kontrola_id in listaBledow:
                 if kontrola_id not in kontrole_doInterpretacji:
                     kontrolaZWynikiemPozytywnym = False
                     break
        else:
            kontrolaZWynikiemPozytywnym = True
        if self.dlg.comboBox.currentText() == 'EGIB':
            self.kontrolaZWynikiemPozytywnym = kontrolaZWynikiemPozytywnym
                 
        if walidacjaZWynikiemPozytywnym and kontrolaZWynikiemPozytywnym:
            widget = iface.messageBar().createMessage(
                f"Walidacja pliku {str(pathlib.Path(plik[0]).name)} "
                "zakończona z wynikiem pozytywnym."
            )
            button = QPushButton(widget)
            button.setText("Pozytywny raport z kontroli / walidacji")
            button.pressed.connect(self.otwarcieRaportuZWalidacji)
            widget.layout().addWidget(button)
            self.iface.messageBar().pushWidget(widget,Qgis.Success)
        else:
            if walidacjaZWynikiemPozytywnym == False and kontrolaZWynikiemPozytywnym == False:
                msg = "Walidacja i kontrola atrybutów zakończona z wynikiem negatywnym: "
            elif walidacjaZWynikiemPozytywnym == False:
                msg = "Walidacja pliku zakończona z wynikiem negatywnym: "
            else:
                msg = "Kontrola atrybutów zakończona z wynikiem negatywnym: "
            widget = iface.messageBar().createMessage(msg, str(pathlib.Path(plik[0]).name))
            
            button = QPushButton(widget)
            button.setText("Raporty z kontroli / walidacji")
            button.pressed.connect(self.otwarcieRaportuZWalidacji)
            widget.layout().addWidget(button)
            self.iface.messageBar().pushWidget(widget, Qgis.Warning)
            
        if 'txt' in self.dlg.mComboBox.checkedItems(): 
           try:
               plikRaportu = open(pathTXT, "w")
               if len(walidowanePliki_df) > 0:
                   for i in range(len(walidowanePliki_df)):
                       plikRaportu.write(f'Walidacja pliku: {walidowanePliki_df[i]} z wynikiem negatywnym.\n')
                       plikRaportu.write(f'- {opisyBledow_df[i]}\n')
                       plikRaportu.write (f'- wiersz: {wiersze_df[i]}\n')
                       plikRaportu.write(f'- komunikat błędu: {komunikatyBledow_df[i]}\n')
               else:
                   plikRaportu.write('------------------------------------------------Brak błędów walidacji-----------------------------------------------------\n')
               if len(kontrolowanePliki_df) > 0:
                   plikRaportu.write('------------------------------------------------ KONTROLE ATRYBUTÓW ------------------------------------------------\n')
                   for i in range(len(kontrolowanePliki_df)):
                       opisBledu = (
                           f'KONTROLOWANIE PLIKI: {kontrolowanePliki_df[i]}'
                           f'KLASA: {klasy_df[i]}' 
                           f'GMLID: {gmlid_df_k[i]}' 
                           f'KOMUNIKAT BŁĘDU: {komunikatyBledowKontroli_df[i]}\n'
                       )
                       plikRaportu.write(opisBledu)
               else:
                   plikRaportu.write('------------------------------------------------ Brak błędów atrybutowych ------------------------------------------------\n')
               plikRaportu.close()
           except:
               self.iface.messageBar().pushMessage(
                   "Uwaga!", "Brak uprawnień do zapisu raportu.", 
                   level=Qgis.Critical
              )
        
        if 'pdf' in self.dlg.mComboBox.checkedItems():
             from .fpdf import FPDF # tutaj importy by nie przeciążyły pamięci
             from .fpdf import FontFace
             from .fpdf.enums import XPos, YPos
             nazwaPliku = str(pathlib.Path(plik[0]).name)
             bledyWalidacji = {
                 'WALIDOWANY PLIK': walidowanePliki_df, 
                 'WIERSZ': wiersze_df, 
                 'OPIS BŁĘDU': opisyBledow_df, 
                 'KOMUNIKAT BŁĘDU': komunikatyBledow_df,
                 'GMLID':gmlid_df_w
                 }
             bledyKontroli = {
                 'KLASA':klasy_df, 
                 'GMLID':gmlid_df_k, 
                 'KOMUNIKAT BŁĘDU':komunikatyBledowKontroli_df
                  }
             dfWalidacji = pd.DataFrame(bledyWalidacji)
             dfKontroli = pd.DataFrame(bledyKontroli)
             datawalidacja = dfWalidacji.values.tolist()
             datakontrola = dfKontroli.values.tolist()
             grupy_str = {
                 klucz: (wartosc[1], str(wartosc[0])) 
                 for klucz, wartosc in slownik_grupa.items()
             } # Zamiana wartości w słowniku liczba błędów na stringi, choć powinno być ze slownik_rupa
             slownik_liczba_bledow_str = {
                 klucz: (wartosc[1], 
                         str(wartosc[0])) 
                         for klucz, wartosc in slownik_liczba_bledow.items()
             }
             lista_grup = [
                 [klucz, wartosc[0], wartosc[1]] 
                 for klucz, wartosc in grupy_str.items()
                 ]
             lista_bledow = [
                 [klucz, wartosc[0],wartosc[1]] 
                 for klucz, wartosc in slownik_liczba_bledow_str.items()
                 ]
             # Łączenie obu list
             dataSlownik = lista_grup + lista_bledow
             if len(str(bledyWalidacji["WIERSZ"])) == 0:
                 bledyWalidacji["WIERSZ"] = 0
             # tworzenie dokumentu
             class PDF(FPDF): # stopka z numerem strony
                 def header(self):
                     if 'verdana' not in self.fonts:
                         self.add_font(
                             'verdana', 
                             '', 
                             os.path.join(
                                 os.path.dirname(os.path.realpath(__file__)),
                                  "fpdf",
                                  "verdana.ttf"
                             ),
                           )
                     self.set_font('verdana', size = 5)
                     self.cell(0, -5, 
                               (
                                   'Raport został wygenerowany przy pomocy wtyczki QGIS'
                                   f' – „Walidator plików GML” w wersji {version} - udostępnionej przez GUGiK'
                                ), 
                               new_x=XPos.RIGHT, 
                               new_y=YPos.TOP,
                               align="L"
                    )
                 def footer(self):
                     self.set_y(-15)
                     self.cell(
                         0, 
                         10,
                         f'Strona {self.page_no()}', 
                         new_x=XPos.RIGHT,
                         new_y=YPos.TOP, 
                         align='C'
                    )
             
             def create_pdf(filename):
                 czas = time.strftime("%Y-%m-%d %H:%M")
                 pdf = PDF()
                 walidator_sciezka = os.path.dirname(os.path.realpath(__file__))
                 pdf.add_page()
                 pdf.alias_nb_pages()
                 pdf.set_margins(10,10,10)
                 if 'verdana' not in pdf.fonts:
                     pdf.add_font(
                         'verdana', 
                         '', 
                         os.path.join(
                             walidator_sciezka,
                             "fpdf",
                             "verdana.ttf"
                         ),
                    )
                 pdf.add_font(
                     "verdana", 
                     "B", 
                     os.path.join(
                         walidator_sciezka,
                         "fpdf",
                         "verdana-bold.ttf"
                         ),
                     )
                 pdf.set_font('verdana', 'B',14)
                 pdf.cell(0,5, new_x=XPos.LMARGIN, new_y=YPos.NEXT)
                 pdf.cell(0, 0, "Raport z kontroli", align='C', new_x=XPos.LEFT, new_y=YPos.NEXT)
                 pdf.set_font("verdana", "", 8)
                 pdf.cell(0,10, new_x=XPos.LMARGIN, new_y=YPos.NEXT)
                 pdf.cell(100,0, "Wskazany plik:", align='R', new_x=XPos.RIGHT, new_y=YPos.TOP)
                 pdf.cell(100,0, nazwaPliku, align = "L")
                 pdf.cell(0,6, new_x=XPos.LMARGIN, new_y=YPos.NEXT)
                 pdf.set_font("verdana", "", 10)
                 pdf.cell(100,0, "Wynik kontroli:", align='R', new_x=XPos.RIGHT, new_y=YPos.TOP)
                 if self.dlg.comboBox.currentText() == 'EGIB':
                     liczbaKontroli = self.liczbaKontroliWykonanych
                 else:
                     liczbaKontroli = liczbaKontroliWykonanych
                 wynikFinalny  = "Pozytywny" if (walidacjaZWynikiemPozytywnym and kontrolaZWynikiemPozytywnym) else "Negatywny"
                 wynikWalidacja  = "Pozytywny" if walidacjaZWynikiemPozytywnym else "Negatywny"
                 wynikKontrola  = "Pozytywny" if kontrolaZWynikiemPozytywnym else "Negatywny"
                 if liczbaKontroli != 0:
                     # były zaznaczone kontrole
                     wynikKontroli   = wynikFinalny # globalny finalny wynik
                     wynikWalidacji  = wynikWalidacja
                     wynikKonDodat   = wynikKontrola
                 else:
                     # użytkownik chciał tylko walidację, bez kontroli
                     wynikKonDodat   = "Nie dotyczy"
                     wynikWalidacji  = wynikWalidacja
                     wynikKontroli   = "Pozytywny" if walidacjaZWynikiemPozytywnym else "Negatywny"
                 # Ustaw kolor tekstu w zależności od wyniku
                 if wynikKontroli == "Pozytywny":
                     pdf.set_text_color(0, 153, 0)
                 else:
                     pdf.set_text_color(255, 0, 0)
                 pdf.cell(100,0, wynikKontroli, align = "L")
                 pdf.cell(0,6, new_x=XPos.LMARGIN, new_y=YPos.NEXT)
                 pdf.set_text_color(0,0,0)
                 pdf.set_font("verdana", "", 8)
                 pdf.cell(100,0, "Wynik walidacji:", align="R", new_x=XPos.RIGHT, new_y=YPos.TOP)
                 if wynikWalidacji == "Pozytywny":
                    pdf.set_text_color(0,153,0)
                 else:
                    pdf.set_text_color(255,0,0)
                 lightblue = (143, 216, 255)
                 gray = (240,240,240)
                 pdf.cell(100,0,wynikWalidacji, align = "L")
                 pdf.cell(0,5, new_x=XPos.LMARGIN, new_y=YPos.NEXT)
                 pdf.set_text_color(0,0,0)
                 pdf.cell(100,0, "Wynik kontroli dodatkowych:", align="R", new_x=XPos.RIGHT, new_y=YPos.TOP)
                 if wynikKonDodat == "Pozytywny":
                         pdf.set_text_color(0,153,0)
                 elif wynikKonDodat == "Negatywny":
                         pdf.set_text_color(255,0,0)
                 else:
                     # przypadek "Nie dotyczy"
                     pdf.set_text_color(0,0,0)
                 pdf.cell(100,0, wynikKonDodat, align = "L")
                 pdf.cell(0,5, new_x=XPos.LMARGIN, new_y=YPos.NEXT)
                 pdf.set_text_color(0,0,0)
                 pdf.cell(100, 0, "Data kontroli:", align="R", new_x=XPos.RIGHT, new_y=YPos.TOP)
                 pdf.cell(100, 0, czas, align="L", new_x=XPos.LMARGIN, new_y=YPos.NEXT)
                 pdf.cell(0,5, new_x=XPos.LMARGIN, new_y=YPos.NEXT)
                 pdf.cell(100,0,"Wersja szablonu:", align = "R")
                 pdf.cell(100,0,wersjaSzablonuKontroli, align = "L", new_x=XPos.LMARGIN, new_y=YPos.NEXT)
                 pdf.cell(0,1, new_x=XPos.LMARGIN, new_y=YPos.NEXT)
                 with pdf.table(
                         first_row_as_headings=False, 
                         col_widths=(105,95), 
                         borders_layout="NONE", 
                         v_align="TOP"
                     ) as tabelaskp:
                     rzad = tabelaskp.row()
                     rzad.cell("Szablon kontroli:", align="R", padding=(1,1,1,1))
                     rzad.cell(szablonKontroliPath, align="J", padding=(1,5,1,1))
                 pdf.cell(0,1, new_x=XPos.LMARGIN, new_y=YPos.NEXT)
                 pdf.cell(100,0,"Wersja schematu aplikacyjnego GML:", align="R", new_x=XPos.RIGHT, new_y=YPos.TOP)
                 pdf.cell(100,0, wersjaSchematu, align = "L", new_x=XPos.LMARGIN, new_y=YPos.NEXT)
                 pdf.cell(0,1, new_x=XPos.LMARGIN, new_y=YPos.NEXT)
                 with pdf.table(
                         first_row_as_headings=False, 
                         col_widths=(105,95), 
                         borders_layout="NONE", 
                         v_align="TOP"
                     ) as tabelaskp:
                     rzad = tabelaskp.row()
                     rzad.cell("Schemat aplikacyjny GML:", align="R", padding = (1,1,1,1))
                     rzad.cell(xsdPath, align = "J", padding = (1,5,1,1))
                 pdf.cell(0,1, new_x=XPos.LMARGIN, new_y=YPos.NEXT)
                 pdf.cell(100,0,"Suma kontrolna szablonu kontroli (CRC32):", align="R", new_x=XPos.RIGHT, new_y=YPos.TOP)
                 pdf.cell(100,0, sumaKontrolaSzablonKontroli, align = "L", new_x=XPos.LMARGIN, new_y=YPos.NEXT)
                 pdf.cell(0,5, new_x=XPos.LMARGIN, new_y=YPos.NEXT)
                 pdf.cell(100,0,"Suma kontrolna schematu (CRC32):", align="R", new_x=XPos.RIGHT, new_y=YPos.TOP)
                 pdf.cell(100,0, sumaKontrolaSchemat, align = "L", new_x=XPos.LMARGIN, new_y=YPos.NEXT)
                 pdf.cell(0,5, new_x=XPos.LMARGIN, new_y=YPos.NEXT)
                 pdf.cell(100,0,"Suma kontrolna wskazanego pliku (CRC32):", align="R", new_x=XPos.RIGHT, new_y=YPos.TOP)
                 pdf.cell(100,0,sumaKontrolaPlikWalidowany, align = "L")
                 pdf.cell(0,5, new_x=XPos.LMARGIN, new_y=YPos.NEXT)
                 if sumaKontrolnaDaneZrodlowe != "nie dotyczy":
                      pdf.cell(100,0,"Suma kontrola danych wydanych (CRC32):", align="R", new_x=XPos.RIGHT, new_y=YPos.TOP)
                      pdf.cell(100,0, sumaKontrolnaDaneZrodlowe, align = "L")
                      pdf.cell(0,5, new_x=XPos.LMARGIN, new_y=YPos.NEXT)
                 if len(nazwy) > 0:
                      pdf.set_font("verdana", "B", 10)
                      pdf.cell(0,0,"Tabela ze zleconymi kontrolami dodatkowymi", align = "C")
                      pdf.cell(0,5, new_x=XPos.LMARGIN, new_y=YPos.NEXT)
                      pdf.set_font("verdana", "", 8)
                      pdf.set_fill_color(lightblue)
                      with pdf.table(col_widths=(12,40), 
                                     text_align = "C",
                                     padding = (1)) as table:
                          pdf.set_font("verdana", "", 5)
                          headings = table.row()
                          headings.cell("ID KONTROLI")
                          headings.cell("ZAKRES KONTROLI")
                          pdf.set_fill_color(gray)
                      with pdf.table(nazwy, col_widths=(12,40), 
                                     first_row_as_headings=False, 
                                     text_align="L", 
                                     padding = (1)
                                     ):
                          pass
                      pdf.cell(0,12, new_x=XPos.LMARGIN, new_y=YPos.NEXT)
                 pdf.set_fill_color(255,255,255)
                 pdf.set_font("verdana", "" , 6)
                 # tabela statystyk
                 if len(dataSlownik)> 0:
                     pdf.set_font("verdana", "B", 10)
                     pdf.cell(0,0,"Statystyki Kontroli", align = "C")
                     pdf.cell(0,5, new_x=XPos.LMARGIN, new_y=YPos.NEXT)
                     pdf.set_font("verdana", "", 8)
                     pdf.set_fill_color(lightblue)
                     with pdf.table(
                             col_widths=(16,80,12),
                             text_align="C",
                             padding=(1)
                             ) as table:
                         pdf.set_font("verdana", "", 5)
                         headings = table.row()
                         headings.cell("IDENTYFIKATOR KONTROLI")
                         headings.cell("NAZWA KONTROLI")
                         headings.cell("LICZBA BŁĘDÓW")
                         pdf.set_fill_color(gray)
                     with pdf.table(
                             dataSlownik, 
                             col_widths=(16,80,12), 
                             first_row_as_headings=False, 
                             text_align="L", 
                             padding = (1)):
                          pass
                     pdf.cell(0,12, new_x=XPos.LMARGIN, new_y=YPos.NEXT)
                 # tabela walidacji
                 if len(bledyWalidacji["WIERSZ"]) > 0:
                     pdf.set_font("verdana", "B", 10)
                     pdf.cell(0,0,"Tabela z błędami walidacji", align = "C")
                     pdf.set_font("verdana", "", 8)
                     pdf.cell(0,5, new_x=XPos.LMARGIN, new_y=YPos.NEXT)
                     pdf.set_fill_color(lightblue)
                     with pdf.table(
                             col_widths=(40,12,35,68,50), 
                             text_align="C",
                             padding=(1)
                             ) as table:
                         pdf.set_font("verdana", "", 5)
                         headings = table.row()
                         headings.cell("WALIDOWANY PLIK")
                         headings.cell("WIERSZ")
                         headings.cell("OPIS BŁĘDU")
                         headings.cell("KOMUNIKAT BŁĘDU")
                         headings.cell("GMLID")
                         pdf.set_fill_color(gray)
                     with pdf.table(
                             datawalidacja, 
                             col_widths=(40,12,35,68,50), 
                             first_row_as_headings=False, 
                             text_align="L", 
                             padding=(1)
                             ):
                         pass
                     pdf.set_fill_color(255,255,255)
                     pdf.set_font("verdana", "" , 6)
                 else:
                     pdf.set_font("verdana", "B", 10)
                     pdf.cell(0, 0, "Brak błędów walidacji", align = "C")
                 pdf.cell(w=0, h=10, text=" ", new_x=XPos.LMARGIN, new_y=YPos.NEXT)
                 # tabela konotroli
                 if len(bledyKontroli["KLASA"]) > 0:
                     pdf.set_font("verdana", "B", 10)
                     naglowek = [["KLASA", "GMLID", "KOMUNIKAT BŁĘDU"]] # Definicja nagłówka
                     datakontrola2 = naglowek + datakontrola # dodanie do tablicy
                     pdf.set_font("verdana", "B", 10)
                     pdf.cell(0,0,"Tabela z błędami kontroli dodatkowych", align = "C")
                     pdf.set_font("verdana", "", 5)
                     pdf.cell(0,5, new_x=XPos.LMARGIN, new_y=YPos.NEXT)
                     headings_style = FontFace(emphasis="BOLD", color=0, fill_color=lightblue)
                     with pdf.table(
                             datakontrola2, 
                             num_heading_rows=1, 
                             col_widths=(40,50,70), 
                             cell_fill_color=(240,240,240), 
                             cell_fill_mode="ROWS", 
                             headings_style=headings_style, 
                             first_row_as_headings=True, 
                             text_align="C", 
                             padding=(1)
                             ):
                         pass
                 elif liczbaKontroliWykonanych != 0:
                      pdf.set_font("verdana", "B", 10)
                      pdf.cell(0,0,"Brak błędów kontroli dodatkowych", align="C")
                      pdf.set_font("verdana", "", 5)
                 pdf.output(filename)
             create_pdf(pathPDF)
             # koniec tworzenia pdf
        
        if 'xls' in self.dlg.mComboBox.checkedItems():
            progressMessageBar = iface.messageBar().createMessage("Generowanie raportu xls...")
            bledyWalidacji = {
                'WALIDOWANY PLIK': walidowanePliki_df, 
                'GMLID': gmlid_df_w, 
                'WIERSZ': wiersze_df, 
                'OPIS BŁĘDU': opisyBledow_df, 
                'KOMUNIKAT BŁĘDU': komunikatyBledow_df
                }
            bledyKontroli = {
                'KLASA':klasy_df, 
                'GMLID':gmlid_df_k, 
                'KOMUNIKAT BŁĘDU':komunikatyBledowKontroli_df, 
                'GRUPA KONTROLI': grupyKontroli_df
                }
            if len(bledyWalidacji["WIERSZ"]) == 0:
                bledyWalidacji["WIERSZ"] = 0
            dataFrameWalidacja = pd.DataFrame(bledyWalidacji)
            dataFrameKontrola = pd.DataFrame(bledyKontroli)
            
            try:
                strony = xlwt.Workbook()
                arkuszDaneWstepne = strony.add_sheet('Podsumowanie kontroli')
                arkuszStatystyk = strony.add_sheet('Statystyki')
                arkuszWalidacji = strony.add_sheet('Raport z walidacji')
                arkuszKontroli = strony.add_sheet('Raport z kontroli dodatkowych')
                styl1 = xlwt.easyxf('align: wrap on, vert center;  borders: left thin, right thin, top thin, bottom thin')
                styl2 = xlwt.easyxf("align: horz center, vert center; font: bold on; align: wrap on; borders: left thin, right thin, top thin, bottom thin")
                styl3 = xlwt.easyxf("align: horz left, vert center; font: bold on; align: wrap on; borders: left thin, right thin, top thin, bottom thin")
                neg = xlwt.easyxf("align: horz left, vert center; font: bold on, color red; align: wrap on; borders: left thin, right thin, top thin, bottom thin")
                poz = xlwt.easyxf("align: horz left, vert center; font: bold on, color green; align: wrap on; borders: left thin, right thin, top thin, bottom thin")
                czr = xlwt.easyxf("align: horz left, vert center; font: bold on, color black; align: wrap on; borders: left thin, right thin, top thin, bottom thin")
                arkuszDaneWstepne.write(0,0,"Data kontroli i wskazany plik", styl3)
                arkuszDaneWstepne.write(1,0,"Wersja wtyczki", styl3)
                arkuszDaneWstepne.write(2,0,"Suma kontrolna szablonu kontroli (CRC32)", styl3)
                arkuszDaneWstepne.write(3,0,"Wersja szablonu kontroli", styl3)
                arkuszDaneWstepne.write(4,0,"Suma kontrolna schematu (CRC32)", styl3)
                arkuszDaneWstepne.write(5,0,"Wersja schematu aplikacyjnego GML", styl3)
                arkuszDaneWstepne.write(6,0,"Suma kontrolna wskazanego pliku (CRC32)", styl3)
                wiersz = 7
                if sumaKontrolnaDaneZrodlowe != 'nie dotyczy':
                    arkuszDaneWstepne.write(wiersz,0,"Suma kontrola danych wydanych (CRC32)", styl3)
                    arkuszDaneWstepne.write(wiersz,1,sumaKontrolnaDaneZrodlowe, styl1)
                    arkuszDaneWstepne.write(wiersz,2,'', styl1)
                    wiersz += 1
                arkuszDaneWstepne.write(wiersz,0,"Wynik kontroli", styl3)
                arkuszDaneWstepne.write(wiersz + 1,0,"Wynik walidacji", styl3)
                arkuszDaneWstepne.write(wiersz + 2,0,"Wynik kontroli dodatkowych", styl3)
                arkuszDaneWstepne.col(0).width = 10000
                arkuszDaneWstepne.col(1).width = 5000
                arkuszDaneWstepne.col(2).width = 35000
                arkuszDaneWstepne.write(0,1,time.strftime("%Y-%m-%d %H:%M"), styl1)
                arkuszDaneWstepne.write(0,2,str(pathlib.Path(plik[0]).name), styl1)
                arkuszDaneWstepne.write(1,1,str(version),styl1)
                arkuszDaneWstepne.write(1,2,'', styl1)
                arkuszDaneWstepne.write(2,1,sumaKontrolaSzablonKontroli, styl1)
                arkuszDaneWstepne.write(2,2,'', styl1)
                arkuszDaneWstepne.write(3,1,wersjaSzablonuKontroli, styl1)
                arkuszDaneWstepne.write(3,2,szablonKontroliPath, styl1)
                arkuszDaneWstepne.write(4,1,sumaKontrolaSchemat, styl1)
                arkuszDaneWstepne.write(4,2,'', styl1)
                arkuszDaneWstepne.write(5,1,wersjaSchematu, styl1)
                arkuszDaneWstepne.write(5,2,xsdPath, styl1)
                arkuszDaneWstepne.write(6,1,sumaKontrolaPlikWalidowany, styl1)
                arkuszDaneWstepne.write(6,2,'', styl1)
                arkuszDaneWstepne.write(wiersz,2,'', styl1)
                arkuszDaneWstepne.write(wiersz + 1,2,'', styl1)
                arkuszDaneWstepne.write(wiersz + 2,2,'', styl1)
                for i, (data1, data2) in enumerate(nazwy):
                    wierszTabela = i + wiersz + 3
                    if wierszTabela >= 65536:  # 0..65535
                        QMessageBox.warning(
                        QMessageBox(), 
                        'Ograniczenie xls',
                        'Ograniczono listę zleconych kontroli do 65 536 wierszy.',
                        QMessageBox.Ok
                        )
                        break
                    arkuszDaneWstepne.write(wierszTabela,0,"Zlecona kontrola dodatkowa", styl3)
                    arkuszDaneWstepne.write(wierszTabela,1, f"{data1}", styl1)
                    arkuszDaneWstepne.write(wierszTabela,2, f"{data2}", styl1)
                arkuszStatystyk.write(0,0,"IDENTYFIKATOR KONTROLI", styl2)
                arkuszStatystyk.write(0,1,"NAZWA KONTROLI", styl2)
                arkuszStatystyk.write(0,2,"LICZBA BŁĘDÓW", styl2)
                arkuszStatystyk.col(0).width = 5000
                arkuszStatystyk.col(1).width = 15000
                arkuszStatystyk.col(2).width = 4000
                start_row = len(slownik_grupa) + 2
                for i, (k, (w, n)) in enumerate(slownik_grupa.items()):
                    arkuszStatystyk.write(i+1,0, k, styl1)
                    arkuszStatystyk.write(i+1,1, n, styl1)
                    arkuszStatystyk.write(i+1,2, w, styl1)
                for j,(klucz, (wartosc, nazwa)) in enumerate(slownik_liczba_bledow.items()):
                    arkuszStatystyk.write(j+start_row,0, klucz, styl1)
                    arkuszStatystyk.write(j+start_row,1, nazwa, styl1)
                    arkuszStatystyk.write(j+start_row,2, wartosc, styl1)
                arkuszWalidacji.write(0,0,"WALIDOWANY PLIK", styl2)
                arkuszWalidacji.write(0,1,"GMLID", styl2)
                arkuszWalidacji.write(0,2,"WIERSZ", styl2)
                arkuszWalidacji.write(0,3,"OPIS BŁĘDU", styl2)
                arkuszWalidacji.write(0,4,"KOMUNIKAT BŁĘDU", styl2)
                arkuszWalidacji.col(0).width = 12500
                arkuszWalidacji.col(1).width = 11000
                arkuszWalidacji.col(2).width = 2000
                arkuszWalidacji.col(3).width = 10000
                arkuszWalidacji.col(4).width = 10000
                arkuszKontroli.write(0,0,"KLASA", styl2)
                arkuszKontroli.write(0,1,"GMLID", styl2)
                arkuszKontroli.write(0,2,"KOMUNIKAT BŁĘDU", styl2)
                arkuszKontroli.write(0,3,"GRUPA KONTROLI", styl2)
                arkuszKontroli.col(0).width = 4000
                arkuszKontroli.col(1).width = 12500
                arkuszKontroli.col(2).width = 27500
                arkuszKontroli.col(3).width = 10000
                for i, row in enumerate(dataFrameWalidacja.values):
                    if i > 65500:
                        QMessageBox.critical(
                            QMessageBox(), 
                            'Ograniczenie xls', 
                            'Liczba wierszy xls została ograniczona do 65535 błędów.', 
                            QMessageBox.Ok
                            )
                        break
                    else:
                        for j, val in enumerate(row):
                            arkuszWalidacji.write(i + 1, j, str(val), styl1)
                
                for i, row in enumerate(dataFrameKontrola.values):
                    if i > 65500:
                        QMessageBox.critical(
                            QMessageBox(), 
                            'Ograniczenie xls', 
                            'Liczba wierszy xls została ograniczona do 65535 błędów.', 
                            QMessageBox.Ok
                            )
                        break
                    else:
                        for j, val in enumerate(row):
                            arkuszKontroli.write(i + 1, j, str(val), styl1)
                if self.dlg.comboBox.currentText() == 'EGIB':
                    liczbaKontroliWykonanych = self.liczbaKontroliWykonanych
                wynik_5_6_7 = "Pozytywny" if walidacjaZWynikiemPozytywnym and kontrolaZWynikiemPozytywnym else "Negatywny"
                wynik_6 = "Pozytywny" if walidacjaZWynikiemPozytywnym else "Negatywny"
                wynik_7 = "Pozytywny" if kontrolaZWynikiemPozytywnym else "Negatywny"
                if liczbaKontroliWykonanych != 0:
                    arkuszDaneWstepne.write(wiersz, 1, wynik_5_6_7, poz if wynik_5_6_7 == "Pozytywny" else neg)
                    arkuszDaneWstepne.write(wiersz + 1, 1, wynik_6, poz if wynik_6 == "Pozytywny" else neg)
                    arkuszDaneWstepne.write(wiersz + 2, 1, wynik_7, poz if wynik_7 == "Pozytywny" else neg)
                else:
                    arkuszDaneWstepne.write(wiersz + 2, 1, "Nie dotyczy", czr)
                    if walidacjaZWynikiemPozytywnym and kontrolaZWynikiemPozytywnym:
                        arkuszDaneWstepne.write(wiersz, 1, "Pozytywny", poz)
                        arkuszDaneWstepne.write(wiersz + 1, 1, "Pozytywny", poz)
                    else:
                        arkuszDaneWstepne.write(wiersz, 1, "Negatywny", neg)
                        arkuszDaneWstepne.write(
                            wiersz + 1, 
                            1, 
                            (
                                "Negatywny" 
                                if not walidacjaZWynikiemPozytywnym 
                                else "Pozytywny",
                            )
                            (
                                neg 
                                if not walidacjaZWynikiemPozytywnym 
                                else poz
                            ),
                        )
                strony.save(pathXLS)
            finally:
                try:
                    # wyczyść referencje, żeby obiekty xlwt wyszły z zasięgu
                    arkuszDaneWstepne = arkuszStatystyk = arkuszWalidacji = arkuszKontroli = None
                    styl1 = styl2 = styl3 = neg = poz = czr = None
                    strony = None
                except Exception as e:
                    print(f'Błąd w tworzeniu pliku xls: {e}')
                    return
            # koniec tworzenia xls
            
        if 'xlsx' in self.dlg.mComboBox.checkedItems(): # nowoczesniejsza wersja xlsx
            progressMessageBar = iface.messageBar().createMessage("Generowanie raportu xlsx...")
            bledyWalidacji = {
                'WALIDOWANY PLIK': walidowanePliki_df, 
                'GMLID': gmlid_df_w, 
                'WIERSZ': wiersze_df, 
                'OPIS BŁĘDU': opisyBledow_df, 
                'KOMUNIKAT BŁĘDU': komunikatyBledow_df
                }
            bledyKontroli = {
                'KLASA':klasy_df, 
                'GMLID':gmlid_df_k, 
                'KOMUNIKAT BŁĘDU':komunikatyBledowKontroli_df, 
                'GRUPA KONTROLI': grupyKontroli_df
                }
            try:
                idenkontroli = []
                nazwKontroli = []
                liczBledy = []
                for i, (k, (w, n)) in enumerate(slownik_grupa.items()):
                    idenkontroli.append(k)
                    nazwKontroli.append(n)
                    liczBledy.append(w)
                if len(slownik_grupa) > 0:
                    idenkontroli.append("") # dodanie pustego wiersza w przerwie
                    nazwKontroli.append("")
                    liczBledy.append("")
                for j,(klucz, (wartosc, nazwa)) in enumerate(slownik_liczba_bledow.items()):
                    idenkontroli.append(klucz)
                    nazwKontroli.append(nazwa)
                    liczBledy.append(wartosc)
                daneStatystyk = {
                    'IDENTYFIKATOR KONTROLI':idenkontroli, 
                    'NAZWA KONTROLI':nazwKontroli, 
                    'LICZBA BŁĘDÓW': liczBledy
                    }
                if self.dlg.comboBox.currentText() == 'EGIB':
                    liczbaKontroliWykonanych = self.liczbaKontroliWykonanych
                wynik_5_6_7 = "Pozytywny" if walidacjaZWynikiemPozytywnym and kontrolaZWynikiemPozytywnym else "Negatywny"
                wynik_6 = "Pozytywny" if walidacjaZWynikiemPozytywnym else "Negatywny"
                wynik_7 = "Pozytywny" if kontrolaZWynikiemPozytywnym else "Negatywny"
                if liczbaKontroliWykonanych != 0:
                  wynikKontroli = wynik_5_6_7
                  wynikWalidacji =  wynik_6
                  wynikKonDodat = wynik_7
                else:
                    wynikKonDodat = 'Nie dotyczy'
                    wynikWalidacji =  wynik_6
                    if walidacjaZWynikiemPozytywnym:
                        wynikKontroli = "Pozytywny"
                    else:
                        wynikKontroli = "Negatywny"
                if len(bledyWalidacji["WIERSZ"]) == 0:
                    bledyWalidacji["WIERSZ"] = 0
            
                daneWstepne = [
                    ["Data kontroli i wskazany plik",time.strftime("%Y-%m-%d %H:%M"), 
                     str(pathlib.Path(plik[0]).name)],
                    ["Wersja wtyczki",str(version), ''],
                    ["Suma kontrolna szablonu kontroli (CRC32)",sumaKontrolaSzablonKontroli, ''],
                    ["Wersja szablonu kontroli",wersjaSzablonuKontroli, szablonKontroliPath],
                    ["Suma kontrolna schematu (CRC32)",sumaKontrolaSchemat, ''],
                    ["Wersja schematu aplikacyjnego GML",wersjaSchematu, xsdPath],
                    ["Suma kontrolna wskazanego pliku (CRC32)", sumaKontrolaPlikWalidowany, ''],
                    ["Wynik kontroli",wynikKontroli,''],
                    ["Wynik walidacji",wynikWalidacji,''],
                    ["Wynik kontroli dodatkowych",wynikKonDodat,'']]
                if sumaKontrolnaDaneZrodlowe != 'nie dotyczy':
                    daneWstepne.insert(7, ["Suma kontrola danych wydanych (CRC32)", sumaKontrolnaDaneZrodlowe, ''])
                for i, (data1, data2) in enumerate(nazwy):
                    daneWstepne.append(
                        ["Zlecona kontrola dodatkowa", data1, data2]
                    )
                arkuszDaneWstepne = pd.DataFrame(daneWstepne)
                arkuszStatystyk = pd.DataFrame(daneStatystyk)
                dataFrameWalidacja = pd.DataFrame(bledyWalidacji)
                dataFrameKontrola = pd.DataFrame(bledyKontroli)
                czcionka = Font(name='Arial', size=10)
                czcioNagl = Font(name='Arial', size=10, bold= True)
                thin_border = Border( # utworzenie ramki 
                    left=Side(style="thin"),
                    right=Side(style="thin"),
                    top=Side(style="thin"),
                    bottom=Side(style="thin")
                    )
                alignment = Alignment(wrap_text=True)
                alignment_center = Alignment(
                    horizontal='center',
                    vertical='center',
                    wrap_text=True
                ) # nagłówki na srodku
                with pd.ExcelWriter(pathXLSX) as writer:
                    arkuszDaneWstepne.to_excel(
                        writer, 
                        sheet_name="Podsumowanie kontroli", 
                        index=False, 
                        header=False
                    )
                    worksheet = writer.sheets["Podsumowanie kontroli"]
                    max_col = worksheet.max_column
                    max_row = worksheet.max_row
                    worksheet.column_dimensions["A"].width = 41 # 1 arkusz
                    worksheet.column_dimensions["B"].width = 20
                    worksheet.column_dimensions["C"].width = 136
                    for row in range(1, worksheet.max_row + 1):  # zmiana szerokosci wierszy
                        worksheet.row_dimensions[row].height = 12.75
                    # Formatowanie pierwszej kolumny jako pogrubionej
                    for row in worksheet.iter_rows(
                            min_col=1,
                            max_col=1, 
                            min_row=1, 
                            max_row=max_row
                        ):
                        for cell in row:
                            cell.font = czcioNagl
                            cell.border = thin_border
                            cell.alignment = alignment
                    for row in worksheet.iter_rows(
                            min_col=2, 
                            max_col=max_col,
                            min_row=1, 
                            max_row=max_row
                        ): # ustawiania na pozostałcy kolumnach
                        for cell in row:
                            cell.font = czcionka
                            cell.border = thin_border
                            cell.alignment = alignment
                            if cell.value == "Pozytywny": # kolorowanie wyników kontroli
                                cell.font = Font(bold=True, color="008000")  # Zielony
                            elif cell.value == "Negatywny":
                                cell.font = Font(bold=True, color="FF0000")  # Czerwony
                            elif cell.value == "Nie dotyczy":
                                cell.font = Font(bold=True)  # Domyślny czarny
                                
                    arkuszStatystyk.to_excel(
                        writer, 
                        sheet_name="Statystyki", 
                        index=False
                    )
                    worksheet = writer.sheets["Statystyki"] # 2 arkusz
                    worksheet.column_dimensions["A"].width = 20
                    worksheet.column_dimensions["B"].width = 58
                    worksheet.column_dimensions["C"].width = 15
                    for row in worksheet.iter_rows():
                        if all(cell.value == "" or cell.value is None for cell in row):  # Sprawdzanie, czy cały wiersz jest pusty
                            continue  # Pomijanie stylizacji dla pustych wierszy
                        for cell in row:
                            cell.font = czcionka
                            cell.border = thin_border
                            cell.alignment = alignment
                    max_col = worksheet.max_column
                    for cell in worksheet[1]:  # Pierwszy wiersz to nagłówki
                        cell.alignment = alignment_center
                        cell.font = czcioNagl 
                    for row in worksheet.iter_rows(min_col=1, max_col=1, min_row=2):
                        for cell in row: # ustawienie na lewy srodek tekstu w kolumnie Identyfikator Kontroli
                            cell.alignment = Alignment(horizontal='left', vertical='center')
                    for row in worksheet.iter_rows(min_col=2, max_col=2, min_row=2):
                        for cell in row: # ustawienie na lewy srodek tekstu w kolumnie Nazwa kontroli
                            cell.alignment = Alignment(horizontal='left', vertical='center', wrap_text=True)
                    for row in worksheet.iter_rows(min_col=max_col, max_col=max_col, min_row=2):
                        for cell in row: # ustawienie na prawy srodek tekstu w kolumnie Liczba Błędów
                            cell.alignment = Alignment(horizontal='right', vertical='center')

                    dataFrameWalidacja.to_excel(writer, sheet_name="Raport z walidacji", index=False)
                    worksheet = writer.sheets["Raport z walidacji"] # 3 arkusz
                    worksheet.column_dimensions["A"].width = 49
                    worksheet.column_dimensions["B"].width = 43
                    worksheet.column_dimensions["C"].width = 8
                    worksheet.column_dimensions["D"].width = 39
                    worksheet.column_dimensions["E"].width = 39
                    max_col = worksheet.max_column
                    max_row=worksheet.max_row
                    for row in worksheet.iter_rows():
                        for cell in row:
                            cell.font = czcionka
                            cell.border = thin_border
                            cell.alignment = alignment
                    for cell in worksheet[1]:  # Pierwszy wiersz to nagłówki
                        cell.alignment = alignment_center
                        cell.font = czcioNagl
                    for row in worksheet.iter_rows(min_col=1, max_col=max_col, min_row=2, max_row= max_row):
                        for cell in row:
                            cell.alignment = Alignment(
                                horizontal='left', 
                                vertical='center', 
                                wrap_text=True
                            )
                   
                    dataFrameKontrola.to_excel(writer, sheet_name="Raport z kontroli dodatkowych", index=False)
                    worksheet = writer.sheets["Raport z kontroli dodatkowych"] # 4 arkusz
                    worksheet.column_dimensions["A"].width = 15.5
                    worksheet.column_dimensions["B"].width = 49
                    worksheet.column_dimensions["C"].width = 107
                    worksheet.column_dimensions["D"].width = 39
                    for row in worksheet.iter_rows():
                        for cell in row:
                            cell.font = czcionka
                            cell.border = thin_border
                            cell.alignment = alignment
                    for cell in worksheet[1]:  # Pierwszy wiersz to nagłówki
                        cell.alignment = alignment_center
                        cell.font = czcioNagl
                    for row in worksheet.iter_rows(min_col=1, max_col=1, min_row=2):
                        for cell in row: # ustawienie na lewy srodek tekstu w kolumnie Klasa
                            cell.alignment = Alignment(horizontal='left', vertical='center')
                    for row in worksheet.iter_rows(min_col=2, max_col=2, min_row=2):
                        for cell in row: # ustawienie na lewy srodek tekstu w kolumnie GMLID
                            cell.alignment = Alignment(horizontal='left', vertical='center')
                    for row in worksheet.iter_rows(min_col=3, max_col=3, min_row=2):
                        for cell in row: # ustawienie na lewy srodek tekstu w kolumnie Komunikat Błedu
                            cell.alignment = Alignment(horizontal='left', vertical='center', wrap_text=True)
                    for row in worksheet.iter_rows(min_col=4, max_col=4, min_row=2):
                        for cell in row: # ustawienie na lewy srodek tekstu w kolumnie Grupa Kontroli
                            cell.alignment = Alignment(horizontal='left', vertical='center')
            except Exception as e:
                 print(f'Błąd w generacji pliku xlsx: {e}')
                 return
        
        if 'shp' in self.dlg.mComboBox.checkedItems():
            created_layers = {
                QgsWkbTypes.PointGeometry: False,
                QgsWkbTypes.LineGeometry: False,
                QgsWkbTypes.PolygonGeometry: False
                }
            for layer in QgsProject.instance().mapLayers().values():
                if layer.isValid() and isinstance(layer, QgsVectorLayer) and layer.featureCount() > 0:
                    if (
                        layer.name() in [
                            "błędy z kontroli atrybutów",
                            "błędne geometrie obiektów pokrycia terenu",
                            "lokalizacje błędów geometrii obiektów pokrycia terenu", 
                            "nakładania w pokryciu terenu",
                            "dziury w pokryciu terenu",
                            "nakładania buforów poziomic"
                        ] 
                        or "błędy z walidacji" in layer.name()
                    ):
                        if "błędy z kontroli atrybutów" in layer.name():
                            typ_geometrii = layer.geometryType()
                            # Jeśli warstwa dla tego typu geometrii została już stworzona, pomiń
                            if created_layers[typ_geometrii]:
                                continue
                            # Ustaw flagę na True, aby oznaczyć, że warstwa tego typu została już przetworzona
                            created_layers[typ_geometrii] = True
                            suffix = ''
                            if typ_geometrii == QgsWkbTypes.PointGeometry:
                                suffix = f"_Punkt"
                            elif typ_geometrii == QgsWkbTypes.LineGeometry:
                                suffix = f"_Linia"
                            elif typ_geometrii == QgsWkbTypes.PolygonGeometry:
                                suffix = f"_Poligon"
                            else:
                                suffix = f"_InnyTypGeometrii"
                            outSHP = (
                                f'{sciezkaGML}/RaportBledow_{nazwa_pliku}_'
                                f'{timestr}_błędy z kontroli atrybutów{suffix}.shp'
                            )
                        elif "błędy z walidacji" in layer.name():
                            outSHP = (
                                f'{sciezkaGML}/RaportBledow_{layer.name()}.shp'
                            ).replace('__', f'_{timestr}_')
                                 
                        else:
                            outSHP = (
                                f'{sciezkaGML}/RaportBledow_'
                                f'{nazwa_pliku}_{timestr}_{layer.name()}.shp'
                            )
                        options = QgsVectorFileWriter.SaveVectorOptions()
                        options.driverName = 'ESRI Shapefile'
                        options.layerName = layer.name()
                        options.fileEncoding = 'UTF-8'
                        options.destCRS = QgsCoordinateReferenceSystem(epsg)
                        options.actionOnExistingFile = QgsVectorFileWriter.CreateOrOverwriteFile
                        error =  QgsVectorFileWriter.writeAsVectorFormatV3(layer, outSHP, QgsCoordinateTransformContext(), options)
        
        if 'gpkg' in self.dlg.mComboBox.checkedItems():
            created_layers = {
                QgsWkbTypes.PointGeometry: False,
                QgsWkbTypes.LineGeometry: False,
                QgsWkbTypes.PolygonGeometry: False
                }
            for layer in QgsProject.instance().mapLayers().values():
                if layer.isValid() and isinstance(layer, QgsVectorLayer) and layer.featureCount() > 0:
                    if (
                            layer.name() in [
                                "błędy z kontroli atrybutów",
                                "błędne geometrie obiektów pokrycia terenu",
                                "lokalizacje błędów geometrii obiektów pokrycia terenu", 
                                "nakładania w pokryciu terenu",
                                "dziury w pokryciu terenu",
                                "nakładania buforów poziomic"
                                ] 
                            or "błędy z walidacji" in layer.name()
                        ):
                        
                        if "błędy z kontroli atrybutów" in layer.name():
                            typ_geometrii = layer.geometryType()
                            # Jeśli warstwa dla tego typu geometrii została już stworzona, pomiń
                            if created_layers[typ_geometrii]:
                                continue
                            # Ustaw flagę na True, aby oznaczyć, że warstwa tego typu została już przetworzona
                            created_layers[typ_geometrii] = True
                            suffix = ''
                            
                            if typ_geometrii == QgsWkbTypes.PointGeometry:
                                suffix = f"_Punkt"
                            elif typ_geometrii == QgsWkbTypes.LineGeometry:
                                suffix = f"_Linia"
                            elif typ_geometrii == QgsWkbTypes.PolygonGeometry:
                                suffix = f"_Poligon"
                            else:
                                suffix = f"_InnyTypGeometrii"
                            outGPKG = (
                                f'{sciezkaGML}/RaportBledow_{nazwa_pliku}_'
                                f'{timestr}_błędy z kontroli atrybutów{suffix}.gpkg'
                            )
                        elif "błędy z walidacji" in layer.name():
                            outGPKG = (
                                f'{sciezkaGML}/RaportBledow_{layer.name()}.gpkg'
                            ).replace('__', f'_{timestr}_')
                        else:
                            outGPKG = (
                                f'{sciezkaGML}/RaportBledow_{nazwa_pliku}_'
                                f'{timestr}_{layer.name()}.gpkg'
                            )
                        options = QgsVectorFileWriter.SaveVectorOptions()
                        options.driverName = 'GPKG'
                        options.layerName = layer.name()
                        options.fileEncoding = 'UTF-8'
                        options.destCRS = QgsCoordinateReferenceSystem(epsg)
                        options.actionOnExistingFile = QgsVectorFileWriter.CreateOrOverwriteFile
                        error =  QgsVectorFileWriter.writeAsVectorFormatV3(layer, outGPKG, QgsCoordinateTransformContext(), options)


    # walidacja pliku GML z conajmniej jednym obiektem
    def walidacja(self, task):
        global walidacjaZWynikiemPozytywnym, plikiZparsowane, plikGML, walidowanyPlik
        plikGML = pliki[int(task.description())]
        try:
            error_gmlid_dic = {}
            plikiZparsowane.append(plikGML)
            if self.dlg.comboBox.currentText() != 'EGIB':  # prostsza walidacja dla innych plików niż EGiB
                unique_gmlid = set()
                walidowanyPlik = lxml.etree.parse(plikGML)
                if walidowanyPlik.getroot() != None:
                    error_gmlid_dic = {}
                    for element in list(walidowanyPlik.iter()):
                        if str(element.tag).endswith('featureMember'):
                            wynikWalidacji = xmlschema.validate(element)
                            if not wynikWalidacji:
                                walidacjaZWynikiemPozytywnym = False
                                for subelement in element:
                                    error_gmlid_dic[xmlschema.error_log] = (
                                        subelement.attrib['{http://www.opengis.net/gml/3.2}id']
                                    )
                
                    return {'taskID':task.description(), 'plikGML':plikGML, 'error':error_gmlid_dic}
        
            else:
                 self.plikiZparsowane = plikiZparsowane # koniecznie na potrzeby pliku posredniego w EGIB
                 plikDoWalidacji = str(plikGML)
                 counter = 0
                 GML_IDS = ('{http://www.opengis.net/gml/3.2}id', '{http://www.opengis.net/gml}id')
                 def wyciagnijGmlId(node):
                     #Szuka GMLID w zależnosci od wersji standardu .gml

                     for el in node.iter():
                         for key in GML_IDS:
                             if key in el.attrib:
                                 return el.attrib[key]
                             return 'BRAK_ID'
                 FakeXsdError = namedtuple('FakeXsdError', 'message line type_name')
                 def naBladWalidacji(msg, line=0, type_name='SCHEMAV_ELEMENT_CONTENT'):
                     # Tworzy „sztuczny” wpis błędu XSD, na przypadek gdy walidator nie zwrócił szczegółów.

                     return FakeXsdError(msg, line, type_name)
                 def znajdzGmlId(el):
                     # Szuka GMLID w całym poddrzewie obiektu (featureMember), w wersjach GML 3.2 i 3.1.
                     # Zwraca pierwsze znalezione ID lub 'BRAK_ID'.
                     ln = getattr(el, 'sourceline', None)
                     if ln:
                         return ln
                     for n in el.iter():
                         ln = getattr(n, 'sourceline', None)
                         if ln:
                             return ln
                         return 0
                 try:
                     with open(plikGML, 'rb', buffering=1024*1024) as f:
                         ctx = etree.iterparse(
                             f, 
                             events=('end',), 
                             tag='{*}featureMember',
                             huge_tree=True
                         )
                         for event, element in ctx:
                             # 1) zanim wyczyścimy element: pobieramy ID i ewentualny numer linii
                             gml_id = wyciagnijGmlId(element) 
                             line_hint = znajdzGmlId(element) 
                             try:
                                 first_child = next(iter(element), None)
                                 if first_child is not None:
                                     # najpierw próbujemy wersję 3.2, potem 3.1
                                     gml_id = (
                                         first_child.attrib.get(GML_IDS[0]) or
                                         first_child.attrib.get(GML_IDS[1]) or
                                         'BRAK_ID'
                                         )
                                     # jeśli nadal BRAK_ID, przeskanuj króciutko całe poddrzewo
                                 if gml_id == 'BRAK_ID':
                                     found = False
                                     for el in element.iter():
                                         val = el.attrib.get(GML_IDS[0]) or el.attrib.get(GML_IDS[1])
                                         if val:
                                             gml_id = val
                                             found = True
                                             break
                             except Exception:
                                 # nic – zachowujemy 'BRAK_ID' jak dotąd
                                 pass
                             # 2) Walidacja pojedynczego obiektu:
                                 #    - assertValid() waliduje i w razie błędów rzuca wyjątek z lokalnym logiem
                             try:
                                 xmlschema.assertValid(element)
                                 ok = True 
                                 errs = [] # brak błędów dla tego obiektu
                             except Exception as e:
                                 ok = False
                                 errs = list(e.error_log) 

                             if not ok:
                                 walidacjaZWynikiemPozytywnym = False
                                 if errs:
                                     error_gmlid_dic[tuple(errs)] = gml_id

                                 else:
                                     error_gmlid_dic[
                                         (
                                             naBladWalidacji(
                                                 "Walidacja nie powiodła się (szczegóły niedostępne)"
                                             ),
                                          line_hint
                                          )
                                     ] = gml_id
                        
                             element.clear()
                             parent = element.getparent()
                             if parent is not None:
                                 while element.getprevious() is not None:
                                     del parent[0]
                             counter += 1
                             if counter % 50000 == 0:
                                 if hasattr(ctx, "root"):
                                     try:
                                         while ctx.root.getprevious() is not None:
                                             del ctx.root.getparent()[0]
                                     except Exception:
                                         pass
                 except Exception as e:
                     QMessageBox.critical(self.iface.mainWindow(), "Błąd walidacji", f"Walidacja przerwana:\n{e}")
                     return
                 return {'taskID':task.description(), 'plikGML':plikGML, 'error':error_gmlid_dic}
        
        except lxml.etree.XMLSyntaxError as error:
            walidacjaZWynikiemPozytywnym = False
            error_gmlid_dic = {}
            error_gmlid_dic[error] = ''
            return {'taskID':task.description(), 'plikGML':plikGML, 'error':error_gmlid_dic}
        except OSError as error:
            print(f"błąd OSError: {error}")
            walidacjaZWynikiemPozytywnym = False
            error_gmlid_dic = {}
            error_gmlid_dic[error] = ''
            return {'taskID':task.description(), 'plikGML':plikGML, 'error':error_gmlid_dic}
        except Exception as e:
            print(f"błąd w funkcji walidacji: {e}")


    def wynikiWalidacji(self, exception = None, value = None):
        global walidowanePliki_df, wiersze_df, opisyBledow_df, komunikatyBledow_df, gmlid_df_w
        
        frazy = {"The value":"Wartość",
                 "failed to load external entity":"nie udało się załadować",
                 "Error reading file":"Błąd odczytu pliku",
                 "is not an element of the set":"nie znajduje się na liście",
                 "This element is not expected":"Ten element jest nieoczekiwany",
                 "Expected is one of":"Oczekiwana jest jedna wartość z ", 
                 "Expected is":"Oczekiwany jest ",
                 "is not a valid value of the atomic type":"jest nieprawidłową wartością typu podstawowego",
                 "is not a valid value of the list type \'{http://www.opengis.net/gml/3.2}doubleList\'":" jest nieprawidłową wartością typu listowego \'{http://www.opengis.net/gml/3.2}doubleList\'",
                 "Opening and ending tag mismatch":"Błędny otwierający lub zamykający znacznik",
                 "line":"linia",
                 "and":"i",
                 "Start tag expected":"Oczekiwany tag początkowy",
                 "huge text node":"ogromny węzeł tekstowy",
                 "Point":"Punkt",
                 "column":"kolumna",
                 "is not a valid value of the union type":"jest nieprawdłową wartością typu unia",
                 "is less than the minimum value allowed":"jest mniejsza niż minimalna dozwolona wartość",
                 "Missing child element(s)":"Brakuje elementów dziecka/dzieci",
                 "EndTag":"Znacznik zamykający",
                 "must be greater than":"musi być większa niż",
                 "is not accepted by the pattern":"nie jest zgodna z paternem",
                 "is greater than the maximum value allowed":"jest większa niż maksymalna dozwolona liczba",
                 "not found": "nie został znaleziony",
                 "is not a valid value of the local atomic type":"nie jest poprawną wartością lokalnego typu podstawowego"
                 }
        if value != None:
            formats_to_check = ['xls', 'pdf', 'txt', 'shp', 'gpkg', 'xlsx']
            for errors in value['error']:
                if isinstance(errors, lxml.etree.XMLSyntaxError):
                    opisBledu = re.sub(r'{[^}]+}', '', str(errors)) 
                    for key in frazy:
                        opisBledu = opisBledu.replace(key,frazy[key])
                    msg =( 
                        f"Błąd w składni pliku XML: {str(value['plikGML'])}\n"
                        f"- komunikat błędu: {opisBledu}\n\n"
                        )
                    if any(format in self.dlg.mComboBox.checkedItems() for format in formats_to_check):
                        walidowanePliki_df.append(str(value['plikGML']))
                        wiersze_df.append("-")
                        opisyBledow_df.append("Błąd w składni pliku XML")
                        komunikatyBledow_df.append(opisBledu)
                        gmlid_df_w.append('Nie pozyskano gmlid')
                elif isinstance(errors, OSError):
                    opisBledu = re.sub(r'{[^}]+}', '', str(errors)) 
                    for key in frazy:
                        opisBledu = opisBledu.replace(key,frazy[key])
                    if any(format in self.dlg.mComboBox.checkedItems() for format in formats_to_check):
                        walidowanePliki_df.append(str(value['plikGML']))
                        wiersze_df.append("-")
                        opisyBledow_df.append("-")
                        komunikatyBledow_df.append(opisBledu)
                        gmlid_df_w.append('Nie pozyskano gmlid')
                else:
                    for error in errors:
                        opisBledu = re.sub(r'{[^}]+}', '', error.message) 
                        for key in frazy:
                            opisBledu = opisBledu.replace(key,frazy[key]) # tłumaczenie
                        msg = (
                            f"Walidacja pliku: {str(value['plikGML'])} z wynikiem negatywnym.\n"
                            f"- {config['KodyWalidacji'][error.type_name]}\n"
                            f"- wiersz: {str(error.line)}\n"
                            f"- komunikat błędu: {opisBledu}\n\n"
                        )
                        if any(format in self.dlg.mComboBox.checkedItems() for format in formats_to_check):
                            walidowanePliki_df.append(str(value['plikGML']))
                            wiersze_df.append(str(error.line))
                            opisyBledow_df.append(config['KodyWalidacji'][error.type_name])
                            komunikatyBledow_df.append(opisBledu)
                        gmlid_df_w.append(value['error'][errors])


    # otwarcie pliku raportu
    def otwarcieRaportuZWalidacji(self):
        for formatRaportu in self.dlg.mComboBox.checkedItems():
            path = (
                f'{sciezkaGML}/RaportBledow_'
                f'{str(nazwa_pliku)}_{timestr}'
                f'.{formatRaportu}'
            )
            if os.path.isfile(path):
                try:
                    os.startfile(path, 'open') # Windows
                except:
                    subprocess.call(('open', path)) # macOS


    # import plików GML do QGIS
    def importGML(self, zparsowanyPlik):
        global epsg
        gdal.SetConfigOption('GML_ATTRIBUTES_TO_OGR_FIELDS', 'YES')
        nazwaPliku = str(pathlib.Path(zparsowanyPlik).name)[:-4]
        root = QgsProject.instance().layerTreeRoot()
        typyGeometrii = {
            0: 'Geometry',
            1: 'Point',
            2: 'LineString',
            3: 'Polygon',
            4: 'MultiPoint',
            5: 'MultiLineString',
            6: 'MultiPolygon',
            8: 'CircularString',
            9: 'CompoundCurve',
            10: 'CurvePolygon',
            11: 'MultiCurve',
            12: 'MultiSurface',
            13: 'Curve',
            100: 'No Geometry',
            1001: 'PointZ',
            -2147483647: 'Point',
            -2147483648: 'Point'
            }
        groupaGlowna = getattr(self, "groupaGlowna", None)
        if groupaGlowna is None:
            QgsMessageLog.logMessage(
                "Brak self.groupaGlowna – przerwam importGML",
                "Walidator plików GML",
                Qgis.Warning
            )
            return
        warstwy = [x.GetName() for x in ogr.Open(zparsowanyPlik)]
        data_source = ogr.Open(zparsowanyPlik)
        typGeometriiWarstw = [x.GetGeomType() for x in ogr.Open(zparsowanyPlik)]
        for warstwa, feature_geom in zip(warstwy, typGeometriiWarstw):
            if warstwa in nazwaPliku:
                nazwaWarstwy = nazwaPliku
            else:
                nazwaWarstwy = nazwaPliku + '_' + warstwa
            if feature_geom == 100: # brak geometrii
                qgis_layer = QgsVectorLayer(
                    f'{zparsowanyPlik}|layername={warstwa}', 
                    nazwaWarstwy, 
                    'ogr'
                )
                QgsProject.instance().addMapLayer(qgis_layer, False)
                groupaGlowna.addLayer(qgis_layer)
                qgis_layer = None
            elif feature_geom == 0: # GeometryPropertyType
                tablica_typow_geometrii = [1,2,3]
                if warstwa in [
                        'EGB_ObrebEwidencyjny',
                        'EGB_Budynek',
                        'EGB_JednostkaEwidencyjna', # EGiB
                        'OT_Ogrodzenia',
                        'OT_BudynekNiewykazanyWEGIB', # BDOT500
                        'NG_NazwaGeograficznaSwiata',
                        'NG_NazwaGeograficznaRP' # PRNG
                    ]:
                    tablica_typow_geometrii = [4,5,6]
                
                for typGeometryPropertyType in tablica_typow_geometrii:
                    qgis_layer = None
                    qgis_layer = QgsVectorLayer(
                        (
                            f'{zparsowanyPlik}|layername={warstwa}'
                            f'|geometrytype={typyGeometrii[typGeometryPropertyType]}'
                        ), 
                        f'{nazwaWarstwy}_{str(typGeometryPropertyType)}', 
                        'ogr'
                    )
                    epsg = qgis_layer.crs().authid()
                    if not self.dlg.checkBox.isChecked():
                        attributes = qgis_layer.fields().names()
                        if 'koniecWersjiObiektu' in attributes:
                            exp = 'koniecWersjiObiektu is NULL'
                            qgis_layer = QgsVectorLayer(
                                (
                                    f'{zparsowanyPlik}|layername={warstwa}|geometrytype='
                                    f'{typyGeometrii[typGeometryPropertyType]}|subset={exp}'
                                ), 
                                f'{nazwaWarstwy}_{str(typGeometryPropertyType)}', 
                                'ogr'
                            )
                        elif 'koniecWersjaObiekt' in attributes:
                            exp = 'koniecWersjaObiekt is NULL'
                            qgis_layer = QgsVectorLayer(
                                (
                                    f'{zparsowanyPlik}|layername={warstwa}'
                                    f'|geometrytype={typyGeometrii[typGeometryPropertyType]}|subset={exp}'
                                ), 
                                f'{nazwaWarstwy}_{str(typGeometryPropertyType)}', 
                                'ogr'
                                )
                    if qgis_layer.featureCount() > 0:
                        QgsProject.instance().addMapLayer(qgis_layer, False)
                        groupaGlowna.addLayer(qgis_layer)
            else:
                qgis_layer = QgsVectorLayer(
                    (
                        f'{zparsowanyPlik}|layername={warstwa}'
                        f'|geometrytype={typyGeometrii[feature_geom]}'
                    ), 
                    nazwaWarstwy, 
                    'ogr'
                )
                epsg = qgis_layer.crs().authid()
                if not self.dlg.checkBox.isChecked():
                    attributes = qgis_layer.fields().names()
                    if 'koniecWersjiObiektu' in attributes:
                        exp = 'koniecWersjiObiektu is NULL'
                        qgis_layer = QgsVectorLayer(
                            (
                                f'{zparsowanyPlik}|layername={warstwa}'
                                f'|geometrytype={typyGeometrii[feature_geom]}|subset={exp}'
                             ), 
                            nazwaWarstwy, 
                            'ogr',
                    )
                    elif 'koniecWersjaObiekt' in attributes:
                        exp = 'koniecWersjaObiekt is NULL'
                        qgis_layer = QgsVectorLayer( 
                            (
                             f'{zparsowanyPlik}|layername={warstwa}'
                             f'|geometrytype={typyGeometrii[feature_geom]}|subset={exp}'
                          ), 
                         nazwaWarstwy, 
                         'ogr',
                 )
                if qgis_layer.featureCount() > 0:
                    QgsProject.instance().addMapLayer(qgis_layer, False)
                    groupaGlowna.addLayer(qgis_layer)
                    qgis_layer = None


    # wczytanie szablonu kontroli
    def wczytanieSzablonuKontroli(self):
        global modelKontroli, wersjaSzablonuKontroli, sumaKontrolaSchemat, szablonKontroliPath
        global sumaKontrolaSzablonKontroli, sumaKontrolnaWskazanyPlik, SumaKontrolnaDaneZrodlowe
        
        szablonKontroliPath = self.sciezkaDoWskazanegoSzablonuKontroli(
            self.dlg.comboBox_2.currentText(), 
            self.dlg.comboBox.currentText()
        )
        buf_size = 5000000  # Czytaj plik w blokach o rozmiarze 64KB
        crc = 0
        with open(xsdPath, 'rb') as f:
            while True:
                data = f.read(buf_size)
                if not data:
                    break
                crc = binascii.crc32(data, crc)
       
        sumaKontrolaSchemat = "%08X" % (crc & 0xFFFFFFFF) # tworzenie sumu kontrolnej dla schematu
        tree = et.parse(szablonKontroliPath)
        root = tree.getroot()
        tree1 = et.parse(xsdPath)
        root1 = tree1.getroot()
        wersjaSzablonuKontroli = root.get('version')
        wersjaSchematu = root1.get('version')
        filename = os.path.basename(xsdPath) # pobiera sama nazwę pliku
        metaSchemat = os.path.splitext(filename)[0] + " " +  wersjaSchematu
        crc = 0
        with open(szablonKontroliPath, 'rb') as f:
            while True:
                data = f.read(buf_size)
                if not data:
                    break
                crc = binascii.crc32(data, crc)
        sumaKontrolaSzablonKontroli = "%08X" % (crc & 0xFFFFFFFF) 
        # tworzenie sumu kontrolnej dla szablonu kontroli
        modelKontroli = QStandardItemModel()
        modelKontroli.setHorizontalHeaderLabels(['Lista kontroli'])
        self.dlg.treeView.setModel(modelKontroli)
        self.dlg.treeView.setUniformRowHeights(True)
        
        i = 0
        for grupaKontroli in root:
            parent = QStandardItem(grupaKontroli.get('name'))
            modelKontroli.appendRow(parent)
            parent.setCheckable(True)
            parent.setCheckState(0)
            for kontrola in grupaKontroli:
                child = QStandardItem(kontrola.get('name'))
                child.setData(kontrola.get('id'), 1)
                child.setData(kontrola.get('name'), 2)
                child.setData(kontrola.get('class'), 3)
                child.setData(kontrola.get('errorPhrase'), 4)
                for k in kontrola:
                    child.setData(k.get('typ'), 5)
                    child.setData(k.get('sql'), 6)
                child.setData(kontrola.get('class2'), 7)
                child.setData(kontrola.get('joinFieldName'), 8)
                child.setData(kontrola.get('targetFieldName'), 9)
                child.setData(kontrola.get('joinFieldNamesSubset'), 11)
                child.setCheckable(True)
                child.setCheckState(0)
                parent.appendRow([child])
            self.dlg.treeView.setFirstColumnSpanned(i, self.dlg.treeView.rootIndex(), True)
            i += 1
        modelKontroli.itemChanged.connect(self.zmianaStatusuKontroli)


    def zaznaczKontroleNaPodstawieDanych(self):
        try:
            self.odznaczWszystkieKontrole()
            files_str = ", ".join(files)
            for i in range(modelKontroli.rowCount()):
                item = modelKontroli.item(i)
                if item.checkState() in (0,1):
                    for child in range(item.rowCount()):
                        if files_str.__contains__(item.child(child).data(3)):
                            item.child(child).setCheckState(2)
        except Exception as e:
            print('błąd w zaznaczKontroleNaPodstawieDanych:',e)



    def zaznaczWszystkieKontrole(self):
        try:
            for i in range(modelKontroli.rowCount()):
                item = modelKontroli.item(i)
                if item.checkState() in (0,1):
                    item.setCheckState(2)
        except Exception as e:
             print('błąd w zaznaczWszystkieKontrole:',e)


    def odznaczWszystkieKontrole(self):
        try:
            for i in range(modelKontroli.rowCount()):
                item = modelKontroli.item(i)
                if item.checkState() in (1,2):
                    item.setCheckState(0)
        except Exception as e:
            print('błąd w odznaczWszystkieKontrole:',e)


    def zmianaStatusuKontroli(self, item):
        global blokady
        statusParent = item.checkState()
        if (
            not item.hasChildren() 
            and self.dlg.comboBox.currentText() == 'BDOT10k' 
            and (
                item.data(6).__contains__("Granice_powiatow") 
                or item.data(6).__contains__("czyObiektyWewnatrzPowiatu")
                or item.data(6).__contains__("minimalna") 
                or item.data(6).__contains__("fullCoverage") 
                or item.data(6).__contains__("minDlugosc") 
                or item.data(6).__contains__("kontrolaZgodnosciZDanymiGDOS")
            )
        ):
            blokady[2] = 0
            for i in range(self.dlg.treeView.model().rowCount()):
                parent_item = self.dlg.treeView.model().item(i)
                for j in range(parent_item.rowCount()):
                    child_item = parent_item.child(j)
                    if (
                            len(self.dlg.mQgsFileWidget_gp.filePath()) == 0 
                            and child_item.checkState() == 2 
                            and any(
                                keyword in child_item.data(6) 
                                for keyword in [
                                    "Granice_powiatow", 
                                    "czyObiektyWewnatrzPowiatu",
                                    "fullCoverage", 
                                    "minimalna", 
                                    "minDlugosc",
                                    "kontrolaZgodnosciZDanymiGDOS"
                                    ]
                            )
                        ):
                        blokady[2] = 1
                        self.dlg.button_box.buttons()[0].setEnabled(False)
                
        if (
                not item.hasChildren() 
                and self.dlg.comboBox.currentText() == 'BDOT10k' 
                and item.data(6).__contains__("Granice_gmin")
            ):
            blokady[3] = 0
            if len(self.dlg.mQgsFileWidget_gg.filePath()) == 0 and item.checkState() == 2:
               blokady[3] = 1
               self.dlg.button_box.buttons()[0].setEnabled(False)
               
        if (
                not item.hasChildren() 
                and self.dlg.comboBox.currentText() == 'BDOT10k' 
                and item.data(6).__contains__("Granice_jednostek_ewidencyjnych")
            ):
            blokady[4] = 0
            if len(self.dlg.mQgsFileWidget_gje.filePath()) == 0 and item.checkState() == 2:
                blokady[4] = 1
                self.dlg.button_box.buttons()[0].setEnabled(False)
                
        if (
                not item.hasChildren() 
                and self.dlg.comboBox.currentText() == 'BDOT10k' 
                and item.data(6).__contains__("(gml,gml)")
            ):
            blokady[5] = 0
            for j in range(item.parent().rowCount()):
                if (
                        len(self.dlg.mQgsFileWidget_dz.filePath()) == 0 
                        and item.parent().child(j).checkState() == 2 
                        and item.parent().child(j).data(6).__contains__("(gml,gml)")
                    ):
                    blokady[5] = 1
                    self.dlg.button_box.buttons()[0].setEnabled(False)
            
        if (
                not item.hasChildren() 
                and self.dlg.comboBox.currentText() == 'BDOT10k' 
                and item.data(6).__contains__("prng_miejscowosci")
            ):
            blokady[6] = 0
            for j in range(item.parent().rowCount()):
                if (
                        len(self.dlg.mQgsFileWidget_prng_m.filePath()) == 0 
                        and item.parent().child(j).checkState() == 2 
                        and item.parent().child(j).data(6).__contains__("prng_miejscowosci")
                    ):
                    blokady[6] = 1
                    self.dlg.button_box.buttons()[0].setEnabled(False)
                
        if (
                not item.hasChildren() 
                and self.dlg.comboBox.currentText() == 'BDOT10k' 
                and item.data(6).__contains__("prng_obiektyfizjograficzne")
            ):
            blokady[7] = 0
            for j in range(item.parent().rowCount()):
                if (
                        len(self.dlg.mQgsFileWidget_prng_o.filePath()) == 0 
                        and item.parent().child(j).checkState() == 2 
                        and item.parent().child(j).data(6).__contains__("prng_obiektyfizjograficzne")
                    ):
                    blokady[7] = 1
                    self.dlg.button_box.buttons()[0].setEnabled(False)
                    
        if (
                not item.hasChildren() 
                and self.dlg.comboBox.currentText() == 'BDOT10k' 
                and item.data(6).__contains__("tereny_chronione")
            ):
            blokady[9] = 0
            for j in range(item.parent().rowCount()):
                if (
                        len(self.dlg.mQgsFileWidget_tc.filePath()) == 0 
                        and item.parent().child(j).checkState() == 2 
                        and item.parent().child(j).data(6).__contains__("tereny_chronione")
                   ):
                   blokady[9] = 1
                   self.dlg.button_box.buttons()[0].setEnabled(False)
                
        if not item.hasChildren() and self.dlg.comboBox.currentText() == 'BDOT10k' and item.data(6).__contains__("ulic_gus"):
            blokady[8] = 0
            for j in range(item.parent().rowCount()):
                 if (
                         len(self.dlg.mQgsFileWidget_ulic.filePath()) == 0 
                         and item.parent().child(j).checkState() == 2 
                         and item.parent().child(j).data(6).__contains__("ulic_gus")
                     ):
                     blokady[8] = 1
                     self.dlg.button_box.buttons()[0].setEnabled(False)
        if (
                not item.hasChildren() 
                and self.dlg.comboBox.currentText() == 'BDOT10k' 
                and item.data(6).__contains__("simc_gus")
            ):
            blokady[10] = 0
            for j in range(item.parent().rowCount()):
                 if (
                         len(self.dlg.mQgsFileWidget_simc.filePath()) == 0 
                         and item.parent().child(j).checkState() == 2 
                         and item.parent().child(j).data(6).__contains__("simc_gus")
                    ):
                     blokady[10] = 1
                     self.dlg.button_box.buttons()[0].setEnabled(False)
        
        if sum(blokady) == 0:
            self.dlg.button_box.buttons()[0].setEnabled(True)
        
        if item.rowCount() > 0:
            for j in range(item.rowCount()):
                if statusParent == 2:
                    item.child(j).setCheckState(2)
                if statusParent == 0:
                    item.child(j).setCheckState(0)
        else:
            suma = 0
            for j in range(item.parent().rowCount()):
                suma += item.parent().child(j).checkState()
            if suma == 0:
                item.parent().setCheckState(0)
            elif suma == item.parent().rowCount() * 2:
                item.parent().setCheckState(2)
            else:
                item.parent().setCheckState(1)


   # kontrola atrybutów
    def kontrolaAtrybutow(self):
        if self.dlg.comboBox.currentText() != 'EGIB':
            self.kontrolaAtrybutow_inne()
        else:
            slownikBledow.clear()
            komunikatyBledowKontroli_df.clear()
            kontrolowanePliki_df.clear()
            gmlid_df_k.clear()
            klasy_df.clear()
            grupyKontroli_df.clear()
            self.idkontroli_LiczbaBledow.clear()
            self.kontrolaAtrybutow_EGIB()
        
    def kontrolaAtrybutow_inne(self):
        global liczbaKontroliWykonanych, progress, slownikBledow, warstwyBledowKontroliAtrybutow, kontroleWykonaniePojedyncze
        global idkontroli_LiczbaBledow, warstwa, kontrolePojedynczyKomunikat, idKontroli
        geometryType = {0:'Point',1:'Line',2:'Polygon'}
        kontrolePojedynczyKomunikat = {"topo_e3_k6":False,"topo_e4_k27":False,"topo_e4_k25":False}
        QgsProjectInstance = QgsProject().instance()
        QApplication.processEvents()
        
        for i in range(modelKontroli.rowCount()):
            parent = modelKontroli.item(i)
            if parent.checkState() in (1,2):
                for j in range(parent.rowCount()):
                    if (
                            parent.child(j).checkState() == 2 
                            and parent.child(j).data(1) != '' 
                            and parent.child(j).data(2) != '' 
                            and parent.child(j).data(3) != '' 
                            and parent.child(j).data(4) != '' 
                            and parent.child(j).data(5) in (
                                'QgsExpression',
                                'QgsExpressionWithJoin',
                                'pythonFunction',
                                'PyExpression',
                                'MgrExpression',
                                ) 
                            and parent.child(j).data(6) != ''
                        ):
                        nazwaKontroli = parent.data(2)
                        errorPhrase = parent.child(j).data(4)
                        idKontroli = parent.child(j).data(1)
                        sqltxt = parent.child(j).data(6)
                        sqltxt = sqltxt.replace("&gt;",">")
                        sqltxt = sqltxt.replace("&lt;","<")
                        klasa = parent.child(j).data(3)
                        klasaDoRaportowania = klasa
                        
                        if len(plikiZparsowane) == 1:
                            parsedFileName = str(pathlib.Path(plikiZparsowane[0]).name)
                            parsedFileBaseName = parsedFileName[:-4]
                        
                        layers_in_group = [node.layer() for node in self.groupaGlowna.children() if isinstance(node, QgsLayerTreeLayer)]
                        for w in layers_in_group:
                            if klasa in w.name() and not kontrolePojedynczyKomunikat.get(idKontroli, False):
                                nazwaWarstwy = w.name()
                                zparsowanyPlik = None
                                if len(plikiZparsowane) > 0:
                                    for plikZparsowany in plikiZparsowane:
                                        parsedFileName_TMP = str(pathlib.Path(plikZparsowany).name)
                                        if klasa in parsedFileName_TMP and nazwaWarstwy in parsedFileName_TMP:
                                            zparsowanyPlik = plikZparsowany
                                            parsedFileName = parsedFileName_TMP
                                            parsedFileBaseName = parsedFileName[:-4]
                                            break
                                    if zparsowanyPlik is None:
                                        zparsowanyPlik = plikZparsowany
                                if self.dlg.comboBox.currentText() == 'BDOT10k':
                                    teryt = parsedFileName[:-15][-4:]
                                else:
                                    teryt = None
                                try:
                                    for warstwaWsqltext in re.findall(r"layer:='(.*?)'", sqltxt):
                                        sqltxt = sqltxt.replace(
                                            f"layer:='{warstwaWsqltext}'",
                                            f"layer:='{parsedFileName[:-13]}{warstwaWsqltext}'_'{warstwaWsqltext}"
                                        )
                                except Exception as e:
                                    print(f"błąd przy tworzeniu warstwy: {e}")
                                    
                                try:
                                    layerL1 = QgsProjectInstance.mapLayersByName(nazwaWarstwy)[0]
                                except:
                                    layerL1 = None
                                
                                if parent.child(j).data(5) in (
                                        'QgsExpression',
                                        'QgsExpressionWithJoin',
                                        'pythonFunction',
                                        'PyExpression',
                                        'MgrExpression'
                                        ) and layerL1 is not None:
                                    try:
                                      
                                        czyWarstwaIstnieje = False
                                        for lyr in QgsProjectInstance.mapLayers().values():
                                            if lyr.name() == nazwaWarstwy:
                                                if czyWarstwaIstnieje:
                                                    QgsProject.instance().removeMapLayer(lyr)
                                                else:
                                                    czyWarstwaIstnieje = True
                                        if not czyWarstwaIstnieje:
                                            liczbaKontroliWykonanych += 1
                                            progress.setValue(liczbaKontroliWykonanych)
                                            continue
                                        layer = QgsProjectInstance.mapLayersByName(nazwaWarstwy)[0]
                                        requestFeatures = []
                                        if parent.child(j).data(5) in ('QgsExpression','QgsExpressionWithJoin'):
                                            start_time = datetime.now()
                                            request = QgsFeatureRequest(QgsExpression(sqltxt))
                                            requestFeatures = layer.getFeatures(request)
                                            end_time = datetime.now()
                                            czas_przetwarzania = end_time - start_time
                                            if klasa == 'OT':
                                                QgsMessageLog.logMessage(
                                                    f'{parent.child(j).data(1)} - {klasa + parsedFileName[-11:-4]} - {czas_przetwarzania}', 
                                                    tag="Walidator plików GML",
                                                    level=Qgis.Info
                                                    )
                                            else:
                                                QgsMessageLog.logMessage(
                                                    f'{parent.child(j).data(1)} - {klasa} - {czas_przetwarzania}', 
                                                    tag="Walidator plików GML", 
                                                    level=Qgis.Info
                                                    )
                                        else:
                                            start_time = datetime.now()
                                            layerTMP = QgsProjectInstance.mapLayersByName(nazwaWarstwy)
                                            if sqltxt.count('(teryt)') > 0:
                                                requestFeatures = globals().get(sqltxt.replace('(teryt)', ''))(layerTMP[0], teryt)
                                            elif sqltxt.count('(gml)') > 0:
                                                requestFeatures = globals().get(sqltxt.replace('(gml)', ''))(layerTMP[0], lxml.etree.parse(zparsowanyPlik))
                                            elif sqltxt.count('(gml,klasa)') > 0:
                                                requestFeatures = globals().get(sqltxt.replace('(gml,klasa)', ''))(layerTMP[0], lxml.etree.parse(zparsowanyPlik), klasa)
                                            elif sqltxt.count('(gml,gml)') > 0:
                                                plikGMLzrodlowy = self.zwrocPlikZrodlowy(parsedFileName[-11:-4])
                                                if plikGMLzrodlowy is not None:
                                                    requestFeatures = globals().get(sqltxt.replace('(gml,gml)', ''))(layerTMP[0], plikGMLzrodlowy, zparsowanyPlik)
                                                else:
                                                    requestFeatures = []
                                            elif '(ulic_gus)' in sqltxt:
                                                requestFeatures = globals().get(sqltxt.replace('(ulic_gus)', ''))(layerTMP[0], ulic_gus)
                                            elif '(ulic_gus,simc_gus)' in sqltxt:
                                                requestFeatures = globals().get(sqltxt.replace('(ulic_gus,simc_gus)', ''))(layerTMP[0], ulic_gus, simc_gus)
                                            elif '(prng_obiektyfizjograficzne)' in sqltxt:
                                                requestFeatures = globals().get(sqltxt.replace('(prng_obiektyfizjograficzne)', ''))(layerTMP[0], prng_obiektyfizjograficzne, klasa)
                                            elif '(prng_miejscowosci)' in sqltxt:
                                                requestFeatures = globals().get(sqltxt.replace('(prng_miejscowosci)', ''))(layerTMP[0], prng_miejscowosci, klasa)
                                            elif '(tereny_chronione)' in sqltxt:
                                                requestFeatures = globals().get(sqltxt.replace('(tereny_chronione)', ''))(layerTMP[0], tereny_chronione, klasa)
                                            elif parent.child(j).data(5) == 'PyExpression':
                                                requestFeatures = pyExpression(layerTMP[0], sqltxt)
                                            elif parent.child(j).data(5) == 'MgrExpression':
                                                requestFeatures = mgrExpression(layerTMP[0], lxml.etree.parse(zparsowanyPlik), sqltxt)
                                            elif 'kontrolaFormatuAtrybutuWysokosc' in sqltxt:
                                                requestFeatures = kontrolaFormatuAtrybutuWysokosc(
                                                    layerTMP[0], 
                                                    sqltxt.replace('kontrolaFormatuAtrybutuWysokosc',''), 
                                                    lxml.etree.parse(zparsowanyPlik)
                                                    )
                                            elif idKontroli in kontroleWykonaniePojedyncze:
                                                if not kontroleWykonaniePojedyncze[idKontroli]:
                                                    if klasa == 'OT_PT':
                                                        if not kontroleWykonaniePojedyncze[idKontroli]:
                                                            requestFeatures = fullCoverage(layerTMP[0])
                                                            kontroleWykonaniePojedyncze[idKontroli] = True
                                                        else:
                                                            continue
                                                    else:
                                                        requestFeatures = kompletnoscPlikowBDOT10k(files)
                                                        kontroleWykonaniePojedyncze[idKontroli] = True
                                            else:
                                                requestFeatures = globals().get(sqltxt)(layerTMP[0])
                                            
                                            end_time = datetime.now()
                                            czas_przetwarzania = end_time - start_time
                                            if klasa == 'OT':
                                                QgsMessageLog.logMessage(
                                                    f'{parent.child(j).data(1)} - {klasa + parsedFileName[-11:-4]} - {czas_przetwarzania}', 
                                                    tag="Walidator plików GML", 
                                                    level=Qgis.Info
                                                    )
                                            else:
                                                QgsMessageLog.logMessage(
                                                    f'{parent.child(j).data(1)} - {klasa} - {czas_przetwarzania}', 
                                                    tag="Walidator plików GML", 
                                                    level=Qgis.Info
                                                    )
                                        
                                        selected_features = []  # lista z wybranymi obiektami
                                        
                                        liczbaBledow = 0
                                        for feature in requestFeatures:
                                            if idKontroli not in 'topo_e3_k6' or not kontrolePojedynczyKomunikat[idKontroli]:
                                                liczbaBledow += 1
                                                gmlid = feature['gml_id'] if 'gml_id' in feature.fields().names() else 'nie dotyczy'
                                                # Sprawdzenie czy klucz errorPhrase już istnieje w słowniku
                                                if errorPhrase not in slownikBledow:
                                                    slownikBledow[errorPhrase] = []
                                                else:
                                                    slownikBledow[errorPhrase].append(feature)
                                                typ_geometrii = QgsWkbTypes.displayString(feature.geometry().wkbType())
                                                
                                                if typ_geometrii == 'Point':
                                                    warstwa = warstwyBledowKontroliAtrybutow['Point']
                                                elif typ_geometrii in (
                                                        'LineString', 
                                                        'CompoundCurve', 
                                                        'CircularString', 
                                                        'MultiLineString'
                                                    ):
                                                    warstwa = warstwyBledowKontroliAtrybutow['LineString']
                                                elif typ_geometrii in (
                                                        'Polygon', 
                                                        'CurvePolygon', 
                                                        'MultiPolygon'
                                                    ):
                                                    warstwa = warstwyBledowKontroliAtrybutow['Polygon']
                                                
                                                if idKontroli in ['topo_e5_k1']:
                                                    klasaDoRaportowania = gmlid
                                                    gmlid = 'nie dotyczy'
                                                if klasa == 'OT':
                                                    klasaDoRaportowania = 'OT' + parsedFileName[-11:-4]
                                                if klasa == 'OT_TC':
                                                    klasaDoRaportowania = 'OT' + parsedFileName[-11:-4]
                                                if klasa == 'OT_SW':
                                                    klasaDoRaportowania = 'OT' + parsedFileName[-11:-4]
                                                if klasa == 'OT_SK':
                                                    klasaDoRaportowania = 'OT' + parsedFileName[-11:-4]
                                                if klasa == 'OT_BU':
                                                    klasaDoRaportowania = 'OT' + parsedFileName[-11:-4]
                                                if klasa == 'OT_SU':
                                                    klasaDoRaportowania = 'OT' + parsedFileName[-11:-4]
                                                if klasa == 'OT_OI':
                                                    klasaDoRaportowania = 'OT' + parsedFileName[-11:-4]
                                                if klasa == 'OT_BUHD':
                                                    klasaDoRaportowania = 'OT' + parsedFileName[-11:-4]
                                                if klasa == 'OT_BUWT':
                                                    klasaDoRaportowania = 'OT' + parsedFileName[-11:-4]
                                                if klasa == 'OT_PT':
                                                    klasaDoRaportowania = 'nie dotyczy'
                                                    gmlid = 'nie dotyczy'
                                                if feature['gml_id'].__contains__("|"):
                                                    gmlid = feature['gml_id'].split("|")[0]
                                                    errorPhrase_fin = errorPhrase + feature['gml_id'].split("|")[1]
                                                else:
                                                    errorPhrase_fin = errorPhrase
                                                
                                                feature.setAttributes([gmlid, klasaDoRaportowania, errorPhrase_fin])
                                                if typ_geometrii != 'Unknown':
                                                    warstwa.dataProvider().addFeatures([feature])
                                                    QgsProject.instance().addMapLayer(warstwa)
                                                
                                            if idKontroli not in kontrolePojedynczyKomunikat or not kontrolePojedynczyKomunikat[idKontroli]:
                                                komunikatyBledowKontroli_df.append(errorPhrase_fin)
                                                kontrolowanePliki_df.append(parsedFileName)
                                                gmlid_df_k.append(gmlid)
                                                klasy_df.append(klasaDoRaportowania)
                                                grupyKontroli_df.append(nazwaKontroli)
                                                if idKontroli in kontrolePojedynczyKomunikat and not kontrolePojedynczyKomunikat[idKontroli]:
                                                    kontrolePojedynczyKomunikat[idKontroli] = True
                                        
                                        if liczbaBledow > 0:
                                            if parent.child(j).data(1) not in idkontroli_LiczbaBledow:
                                                idkontroli_LiczbaBledow[parent.child(j).data(1)] = liczbaBledow
                                            else:
                                                idkontroli_LiczbaBledow[parent.child(j).data(1)] += liczbaBledow
                                        
                                    except Exception as e:
                                        print(f'Błąd przy wykonaniu {parent.child(j).data(1)}: {e}')
                                    liczbaKontroliWykonanych += 1
                                    progress.setValue(liczbaKontroliWykonanych)


    def kontrolaWybranychFormatowRaportow(self, txt):
        global blokady
        if txt == []:
            QMessageBox.critical(
                QMessageBox(),
                'Formaty raportów',
                'Musi być wybrany co najmniej jeden format raportu.', 
                QMessageBox.Ok
            )
            blokady[1] = 1
            self.dlg.button_box.buttons()[0].setEnabled(False)
        else:
            blokady[1] = 0
            if sum(blokady) == 0:
                self.dlg.button_box.buttons()[0].setEnabled(True)


    def zwrocPlikZrodlowy(self, klasa):
        plikGMLzrodlowy = None
        if len(sciezkiPlikowZrodlowych) > 0:
            for sciezkaPlikuZrodlowego in sciezkiPlikowZrodlowych:
                    if klasa in sciezkaPlikuZrodlowego:
                        if 'plikZIPzrodlowy' in globals():
                            plikGMLzrodlowy = plikZIPzrodlowy.extract(
                                sciezkaPlikuZrodlowego,
                                os.path.join(
                                    sciezkaGML,
                                    "daneZrodlowe"
                                    )
                                )
                        else:
                             # gdy użytkownik podał pojedynczy .gml/.xml
                             plikGMLzrodlowy = sciezkaPlikuZrodlowego
                        break  
        return plikGMLzrodlowy