import os, sys, re, io
from qgis.PyQt.QtXml import QDomDocument
from qgis.PyQt import uic

jp = os.path.join
dn = os.path.dirname

# dictionary to store form classes and avoid multiple calls to read <myui>.ui
FORM_CLASSES = dict()
QGIS_RESOURCE_WARNINGS = set()

def loadUIFormClass(pathUi:str, from_imports=False, resourceSuffix:str='', fixQGISRessourceFileReferences=True, _modifiedui=None):
    """
    Loads Qt UI files (*.ui) while taking care on QgsCustomWidgets.
    Uses PyQt4.uic.loadUiType (see http://pyqt.sourceforge.net/Docs/PyQt4/designer.html#the-uic-module)
    :param pathUi: *.ui file path
    :param from_imports:  is optionally set to use import statements that are relative to '.'. At the moment this only applies to the import of resource modules.
    :param resourceSuffix: is the suffix appended to the basename of any resource file specified in the .ui file to create the name of the Python module generated from the resource file by pyrcc4. The default is '_rc', i.e. if the .ui file specified a resource file called foo.qrc then the corresponding Python module is foo_rc.
    :return: the form class, e.g. to be used in a class definition like MyClassUI(QFrame, loadUi('myclassui.ui'))
    """

    RC_SUFFIX = resourceSuffix
    assert os.path.isfile(pathUi), '*.ui file does not exist: {}'.format(pathUi)


    if pathUi not in FORM_CLASSES.keys():
        #parse *.ui xml and replace *.h by qgis.gui

        with open(pathUi, 'r', encoding='utf-8') as f:
            txt = f.read()

        dirUi = os.path.dirname(pathUi)

        locations = []

        for m in re.findall(r'(<include location="(.*\.qrc)"/>)', txt):
            locations.append(m)

        missing = []
        for t in locations:
            line, path = t
            if not os.path.isabs(path):
                p = os.path.join(dirUi, path)
            else:
                p = path

            if not os.path.isfile(p):
                missing.append(t)
        match = re.search(r'resource="[^:].*/QGIS[^/"]*/images/images.qrc"',txt)
        if match:
            txt = txt.replace(match.group(), 'resource=":/images/images.qrc"')



        if len(missing) > 0:

            missingQrc = []
            missingQgs = []

            for t in missing:
                line, path = t
                if re.search(r'.*(?i:qgis)/images/images\.qrc.*', line):
                    missingQgs.append(m)
                else:
                    missingQrc.append(m)

            if len(missingQrc) > 0:
                print('{}\nrefers to {} none-existing resource (*.qrc) file(s):'.format(pathUi, len(missingQrc)))
                for i, t in enumerate(missingQrc):
                    line, path = t
                    print('{}: "{}"'.format(i+1, path), file=sys.stderr)

        doc = QDomDocument()
        doc.setContent(txt)

        elem = doc.elementsByTagName('customwidget')
        for child in [elem.item(i) for i in range(elem.count())]:
            child = child.toElement()
            className = str(child.firstChildElement('class').firstChild().nodeValue())
            if className.startswith('Qgs'):
                cHeader = child.firstChildElement('header').firstChild()
                cHeader.setNodeValue('qgis.gui')


        # collect resource file locations
        elems = doc.elementsByTagName('include')
        qrcPaths = []
        for i in range(elems.count()):
            node = elems.item(i).toElement()
            lpath = node.attribute('location')
            if len(lpath) > 0 and lpath.endswith('.qrc'):
                p = lpath
                if not os.path.isabs(lpath):
                    p = os.path.join(dirUi, lpath)
                else:
                    p = lpath
                qrcPaths.append(p)


        buffer = io.StringIO()  # buffer to store modified XML

        if isinstance(_modifiedui, str):
            f = open(_modifiedui, 'w', encoding='utf-8')
            f.write(doc.toString())
            f.flush()
            f.close()

        buffer.write(doc.toString())
        buffer.flush()
        buffer.seek(0)



        #if existent, make resource file directories available to the python path (sys.path)
        baseDir = os.path.dirname(pathUi)
        tmpDirs = []
        if True:
            for qrcPath in qrcPaths:
                d = os.path.abspath(os.path.join(baseDir, qrcPath))
                d = os.path.dirname(d)
                if os.path.isdir(d) and d not in sys.path:
                    tmpDirs.append(d)
            sys.path.extend(tmpDirs)

        #create requried mockups

        if True:
            FORM_CLASS_MOCKUP_MODULES = [os.path.splitext(os.path.basename(p))[0] for p in qrcPaths]
            FORM_CLASS_MOCKUP_MODULES = [m for m in FORM_CLASS_MOCKUP_MODULES if m not in sys.modules.keys()]
            for mockupModule in FORM_CLASS_MOCKUP_MODULES:
                pass
                #print('ADD MOCKUP MODULE {}'.format(mockupModule))

                #sys.modules[mockupModule] = resourcemockup


        #load form class
        try:
            FORM_CLASS, _ = uic.loadUiType(buffer, resource_suffix=RC_SUFFIX)
        except Exception as ex1:
            print(doc.toString(), file=sys.stderr)
            info = 'Unable to load {}'.format(pathUi) + '\n{}'.format(str(ex1))
            ex = Exception(info)
            raise ex

        for mockupModule in FORM_CLASS_MOCKUP_MODULES:
            if mockupModule in sys.modules.keys():
                sys.modules.pop(mockupModule)


        buffer.close()

        FORM_CLASSES[pathUi] = FORM_CLASS

        #remove temporary added directories from python path
        for d in tmpDirs:
            sys.path.remove(d)
    if pathUi.endswith('spectrallibrarywidget.ui'):
        s =""


    return FORM_CLASSES[pathUi]
