# -*- coding: utf-8 -*-

# Copyright 2008-2016 Mir Calculate. http://www.calculate-linux.org
#
#  Licensed under the Apache License, Version 2.0 (the "License");
#  you may not use this file except in compliance with the License.
#  You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
#  Unless required by applicable law or agreed to in writing, software
#  distributed under the License is distributed on an "AS IS" BASIS,
#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#  See the License for the specific language governing permissions and
#  limitations under the License.

import sys
from ..cl_xml import xpath, str_to_xml_doc
from .xml_xfce import xml_xfce
from collections.abc import Iterable
from copy import deepcopy
from ..cl_lang import setLocalTranslate

_ = lambda x: x
setLocalTranslate('cl_lib3', sys.modules[__name__])


class xml_xfcepanel(xml_xfce):
    """Класс для объединения xfce-panel файлов"""

    def prepare(self):
        super().prepare()
        self.panelNumbers = {}

    def textToXML(self):
        """Создание из текста XML документа
        Храним xml в своем формате
        """
        if not self.text.strip():
            self.text = '''<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE config SYSTEM "config.dtd">
<panels>
</panels>'''
        try:
            # self.doc = xml.dom.minidom.parseString(self.text)
            # self.doc = etree.XML(bytes(bytearray(self.text, encoding='utf-8')))
            self.doc = str_to_xml_doc(self.text)
        except Exception:
            self.setError(_("The template content is not XML"))
            return False
        self.rootNode = self.doc.getroottree().getroot()
        self.bodyNode = self.rootNode
        return self.doc

    def setNameBodyNode(self, name):
        """Пустой метод"""
        return True

    def _join(self, xmlNewNode, xmlOldNode, flagRootNode=True, levelNumber=0):
        """Объединение корневой ноды шаблона и корневой ноды файла"""
        xmlNode = xmlNewNode
        childNodes = list(xmlNode)
        nextOldNode = xmlOldNode
        n = xmlNode
        flagArray = False
        nValue = ''
        nAction = ''
        attrName = ''
        path = n.tag
        if path == "items":
            flagArray = True
        if not flagArray:
            if "name" in n.keys():
                nName = n.get("name")
                attrName = "attribute::name='%s'" % nName
            if "value" in n.keys():
                nValue = n.get("value")
        if "action" in n.keys():
            nAction = n.get("action")
            if not nAction in ("join", "replace", "drop"):
                textError = _("In the text of the XML template, "
                                "reserved attribute 'action' comes with an "
                                "incorrect value.\n"
                                "Valid values of the 'action' attribute are: "
                                '(action="join", action="replace", '
                                'action="drop")')
                self.setError(textError)
                return False
        if xmlNewNode.getparent() is not None:
            findAttrStr = ""
            if attrName:
                findAttrStr = "[%s]" % attrName
            findPath = "child::%s%s" % (path, findAttrStr)
            # Рабочая нода
            if flagRootNode:
                workNode = xmlOldNode.getparent()
            else:
                workNode = xmlOldNode
            oldNodes = xpath.Evaluate(findPath, workNode)
            flagDrop = False
            flagJoin = True
            flagReplace = False
            flagAppend = False
            if nAction == "replace":
                flagJoin = False
                flagReplace = True
            elif nAction == "drop":
                flagJoin = False
                flagDrop = True
                if flagRootNode:
                    textError = _('Incorrect action="drop" '
                                    'in the root node')
                    self.setError(textError)
                    return False
            if path == "panel":
                flagJoin = False
                if levelNumber in self.panelNumbers.keys():
                    self.panelNumbers[levelNumber] += 1
                else:
                    self.panelNumbers[levelNumber] = 0
            if oldNodes:
                if len(oldNodes) > 1 and path != "panel":
                    textError = _("Ambiguity in this template: the "
                                    "same nodes are on a same level")
                    self.setError(textError)
                    return False
                if path == "panel":
                    if len(oldNodes) <= self.panelNumbers[levelNumber]:
                        nextOldNode = oldNodes[-1]
                        # Добавляем ноду
                        if not flagDrop:
                            flagAppend = True
                            flagReplace = False
                            childNodes = False
                    else:
                        nextOldNode = oldNodes[
                            self.panelNumbers[levelNumber]]
                else:
                    nextOldNode = oldNodes[0]
                # Замещаем ноду в случае массива
                if flagArray and not flagDrop:
                    replaceXmlNode = deepcopy(xmlNode)
                    if nAction:
                        del replaceXmlNode.attrib["action"]
                    workNode.replace(nextOldNode, replaceXmlNode)
                    flagJoin = False
                    flagReplace = False
                    childNodes = False
                # Объединение нод
                if flagJoin:
                    if "value" in nextOldNode.keys():
                        oValue = nextOldNode.get("value")
                        if nValue != oValue:
                            nextOldNode.set("value", nValue)
                # Замещение ноды
                elif flagReplace:
                    replaceXmlNode = deepcopy(xmlNode)
                    if not self._removeDropNodesAndAttrAction(
                            replaceXmlNode):
                        return False
                    workNode.replace(nextOldNode, replaceXmlNode)
                    childNodes = False
                # Удаление ноды
                elif flagDrop:
                    workNode.remove(nextOldNode)
                    childNodes = False
            else:
                flagAppend = True
                flagDrop = False
            if flagAppend and not flagDrop:
                # Добавление ноды
                childNodes = False
                if not flagDrop:
                    appendXmlNode = deepcopy(xmlNode)
                    if not self._removeDropNodesAndAttrAction(
                            appendXmlNode):
                        return False
                    workNode.append(appendXmlNode)
        if isinstance(childNodes, Iterable):
            for node in childNodes:
                levelNumber += 1
                if not self._join(node, nextOldNode, False, levelNumber):
                    return False
                levelNumber -= 1
        return True

    def join(self, xml_xfceObj):
        """Объединяем конфигурации"""
        if isinstance(xml_xfceObj, xml_xfcepanel):
            try:
                self.joinDoc(xml_xfceObj.doc)
            except Exception:
                self.setError(_("Failed to join the template"))
            return False
        return True
