# -*- coding: utf-8 -*-
"""
Copyright (c) 2016 Biuro Urządzania Lasu i Geodezji Leśnej

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), 
to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, 
and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 
OTHER DEALINGS IN THE SOFTWARE.
"""
from certifi.core import where
from _ast import Try

"""Moduł kontroli warstw z tabelami bazy danych"""
#Marcin Śliwa
from Mapa_PU.kontroler.mapa import Mapa
from Mapa_PU.model.baza_danych import Baza
from Mapa_PU.model.wynik_kontroli import WynikKontroli,Result,TypeOfControl
from queue import Queue
from Mapa_PU.model.konfiguracja import *
from Mapa_PU.kontroler import komunikaty
import datetime
import os
import codecs
from qgis.core import *
from PyQt5 import QtCore, QtGui
import traceback
from PyQt5.QtWidgets import QProgressBar
from qgis.gui import QgsMessageBarItem
from Mapa_PU.widok.pasek_wiadomosci import PasekWiadomosc
from lxml.etree import ElementTree
from Mapa_PU.kontroler.excel import Excel,ExcelError
from Mapa_PU.model import date_helper
import processing

class Kontroluj():
    """wywołanie kontroli w wątku"""
    def __init__(self,root,swdl_version,Mapa,Konfiguracja,iface,wersja):
        """konstruktor"""
        self.iface=iface
        self.mapa=Mapa
        self.konfiguracja=Konfiguracja
        self.flaga=False
        self.root=root
        self.wersja=wersja
        self.swdl_version=swdl_version
        
        
    def start(self):
        """Uruchomienie wądku kontroli"""
        self.flaga=False
        kontrola = KontrolujDane(self.root,self.swdl_version,self.mapa,self.konfiguracja,self.iface,self.wersja)
        ret=kontrola.uruchom()
        self.obslugaZakonczenia(ret)
      
            
    def obslugaZakonczenia(self, ret):
        """Zakończenie kontroli
        :param ret:wynik kontroli
        """
     
        self.flaga=True
        
        komunikaty.usun()
        if ret is not None:
            message="{}\n{}".format(ret[0],ret[1])    
            dec=komunikaty.pytanie_zamknij_pokaz_raport_txt_xls(u'Zakończono kontrolę.', (u"Zakończono kontrolę spójności.  Szczegóły zostały zapisane do pliku raportu '\n%s'" % message))
            
            if dec==1:
                #uruchomienie raportu
                os.startfile(ret[0])
            if dec==2:
                os.startfile(ret[1])
        else:
            komunikaty.informacja(u"Anuluj",u'Anulowano wykonywanie kontroli danych')
         
        
        
    def obslugaBledu(self, e, exception_string):
        """Obsługa błędu kontroli
        :param e:błąd
        :param exception_string:komunikat błędu
        """
      
        #self.iface.messageBar().pushMessage(u'Bląd %s.' % exception_string, level=self.iface.messageBar().CRITICAL)
        self.iface.messageBar().pushCritical(u'Błąd',u'%s.' % exception_string)
      
        
    def usunPanel(self):
        """Przerwanie kontroli na skutek usunięcia pasak postępu"""
      
        if self.flaga==True:
            return
        self.kontrola.przerwij()

class KontrolujDane(QtCore.QObject):
    """Implementacja kontroli danych"""
    
    zakonczenie = QtCore.pyqtSignal(object)
    blad = QtCore.pyqtSignal(Exception, basestring)
    #postep = QtCore.pyqtSignal(float)
    #komunikat=QtCore.pyqtSignal('QString')
    
    
    def __init__(self,root,swdl_version ,Mapa,Konfiguracja,iface,wersja):
        """Konstruktor"""
        QtCore.QObject.__init__(self)
        self.__iface=iface
        self.__mapa=Mapa
        self.__konfiguracja=Konfiguracja
        self.kontrole=[]
        self.przerwanie = False
        self.daneW=None
        self.daneB=None
        self.__root=root
        self.__wersja=wersja
        self.__swdl_version=swdl_version
        #TODO nie może być tu bo wystawia na swiat 
        #self.komunikat,self.postep=komunikaty.pasek_postepu(u'Kontrola danych')
    
    def kontrola_ob_podst(self,baza:Baza,pasek_wiadomosci:PasekWiadomosc,przerwanie=None)->[]:
        """Kontrola obiektów podstawowych PU019"""
        try:
            nazwa=u'Kontrola adresów obiektów podstawowych'
            nazwaWarstwy='O_PODST'
            pola=('ADR_BDL','ADR_ADM','NR_EW','NR_KONT')
            sql="SELECT [F_ARODES]![ADRESS_FOREST] & ';' & [F_PARCEL]![COUNTY_CD] & '-' & [F_PARCEL]![DISTRICT_CD] & '-' & [F_PARCEL]![MUNICIPALITY_CD] & '-' & [F_PARCEL]![COMMUNITY_CD] & ';' & [F_PARCEL]![PARCEL_NR] & ';' & [F_PARCEL_LAND_USE]![SHAPE_NR] AS ADRES FROM (F_PARCEL INNER JOIN F_PARCEL_LAND_USE ON F_PARCEL.PARCEL_INT_NUM = F_PARCEL_LAND_USE.PARCEL_INT_NUM) INNER JOIN (F_ARODES INNER JOIN F_AROD_LAND_USE ON F_ARODES.ARODES_INT_NUM = F_AROD_LAND_USE.ARODES_INT_NUM) ON (F_PARCEL.PARCEL_INT_NUM = F_AROD_LAND_USE.PARCEL_INT_NUM) AND (F_PARCEL_LAND_USE.SHAPE_NR = F_AROD_LAND_USE.SHAPE_NR) AND (F_PARCEL_LAND_USE.PARCEL_INT_NUM = F_AROD_LAND_USE.PARCEL_INT_NUM) WHERE (((F_ARODES.ADRESS_VALID)='T'));"
            warstwa=self.__mapa.warstwaRejestr(nazwaWarstwy)
            #wczytanie warstwy
            self.daneW=self.daneWarstwa(pola,pasek_wiadomosci,przerwanie,warstwa)
            #koniec wczytywania
            #wczytanie bazy
            self.daneB=self.daneBaza(baza, sql,pasek_wiadomosci,przerwanie)            
            #koniec wczytania bazy
            #kontrola
            kontrola=self.kontroluj(self.daneW,self.daneB, nazwa, nazwaWarstwy)
            return kontrola
        except Exception as e:
            raise e
    
    def kontrola_pow(self,baza:Baza,pasek_wiadomosci:PasekWiadomosc,przerwanie=None):
        """Kontrola adresów pododdziałów PU020"""
        try:
            nazwa=u'Kontrola adresów pododdziałów'
            nazwaWarstwy='POW'
            pola=('ADR_BDL',)
            sql="SELECT F_ARODES.ADRESS_FOREST FROM F_ARODES WHERE (((F_ARODES.ADRESS_VALID)='t') AND ((F_ARODES.ARODES_TYP_CD)='WYDZIEL'));"
            warstwa=self.__mapa.warstwaRejestr(nazwaWarstwy)
            #wczytanie warstwy
            self.daneW=self.daneWarstwa(pola,pasek_wiadomosci,przerwanie,warstwa)
            #koniec wczytywania
            #wczytanie bazy
            self.daneB=self.daneBaza(baza, sql,pasek_wiadomosci,przerwanie)            
            #koniec wczytania bazy
            #kontrola
            
            #Kontrola
            
            kontrola=self.kontroluj(self.daneW,self.daneB, nazwa, nazwaWarstwy)
            return kontrola
        except Exception as e:
            raise e
    
    def kontrola_oddzial(self,baza:Baza,pasek_wiadomosci:PasekWiadomosc,przerwanie=None):
        """Kontrola adresów oddziałów"""
        try:
            nazwa=u'Kontrola adresów oddziałów'
            nazwaWarstwy='ODDZIAL'
            pola=('ADR_BDL',)
            sql="SELECT LEFT(F_ARODES.ADRESS_FOREST,23) FROM F_ARODES WHERE (((F_ARODES.ADRESS_VALID)='t') AND ((F_ARODES.ARODES_TYP_CD)='ODDZ'));"
            warstwa=self.__mapa.warstwaRejestr(nazwaWarstwy)
            #wczytanie warstwy
            self.daneW=self.daneWarstwa(pola,pasek_wiadomosci,przerwanie,warstwa)
            #koniec wczytywania
            #wczytanie bazy
            self.daneB=self.daneBaza(baza, sql,pasek_wiadomosci,przerwanie)            
            #koniec wczytania bazy
            #Kontrola
            kontrola=self.kontroluj(self.daneW,self.daneB, nazwa, nazwaWarstwy)
            return kontrola
        except Exception as e:
            raise e
    
    def kontrola_pnsw(self,baza:Baza,pasek_wiadomosci:PasekWiadomosc,przerwanie=None):
        """Kontrola adresów PNSW PU022"""
        try:
            nazwa=u'Kontrola adresów PNSW'
            nazwaWarstwy='PNSW'
            pola=('ADR_BDL', 'KOD_PNSW','NR_PNSW')
            sql="SELECT [F_ARODES]![ADRESS_FOREST] & ';' & [F_AROD_SPEC_AREA]![SPECIAL_AREA_CD] & ';' & [F_AROD_SPEC_AREA]![AROD_SPAREA_ORDER] AS ADRES FROM F_ARODES INNER JOIN F_AROD_SPEC_AREA ON F_ARODES.ARODES_INT_NUM = F_AROD_SPEC_AREA.ARODES_INT_NUM WHERE (((F_ARODES.ADRESS_VALID)='t'));"
            warstwa=self.__mapa.warstwaRejestr(nazwaWarstwy)
            #wczytanie warstwy
            self.daneW=self.daneWarstwa(pola,pasek_wiadomosci,przerwanie,warstwa)
            #koniec wczytywania
            #wczytanie bazy
            self.daneB=self.daneBaza(baza, sql,pasek_wiadomosci,przerwanie)            
            #koniec wczytania bazy
            #Kontrola
            kontrola=self.kontroluj(self.daneW,self.daneB, nazwa, nazwaWarstwy)
            return kontrola
        except Exception as e:
            raise e
    
    def kontrola_osob_prz(self,baza:Baza,pasek_wiadomosci:PasekWiadomosc,przerwanie=None):
        """Kontrola osobliwości przyrodniczych PU023"""
        try:
            nazwa=u'Kontrola osobliwości przyrodniczych'
            nazwaWarstwy=('OS_PKT','OS_POW')
            pola=('ADR_BDL', 'KOD_OSOBL', 'NR_OSOBL')
            sql="SELECT [F_ARODES]![ADRESS_FOREST] & ';' & [F_AROD_PHENOMENA]![PHENOMENA_CD] & ';' & [F_AROD_PHENOMENA]![PHEN_RANK_ORDER] AS ADRES FROM F_AROD_PHENOMENA INNER JOIN F_ARODES ON F_AROD_PHENOMENA.ARODES_INT_NUM = F_ARODES.ARODES_INT_NUM WHERE (((F_ARODES.ADRESS_VALID)='t'));"
            warstwy=self.__mapa.warstwyRejestr(*nazwaWarstwy)
            #wczytanie warstwy
            self.daneW=self.daneWarstwa(pola,pasek_wiadomosci,przerwanie,*warstwy)
            #koniec wczytywania
            #wczytanie bazy
            self.daneB=self.daneBaza(baza, sql,pasek_wiadomosci,przerwanie)            
            #koniec wczytania bazy
            #Kontrola
            kontrola=self.kontroluj(self.daneW,self.daneB, nazwa, nazwaWarstwy)
            return kontrola
        except Exception as e:
            raise e
    
    def kontrola_f_parameter(self,baza:Baza,pasek_wiadomosci:PasekWiadomosc)->str:
        """Kontroluje czy w bazie jest wpisana nazwa obiektu"""
        try:
            nazwa='Kontrola nazwy obiektu w tabeli F_PARAMETER'
            sql="SELECT F_PARAMETER.ObjectFullName FROM F_PARAMETER;"
            #wczytanie bazy
            data=self.daneBaza(baza, sql,pasek_wiadomosci,None) 
            wynik=WynikKontroli(nazwa,'Brak nazwy obiektu w tabeli','','')
            wynik.bledyWarstwy=[] 
            wynik.bledyBazy=[]
            if len(data)>0:
                if data[0]==None:
                    wynik.bledyBazy=[' F_PARAMETER',]
                    wynik.add_result(Result(nazwa,'Brak nazwy obiektu w tabeli',[' F_PARAMETER',],TypeOfControl.DATA))
            else:
                wynik.bledyBazy=[' F_PARAMETER',]
                wynik.add_result(Result(nazwa,'Brak nazwy obiektu w tabeli',[' F_PARAMETER',],TypeOfControl.DATA))
            return wynik
        except Exception as e:
            raise e
    
    def kontrola_f_measure(self,baza:Baza,pasek_wiadomosci:PasekWiadomosc):
        """Kontrola opisów wskazówek"""
        try:
            nazwa=u'Kontrola opisów wskazówek'
            sql="SELECT F_AROD_CUE.MEASURE_CD FROM F_ARODES INNER JOIN (F_MEASURE INNER JOIN F_AROD_CUE ON F_MEASURE.measure_cd = F_AROD_CUE.MEASURE_CD) ON F_ARODES.ARODES_INT_NUM = F_AROD_CUE.ARODES_INT_NUM WHERE (((F_MEASURE.measure_name) Is Null)) GROUP BY F_AROD_CUE.MEASURE_CD;"
            #wczytanie bazy
            daneB=self.daneBaza(baza, sql,pasek_wiadomosci,None)    
            wynik=WynikKontroli(nazwa,'- brak nazwy wskazówki','','')
            wynik.bledyWarstwy=[] 
            wynik.bledyBazy=[]
            if len(daneB)>0:
                wynik.bledyBazy=daneB
                wynik.add_result(Result(nazwa,'brak nazwy wskazówki',daneB,TypeOfControl.DATA))
            return wynik
        except Exception as e:
            raise e
    
    def kontrola_f_parcel(self,baza:Baza,pasek_wiadomosci:PasekWiadomosc,przerwanie=None):
        """Kontrola działek z bazą danych, test sprawdza czy wszystkie działki w bazie powiązane z wydzieleniami mają geometrię"""
        try:
            nazwa=u'Kontrola działek ewidencyjnych'
            sql="SELECT distinct [F_COUNTY].[COUNTY_CD] & '-' & [F_DISTRICT].[DISTRICT_CD] & '-' & [F_MUNICIPALITY].[MUNICIPALITY_CD] & '-' & [F_COMMUNITY].[COMMUNITY_CD] & ';' & [F_PARCEL].[PARCEL_NR] AS ADR_ADM FROM ((F_COUNTY INNER JOIN F_DISTRICT ON F_COUNTY.COUNTY_CD = F_DISTRICT.COUNTY_CD) INNER JOIN F_MUNICIPALITY ON (F_DISTRICT.DISTRICT_CD = F_MUNICIPALITY.DISTRICT_CD) AND (F_DISTRICT.COUNTY_CD = F_MUNICIPALITY.COUNTY_CD)) INNER JOIN (F_COMMUNITY INNER JOIN (F_ARODES INNER JOIN (F_PARCEL INNER JOIN F_AROD_LAND_USE ON F_PARCEL.PARCEL_INT_NUM = F_AROD_LAND_USE.PARCEL_INT_NUM) ON F_ARODES.ARODES_INT_NUM = F_AROD_LAND_USE.ARODES_INT_NUM) ON (F_COMMUNITY.COMMUNITY_CD = F_PARCEL.COMMUNITY_CD) AND (F_COMMUNITY.MUNICIPALITY_CD = F_PARCEL.MUNICIPALITY_CD) AND (F_COMMUNITY.DISTRICT_CD = F_PARCEL.DISTRICT_CD) AND (F_COMMUNITY.COUNTY_CD = F_PARCEL.COUNTY_CD)) ON (F_MUNICIPALITY.MUNICIPALITY_CD = F_COMMUNITY.MUNICIPALITY_CD) AND (F_MUNICIPALITY.DISTRICT_CD = F_COMMUNITY.DISTRICT_CD) AND (F_MUNICIPALITY.COUNTY_CD = F_COMMUNITY.COUNTY_CD) WHERE (((F_ARODES.ADRESS_VALID)='T'));"
            #wczytanie warstwy
            nazwaWarstwy='DZ_EWID'
            pola=('ADR_ADM', 'NR_EW')
            warstwa=self.__mapa.warstwaRejestr(nazwaWarstwy)
            #wczytanie warstwy
            daneW=self.daneWarstwa(pola,pasek_wiadomosci,przerwanie,warstwa)
            #wczytanie bazy
            daneB=self.daneBaza(baza, sql,pasek_wiadomosci,None)  
            kontrola=self.kontroluj(daneW,daneB, nazwa,True,False,nazwaWarstwy)
            return kontrola
        except Exception as e:
            raise e
    
    def kontrola_duplikatow(self,nazwaWarstwy:str,pola:(),pasek_wiadomosci:PasekWiadomosc,przerwanie=None):
        """Kontroluje duplikaty w warstwach"""
        try:
            nazwa=u'Kontrola zdublowanych rekordów'
            warstwa=self.__mapa.warstwaRejestr(nazwaWarstwy)
            #wczytanie warstwy
            daneWarstwa=self.daneWarstwa(pola, pasek_wiadomosci, przerwanie,warstwa) #self.daneWarstwaCalosc(pola,pasek_wiadomosci,przerwanie,warstwa)
            wynik=WynikKontroli(nazwa,'','- warstwa {} zawiera zdublowany rekord'.format(nazwaWarstwy),nazwaWarstwy)
            #nie jest to optymalny sposów #wykorzystać 
            bledyWarstwy=list(set([x for x in daneWarstwa if daneWarstwa.count(x) > 1]))
            if len(bledyWarstwy)>0:
                wynik.add_result(Result(nazwa,'warstwa {} zawiera zdublowany rekord'.format(nazwaWarstwy),bledyWarstwy,TypeOfControl.DATA))
            wynik.bledyWarstwy=bledyWarstwy
            wynik.bledyBazy=[]
            return wynik
            
        except Exception as e:
            raise e            
                
    def uruchom(self):
        """Wykonanie kontroli
        :return nazwa pliku wynikowego
        """
        ret=None
        try:
            pasek=PasekWiadomosc(self.__iface,u'Kontrola danych')
            pasek.pasekPostepu()
            
            baza=Baza(self.__konfiguracja.plikBazaTaksator)
            
            #Kontrola obiekt�w podstawowych PU019
            if self.przerwanie is True:
                return ret
            #Kontrola duplikatów rekordów w warstwie
            #"POW"
            nazwaWarstwy='POW'
            pola=('ADR_BDL',)
            kontrola=self.kontrola_duplikatow(nazwaWarstwy,pola,pasek)
            self.kontrole.append(kontrola) 
            #ODDZIAL
            nazwaWarstwy='ODDZIAL'
            pola=('ADR_BDL',)
            kontrola=self.kontrola_duplikatow(nazwaWarstwy,pola,pasek)
            self.kontrole.append(kontrola) 
            #DZ_EWID
            nazwaWarstwy='DZ_EWID'
            pola=('ADR_ADM','NR_EW',)
            kontrola=self.kontrola_duplikatow(nazwaWarstwy,pola,pasek)
            self.kontrole.append(kontrola) 
            #UZYTKI
            nazwaWarstwy='UZYTKI'
            pola=('ADR_ADM','NR_EW','NR_KONT',)
            kontrola=self.kontrola_duplikatow(nazwaWarstwy,pola,pasek)
            self.kontrole.append(kontrola)
            ##
            #nazwa=u'Kontrola adresów obiektów podstawowych'
            nazwaWarstwy='O_PODST'
             
            pasek.setText(u"Kontrola warstwy '%s'" % nazwaWarstwy)
            #Kontrola
             
            kontrola=self.kontrola_ob_podst(baza,pasek,self.przerwanie)
            #koniec kontroli
            self.kontrole.append(kontrola) 
             
            #Kontrola adresów pododdziałów PU020
            if self.przerwanie is True:
                return ret
            #nazwa=u'Kontrola adresów pododdziałów'
            nazwaWarstwy='POW'
            
            pasek.setText(u"Kontrola warstwy '%s'" % nazwaWarstwy)
            #Kontrola
             
            kontrola=self.kontrola_pow(baza,pasek,self.przerwanie)
            #koniec kontroli
            self.kontrole.append(kontrola) 
             
            #Kontrola adresów oddziałów PU021
            if self.przerwanie is True:
                return ret   
            #nazwa=u'Kontrola adresów oddziałów'
            nazwaWarstwy='ODDZIAL'
             
            pasek.setText(u"Kontrola warstwy '%s'" % nazwaWarstwy)
            #Kontrola
             
            kontrola=self.kontrola_oddzial(baza,pasek,self.przerwanie)
            #koniec kontroli
            self.kontrole.append(kontrola) 
             
            #Kontrola adresów PNSW PU022
            if self.przerwanie is True:
                return ret
            #nazwa=u'Kontrola adresów PNSW'
            nazwaWarstwy='PNSW'
             
            pasek.setText(u"Kontrola warstwy '%s'" % nazwaWarstwy)
            #Kontrola
             
            kontrola=self.kontrola_pnsw(baza,pasek,self.przerwanie)
            #koniec kontroli
            self.kontrole.append(kontrola) 
             
            #Kontrola osobliwości przyrodniczych PU023
            if self.przerwanie is True:
                return ret
            #nazwa=u'Kontrola osobliwości przyrodniczych'
            nazwaWarstwy=('OS_PKT','OS_POW')
            
            pasek.setText(u"Kontrola warstwy '%s'" % ','.join(nazwaWarstwy))
                         
            kontrola=self.kontrola_osob_prz(baza,pasek,self.przerwanie)
            #koniec kontroli
            self.kontrole.append(kontrola) 
             
            #Kontrola tabeli F_PARAMETER
            kontrola=self.kontrola_f_parameter(baza, pasek)
            self.kontrole.append(kontrola)
             
            #kontrola tabeli F_MEASURE
            kontrola=self.kontrola_f_measure(baza, pasek)
            self.kontrole.append(kontrola)
             
            #kontrola tabeli F_PARCEL
            kontrola=self.kontrola_f_parcel(baza,pasek)
            self.kontrole.append(kontrola)
            
            #kontrola słowników
            #Kontrola CAUSE_CD
            ret=self.kontrolujSlownik(self.__root,self.__swdl_version ,baza, 'F_END_CAUSE_DIC','CAUSE_CD', 'causeCd', pasek,None ,True)
            self.kontrole.append(ret)
            #Kontrola F_AREA_TYPE_DIC
            ret=self.kontrolujSlownik(self.__root,self.__swdl_version, baza, 'F_AREA_TYPE_DIC','AREA_TYPE_CD', 'areaTypeCd', pasek,None ,True)
            self.kontrole.append(ret)
            #Kontrola F_MOISTENING_DIC
            ret=self.kontrolujSlownik(self.__root, self.__swdl_version,baza, 'F_MOISTENING_DIC','MOISTURY_CD', 'moistureCd', pasek,None ,True)
            self.kontrole.append(ret)
            #Kontrola F_LOCATION_DIC
            ret=self.kontrolujSlownik(self.__root, self.__swdl_version,baza, 'F_LOCATION_DIC','LOCATION_CD', 'locationCd', pasek,None ,True)
            self.kontrole.append(ret)
            #Kontrola F_MIXTURE_DIC
            ret=self.kontrolujSlownik(self.__root, self.__swdl_version,baza, 'F_MIXTURE_DIC','MIXTURE_CD', 'mixtureCd', pasek,None ,True)
            self.kontrole.append(ret)
            #Kontrola F_PART_DIC
            ret=self.kontrolujSlownik(self.__root, self.__swdl_version,baza, 'F_PART_DIC','PART_CD', 'partCd', pasek,None ,True)
            self.kontrole.append(ret)
            #Kontrola F_PLANT_DIC
            ret=self.kontrolujSlownik(self.__root, self.__swdl_version,baza, 'F_PLANT_DIC','PLANT_CD', 'plantCd', pasek,None ,True)
            self.kontrole.append(ret)
            #Kontrola F_PHENOMENA_DIC
            ret=self.kontrolujSlownik(self.__root, self.__swdl_version,baza, 'F_PHENOMENA_DIC','PHENOMENA_CD', 'phenomenaCd', pasek,None ,True)
            self.kontrole.append(ret)
            #Kontrola F_SITE_TYPE_DIC
            ret=self.kontrolujSlownik(self.__root, self.__swdl_version,baza, 'F_SITE_TYPE_DIC','SITE_TYPE_CD', 'siteTypeCd', pasek,None ,True)
            self.kontrole.append(ret)
            #Kontrola F_POSITION_DIC
            ret=self.kontrolujSlownik(self.__root, self.__swdl_version,baza, 'F_POSITION_DIC','POSITION_CD', 'positionCd', pasek,None ,True)
            self.kontrole.append(ret)
            #Kontrola F_RELIEF_DIC
            ret=self.kontrolujSlownik(self.__root, self.__swdl_version,baza, 'F_POSITION_DIC','RELIEF_CD', 'reliefCd', pasek,None ,True)
            self.kontrole.append(ret)
            #Kontrola F_DEGRADATION_DIC
            ret=self.kontrolujSlownik(self.__root, self.__swdl_version,baza, 'F_DEGRADATION_DIC','DEGRADATION_CD', 'degradationCd', pasek,None ,True)
            self.kontrole.append(ret)
            #Kontrola F_VEG_COVER_DIC
            ret=self.kontrolujSlownik(self.__root, self.__swdl_version,baza, 'F_VEG_COVER_DIC','VEG_COVER_CD', 'vegCoverCd', pasek,None ,True)
            self.kontrole.append(ret)
            #Kontrola F_SILVICULTURE_DIC
            ret=self.kontrolujSlownik(self.__root, self.__swdl_version,baza, 'F_SILVICULTURE_DIC','SILVICULTURE_CD', 'silvicultureCd', pasek,None ,True)
            self.kontrole.append(ret)
            #Kontrola F_FOREST_FUNC_DIC
            ret=self.kontrolujSlownik(self.__root, self.__swdl_version,baza, 'F_FOREST_FUNC_DIC','FOREST_FUNC_CD', 'forestFuncCd', pasek,None ,True)
            self.kontrole.append(ret)
            #Kontrola F_STAND_STRUCT_DIC
            ret=self.kontrolujSlownik(self.__root, self.__swdl_version,baza, 'F_STAND_STRUCT_DIC','STAND_STRUCT_CD', 'standStructCd', pasek,None ,True)
            self.kontrole.append(ret)
            #Kontrola F_SLOPE_DIC
            ret=self.kontrolujSlownik(self.__root, self.__swdl_version,baza, 'F_SLOPE_DIC','SLOPE_CD', 'slopeCd', pasek,None ,True)
            self.kontrole.append(ret)
            #Kontrola F_EXPOSURE_DIC
            ret=self.kontrolujSlownik(self.__root, self.__swdl_version,baza, 'F_EXPOSURE_DIC','EXPOSURE_CD', 'exposureCd', pasek,None ,True)
            self.kontrole.append(ret)
            #Kontrola F_SOIL_PEC_DIC
            ret=self.kontrolujSlownik(self.__root, self.__swdl_version,baza, 'F_SOIL_PEC_DIC','SOIL_PEC_CD', 'soilPecCd', pasek,None ,True)
            self.kontrole.append(ret)
            #Kontrola F_SOIL_SUBTYPE_DIC
            ret=self.kontrolujSlownik(self.__root, self.__swdl_version,baza, 'F_SOIL_SUBTYPE_DIC','SOIL_SUBTYPE_CD', 'soilSubTypeCd', pasek,None ,None)
            self.kontrole.append(ret)
            #Kontrola F_RECONSTRUCTION_DIC
            ret=self.kontrolujSlownik(self.__root, self.__swdl_version,baza, 'F_RECONSTRUCTION_DIC','RECONSTR_CD', 'reconstrCd', pasek,None ,True)
            self.kontrole.append(ret)
            #Kontrola F_GROWTH_PHASE_DIC
            ret=self.kontrolujSlownik(self.__root, self.__swdl_version,baza, 'F_GROWTH_PHASE_DIC','PHASE_CD', 'phaseCd', pasek,None ,True)
            self.kontrole.append(ret)
            #Kontrola F_FOREST_PEC_DIC
            ret=self.kontrolujSlownik(self.__root, self.__swdl_version,baza, 'F_GROWTH_PHASE_DIC','F_FOREST_PEC_DIC', 'forestPecDic', pasek,None ,True)
            self.kontrole.append(ret)
            #Kontrola F_PROT_CATEG_DIC
            ret=self.kontrolujSlownik(self.__root, self.__swdl_version,baza, 'F_PROT_CATEG_DIC','PROT_CATEGORY_CD', 'categoryCd', pasek,None ,True)
            self.kontrole.append(ret)
            #Kontrola F_TREE_SPECIES
            ret=self.kontrolujSlownik(self.__root, self.__swdl_version,baza, 'F_TREE_SPECIES','SPECIES_CD', 'speciesCd', pasek,None ,True)
            self.kontrole.append(ret)
            #Kontrola F_DENSITY_DIC
            ret=self.kontrolujSlownik(self.__root, self.__swdl_version,baza, 'F_DENSITY_DIC','DENSITY_CD', 'densityCd', pasek,None ,True)
            self.kontrole.append(ret)
            #Kontrola F_TREE_STOCK_DIC
            ret=self.kontrolujSlownik(self.__root, self.__swdl_version,baza, 'F_TREE_STOCK_DIC','TREE_STOCK_CD', 'treeStockCd', pasek,None ,True)
            self.kontrole.append(ret)
            #Kontrola F_SITE_CLASS_DIC
            ret=self.kontrolujSlownik(self.__root, self.__swdl_version,baza, 'F_SITE_CLASS_DIC','SITE_CLASS_CD', 'siteClassCd', pasek,None ,True)
            self.kontrole.append(ret)
            #Kontrola F_ENV_PROTECT_DIC
            ret=self.kontrolujSlownik(self.__root, self.__swdl_version,baza, 'F_ENV_PROTECT_DIC','PROTECT_AREA_CD', 'naturalValueCd', pasek,None ,False)
            self.kontrole.append(ret)
            #Kontrola F_PROT_AREA_DIC 
            ret=self.kontrolujSlownik(self.__root, self.__swdl_version,baza, 'F_PROT_AREA_DIC','PROTECT_AREA_CD', 'protectAreaCD', pasek,None ,False)
            self.kontrole.append(ret)
            #Kontrola F_SOIL_SPECIES_DIC
            ret=self.kontrolujSlownik(self.__root, self.__swdl_version,baza, 'F_SOIL_SPECIES_DIC','SOIL_SPECIES_CD', 'soilSpeciesCd', pasek,None ,False)
            self.kontrole.append(ret)
            
            filename_txt='%s\kontrola_spojności_%s.txt' % (self.__konfiguracja.kontrole, datetime.date.today())
            filename_xls='%s\kontrola_spojności_%s.xlsx' % (self.__konfiguracja.kontrole, datetime.date.today())
            if self.przerwanie is True:
                return ret
            self.zapiszWyniki(self.kontrole,filename_txt,filename_xls)
               
            if self.przerwanie is False:
                pasek.setProgressValue(100)
                ret = (filename_txt,filename_xls)
            return ret            
        except Exception as e:
          raise e
       
    def run(self):
        """Uruchomienie kontroli"""
        ret=None
        try:
            
            ret=self.uruchom()
            
        except Exception as e:
            self.blad.emit(e, traceback.format_exc())
        self.zakonczenie.emit(ret)

    def przerwij(self):
        """Przerwanie kontroli"""
        self.przerwanie = True
    
    def daneBaza(self,baza,sql,pasek_wiadomosci:PasekWiadomosc,przerwanie):
        """Pobranie danych z bazy
        :param baza:baza danych
        :param sql:zapytanie
        :return dane
        """
        lista=[]
      
        try:
            baza.polaczOdbc()
            tabela=baza.wykonajZapytanie(sql)
            baza.zamknijPolaczenie()
            pasek_wiadomosci.setText(u"Wczytanie danych z bazy 'UPUL.MDB'")            
                #komunikat.emit(u"Wczytanie danych z bazy 'UPUL.MDB'")
            
            liczbaRekordow=len(tabela)
            
            krok = liczbaRekordow // 100
            k=0
            for wiersz in tabela:
                if przerwanie is not None and przerwanie is True:
                    break
                if wiersz[0] not in lista:
                    lista.append(wiersz[0])
                                
                k+=1
                if (krok == 0 or k % krok == 0) and liczbaRekordow>0:
                    pasek_wiadomosci.setProgressValue((k / float(liczbaRekordow))*100)
                        #postep.emit((k / float(liczbaRekordow))*100)
        except Exception as e:
            raise e
            #self.blad.emit(e, traceback.format_exc())
        finally:
            return lista
    
    def slownikBaza(self,baza:Baza,tabela:str,pole:str,pasek_wiadomosci:PasekWiadomosc,przerwanie,upper):
        """Pobranie słownika z bazy
        :param baza:baza danych
        :param tabela:nazwa tabeli
        :param pole: nazwa pola w bazie danych
        :param upper: zgoda na konwersję wartości do dużych liter. Związane z tym że do swdl część danych słownikowych wpisywana jest dużymi literami 
        :return dane
        """
        lista=[]
      
        try:
            baza.polaczOdbc()
            sql='SELECT {}.{} FROM {};'.format(tabela,pole,tabela)
            tabela=baza.wykonajZapytanie(sql)
            baza.zamknijPolaczenie()
            pasek_wiadomosci.setText(u"Wczytanie danych z bazy 'UPUL.MDB'")            
                #komunikat.emit(u"Wczytanie danych z bazy 'UPUL.MDB'")
            
            liczbaRekordow=len(tabela)
            
            krok = liczbaRekordow // 100
            k=0
            for wiersz in tabela:
                if przerwanie is not None and przerwanie is True:
                    break
                if wiersz[0] not in lista:
                    lista.append(wiersz[0])
                                
                k+=1
                if (krok == 0 or k % krok == 0) and liczbaRekordow>0:
                    pasek_wiadomosci.setProgressValue((k / float(liczbaRekordow))*100)
                        #postep.emit((k / float(liczbaRekordow))*100)
        except Exception as e:
            raise e
            #self.blad.emit(e, traceback.format_exc())
        finally:
            if upper==None:
                return lista
            if upper :
                return [wart.upper() for wart in lista]
            else:
                return [wart.lower() for wart in lista]
            
    
    def daneWarstwa(self,pola,pasek_wiadomosci:PasekWiadomosc,przerwanie,*warstwa):
        """Pobranie danych z warstw
        :param pola:nazwy pól warstwy
        :param warstwa:warstwy
        """
        dane=[]
        
        try:
            
            s=';'
                       
            for war in warstwa:
                
                if przerwanie is not None and przerwanie is True:
                    break
                pasek_wiadomosci.setText(u"Wczytanie danych z warstwy '%s'" % war.name())
                    #komunikat.emit(u"Wczytanie danych z warstwy '%s'" % war.name())
                
                liczbaRekordow=war.liczbaRekordow()
                krok = liczbaRekordow // 100
                k=0
                
                fr="||';'||".join(pola)
                layer_calculator=processing.run("native:fieldcalculator", {'INPUT':war,'FIELD_NAME':'result','FIELD_TYPE':2,'FIELD_LENGTH':0,'FIELD_PRECISION':0,'FORMULA':fr,'OUTPUT':'TEMPORARY_OUTPUT'})
                layer=layer_calculator['OUTPUT']
                [dane.append(feature['result']) for feature in layer.getFeatures()]
                               
                k+=1
                if (krok == 0 or k % krok == 0) and liczbaRekordow>0:
                    pasek_wiadomosci.setProgressValue((k / float(liczbaRekordow))*100)
                    
                            #postep.emit((k / float(liczbaRekordow))*100)
        except Exception as e:
            raise e
            #self.blad.emit(e, traceback.format_exc())
        finally:
            return dane
    
    def daneSwdl(self,root,swdl_version,nazwa:str)->[]:
        """Dane zawartw w schemacie swdl
        :param nazwa: Nazwa słownika;
        """
        try:
            tree=ElementTree(file=root+u'/XSD/{}/XSD/swdl/swdl.xsd'.format(swdl_version))
            li=[e for e in tree.iter('{http://www.w3.org/2001/XMLSchema}element') if 'name' in e.attrib.keys() and e.attrib['name']==nazwa]
            values=[]
            if(len(li)>0):
                values=[element.attrib['value'] for element in li[0].iter('{http://www.w3.org/2001/XMLSchema}enumeration')]
            return values
        except Exception as e:
            raise e
    
#     def daneWarstwaCalosc(self,pola,pasek_wiadomosci:PasekWiadomosc,przerwanie,*warstwa):
#         """wczytuje wszystkie dane z warstwy"""
#         try:
#             dane=[]
#                                    
#             for war in warstwa:
#                 
#                 if przerwanie is not None and przerwanie is True:
#                     break
#                 pasek_wiadomosci.setText(u"Wczytanie danych z warstwy '%s'" % war.name())
#                     #komunikat.emit(u"Wczytanie danych z warstwy '%s'" % war.name())
#                 
#                 liczbaRekordow=war.liczbaRekordow()
#                 krok = liczbaRekordow // 100
#                 k=0
#                 for obiekt in war.getFeatures():
#                     if przerwanie is not None and przerwanie is True:
#                         break
#                     elementy=[]
#                     for pole in pola:
#                         elementy.append(str(obiekt[pole]))
#                     dane.append(';'.join(elementy))    
#                     k+=1
#                     if krok == 0 or k % krok == 0:
#                         pasek_wiadomosci.setProgressValue((k / float(liczbaRekordow))*100)
#                 
#                 return dane
#         except Exception as e:
#             raise e
#         
    def kontroluj(self,daneWarstwa,daneBaza,nazwa,baza_bool=True,warstwa_bool=True,*nazwaWarstwy):
        """Wykonanie pojedyńczej kontroli
        :param daneWarstwa: dane z warstwy
        :param daneBaza:dane z bazy
        :param nazwa kontroli
        :param baza_bool:kontrola bazy
        :param warstwa_bool:kontrola warstwy
        :param nazwaWarstwy: nazwy warstw
        :return wynik kontroli
        """
        try:
                                  
            wynik=WynikKontroli(nazwa,'- brak na mapie','- brak w bazie',*nazwaWarstwy)
            kontrolaWarstwa=set(daneWarstwa)-set(daneBaza) #[i for i in daneWarstwa if i not in daneBaza ]
            if len(kontrolaWarstwa)>0 and warstwa_bool:
                wynik.add_result(Result(nazwa,'brak w bazie',kontrolaWarstwa,TypeOfControl.DATA))
#             if self.przerwanie is True:
#                     return
#             self.komunikat.emit(u"Kontrola danych w bazie 'UPUL.MDB'")
                        
            kontrolaBaza=set(daneBaza)-set(daneWarstwa) #[i for i in daneBaza if i not in daneWarstwa ]
            if len(kontrolaBaza)>0 and baza_bool:
                wynik.add_result(Result(nazwa,'brak na mapie',kontrolaBaza,TypeOfControl.DATA))
            if warstwa_bool:
                wynik.bledyWarstwy=kontrolaWarstwa
            if baza_bool:
                wynik.bledyBazy=kontrolaBaza  
             
            return wynik 
        except Exception as e:
            self.blad.emit(e, traceback.format_exc())
    
    
       
    def kontrolujSlownik(self,root,swdl_version,baza:Baza,tabela:str,pole:str,nazwa_swdl:str,pasek_wiadomosci:PasekWiadomosc,przerwanie,upper):
        """Kontrola słownika z swdl z danymi w bazie"""
        try:
           
            dane=self.slownikBaza(baza, tabela, pole, pasek_wiadomosci, przerwanie, upper)
            #Dane z bazy
            slownik=self.daneSwdl(root,swdl_version,nazwa_swdl)
            #Dane słownika z pliku swdl
            #Kontrola wartości z bazy i swdl
            niezgodnosci=set(dane)-set(slownik) #[niezg for niezg in dane if niezg not in slownik]
            
            nazwa=u'Kontrola słownika {}'.format(tabela)
            wynik=WynikKontroli(nazwa,'Słownik zawiera elementy niedopuszczalne w schemacie swdl','CCCC','','')
            wynik.bledyWarstwy=[] 
            wynik.bledyBazy=[]
            
            if len(niezgodnosci)>0:
                wynik.bledyBazy=['{}'.format(niezgodnosci),]
                wynik.add_result(Result('FFFFF','Słownik zawiera błędne elementy',niezgodnosci,TypeOfControl.DATA))
            return wynik 
        
  
        except Exception as e:
            raise e
        
                 
    def zapiszWyniki(self,wyniki,path_txt,path_xls):
        """Zapisuje wyniki kontroli do pliku
        :param wyniki:wyniki kontroli
        :param path_txt:scieżka do pliku txt
        :param path_xls:ścieżka do pliku xls
        """
        try:
            #Zapis do pliku excel
            heading=('Kontrola spójności danych','Wersja programu Mapa PU {}, {}'.format(self.__wersja,date_helper.curentDate()),'Raport zawiera wyniki kontroli spójności danych')
            lst=[]
            excel=Excel()
            # for kontrola in wyniki:
            #     for result in kontrola.results:
            #         for error in result.errors:
            #             lst.append(ExcelError(kontrola.,error,''))
            
            
            #Zapis do pliku tekstowego  
            plik=codecs.open(path_txt,'w',encoding="utf-8")
          
            plik.write('Kontrole spójności danych\nWersja programu Mapa PU {}, {}\nRaport zawiera wyniki kontroli spójności danych\n'.format(self.__wersja,date_helper.curentDate()))
            for kontrola in wyniki:
             
                nowaLinia=u'\r\n'
                lp='==========================================================================='
                l='---------------------------------------------------------------------------'
                plik.write(lp+nowaLinia)
                plik.write('Kontrola - %s' % kontrola.nazwa+nowaLinia)
                plik.write(lp+nowaLinia)
                plik.write('Warstwa - %s' % kontrola.nazwaWarstwy+nowaLinia)
                plik.write(l+nowaLinia)
                plik.write('Wynik kontroli - %s' % (u'OK' if kontrola.wynik==True else u'Stwierdzono błędy') +nowaLinia)
                plik.write(l+nowaLinia)
              
                #===================================================================
                for blad in kontrola.bledyBazy:
                    plik.write(u'%s %s%s' %(blad,kontrola.komunikatBaza,nowaLinia))
                    lst.append(ExcelError(kontrola.nazwa,"{} {}".format(blad,kontrola.komunikatBaza)))
                #===================================================================
                plik.write(l+nowaLinia)
                #===================================================================
                for blad in kontrola.bledyWarstwy:
                    plik.write(u'%s %s%s' %(blad,kontrola.komunikatWarstwa,nowaLinia))
                    lst.append(ExcelError(kontrola.nazwa,"{} {}".format(blad,kontrola.komunikatWarstwa)))
                #===================================================================
                plik.write(lp+nowaLinia)

            #if len(lst)>0:
            file=excel.save_to_excell(lst, self.__root, path_xls,heading)
    
        except Exception as e:
            raise e
            #self.blad.emit(e, traceback.format_exc())
        finally:
            if plik!=None:
                plik.close()
      
    
    