"""
/***************************************************************************
                                 A QGIS plugin
 Набор инструментов для работы с материалами документации территориального планирования
 Generated by Plugin Builder: http://g-sherman.github.io/Qgis-Plugin-Builder/
                             -------------------
        begin                : 2024-03-18
        git sha              : $Format:%H$
        copyright            : (C) 2024 by I.Bukharin/Mirproekt
        email                : iabukharin@gmail.com
 ***************************************************************************/
 Функция-парсер XSD схем
"""

import xml.etree.ElementTree as et

def parseFgistpXSD(strFgistpXSD):
    root = et.fromstring(strFgistpXSD)#.getroot()

    layerGeomTypes = set()
    simpleTypes = dict()
    """ simpleTypes = {
        nameSpravochnika:{
            "typeUserName": "Перечень объектов в классе «",
            "documentation": "Перечень объектов в классе «",
            "baseType": "xs:string",
            "dictValues": {
                "601010100": "Государственная граница Российской Федерации",
            }
        }} """
    complexTypes = dict()
    """ complexTypes = {
        nameComplexType:{
            "geometryTypes":[],
            "attributes":{
                attributeName:{
                    baseType: "fgistp:UUID",
                    typeUserName: "Идентификатор объекта",
                    documentation: "Идентификатор объекта"
                    minOccurs: "Y"/"N"/"C",
                    mirDepend: "STATUS=[2, 3]"
                }
            }
        }
    } """
    elementTypes = dict()
    """ elementTypes = {
        nameElement:{
            elementType:"fgistp:AdmBorder_Type",
            typeUserName:"Границы единиц административно-территориального деления Российской Федерации",
            documentation: "Границы единиц административно-территориального деления Российской Федерации"
        }
    } """
    groupDict = dict()
    """ groupDict = {
        кодовое наименование слоя (AdmBorder):наименование группы
    }
    """
    for elem in root.iter():
        if not hasattr(elem.tag, 'find'): continue  # guard for Comment tags
        i = elem.tag.find('}')
        if i >= 0:
            elem.tag = elem.tag[i+1:]
        for attr in list(elem.attrib.keys()):
            i = attr.find('}')
            if i >= 0:
                elem.attrib[attr[i+1:]] = elem.attrib[attr]
                del elem.attrib[attr]

    for elem in root:
        tag = elem.tag
        name = elem.get('name')

        # 1. Обработка simpleType
        if tag == 'simpleType' and name:
            data = {
                'typeUserName': elem.get('username', ''),
                'documentation': '',
                'baseType': '',
                'dictValues': {}
            }
            doc = elem.find('.//documentation')
            if doc is not None:
                data['documentation'] = doc.text
                
            restr = elem.find('.//restriction')
            if restr is not None:
                data['baseType'] = restr.get('base', '')
                for enum in restr.findall('enumeration'):
                    val = enum.get('value')
                    user_val = enum.get('username')
                    if val and user_val:
                        data['dictValues'][val] = user_val
            simpleTypes[name] = data

        # 2. Обработка complexType
        elif tag == 'complexType' and name:
            complexTypes[name] = {'geometryTypes': [], 'attributes': dict()}

            for pole in elem.findall('.//sequence//element'):
                attr_name = pole.get('name')
                if not attr_name: continue
                
                attr_data = {
                    'baseType': pole.get('type', ''),
                    'typeUserName': pole.get('username', ''),
                    'documentation': '',
                    'minOccurs': 'Y',
                    'mirDepend': pole.get('mirDepend', '')
                }

                # Если типа нет в атрибутах, ищем во вложенном simpleType
                if not attr_data['baseType']:
                    restr = pole.find('.//restriction')
                    if restr is not None:
                        attr_data['baseType'] = restr.get('base', '')

                # Логика обязательности (minOccurs)
                min_occ = pole.get('minOccurs')
                if attr_data['mirDepend']:
                    attr_data['minOccurs'] = 'C'
                elif min_occ == '0':
                    attr_data['minOccurs'] = 'N'

                doc = pole.find('.//documentation')
                if doc is not None:
                    attr_data['documentation'] = doc.text
                
                complexTypes[name]['attributes'][attr_name] = attr_data

            # Поиск геометрии (через ref)
            for geom in elem.findall('.//choice/element'):
                ref = geom.get('ref')
                if ref:
                    complexTypes[name]['geometryTypes'].append(ref)
                    layerGeomTypes.add(ref)

        # 3. Обработка element
        elif tag == 'element' and name:
            el_data = {
                'elementType': elem.get('type', ''),
                'typeUserName': elem.get('username', ''),
                'documentation': '',
                'mirGroup': elem.get('mirGroup', '')
            }
            doc = elem.find('.//documentation')
            if doc is not None:
                el_data['documentation'] = doc.text
            
            elementTypes[name] = el_data
            
            # Группировка
            ignored_names = {'ADME_Element', 'year', 'day', 'month', 'xref', 'target', 
                             'tasks', 'event', 'indicator', 'indicatorsGroup', 'eventGroup', 'indicators'}
            if el_data['mirGroup']:
                groupDict[name] = el_data['mirGroup']
            elif name not in ignored_names:
                groupDict[name] = ''

    # Валидация: проверка связей (используем set для скорости O(1))
    # 1. Подготовка эталонных списков для быстрой проверки (O(1))
    # Собираем все доступные типы: и оригинальные, и без префикса fgistp:
    known_simple = set(simpleTypes.keys())
    known_simple.update(name.replace('fgistp:', '') for name in simpleTypes.keys())
    
    known_complex = set(complexTypes.keys())
    known_complex.update(name.replace('fgistp:', '') for name in complexTypes.keys())
    
    xs_types = {'xs:string', 'xs:double', 'xs:positiveInteger', 'xs:integer', 'xs:dateTime', 'xs:date', 'xs:boolean'}


    errlayers = set()
    for layer_name, info in elementTypes.items():
        etype = info['elementType']
        etype_clean = etype.replace('fgistp:', '')
        
        # Если типа нет ни в сложных, ни в простых
        if etype not in known_complex and etype_clean not in known_complex:
            errlayers.add(layer_name)

    errTypes = set()
    for type_name, data in complexTypes.items():
        # Проверяем только те типы, где есть и геометрия, и атрибуты (как в вашем исходнике)
        if data['geometryTypes'] and data['attributes']:
            for attr_name, attr_info in data['attributes'].items():
                attr_type = attr_info['baseType']
                attr_type_clean = attr_type.replace('fgistp:', '')
                
                # Проверяем: нет ли типа в простых, нет ли в стандартных xs:
                if (attr_type not in known_simple and 
                    attr_type_clean not in known_simple and 
                    attr_type not in xs_types):
                    errTypes.add(attr_type)

    return {'simpleTypes':simpleTypes, 
            'complexTypes': complexTypes, 
            'elementTypes': elementTypes, 
            'groupDict': groupDict,
            'errlayers': errlayers, 
            'errTypes': errTypes,
            'layerGeomTypes': layerGeomTypes}