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

# Copyright 2015-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 calculate.lib.cl_template import TemplateFormat
from calculate.lib.utils.text import _u
from calculate.lib.cl_lang import setLocalTranslate
from collections import OrderedDict
from calculate.lib.utils.tools import json_module

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


class json(TemplateFormat):
    """Класс для объединения файлов конфигурации ядра"""
    # root нода
    rootNode = False
    # body нода
    bodyNode = False
    # Документ
    doc = False
    # Текст шаблона
    text = ""
    # Комментарий
    _comment = None

    def __init__(self, text):
        self.text = text
        # Создаем пустой объект
        self.docObj = type("_empty_class", (object,), {})()
        # Названия аттрибутов для пустого объекта
        empty_methods = ["getNodeBody", "removeComment", "insertBRtoBody",
                         "insertBeforeSepAreas"]
        # Добавляем необходимые аттрибуты пустому объекту
        for method in empty_methods:
            setattr(self.docObj, method, self.emptyMethod)
        # Создаем XML документ
        self.doc = self.textToXML()

    def emptyMethod(self, *arg, **argv):
        """Пустой метод"""
        return True

    def textToXML(self):
        """Создание документа из текста self.text
        """
        try:
            doc = json_module.loads(self.text.strip() or "{}",
                                    object_pairs_hook=OrderedDict)
        except ValueError:
            doc = False
        return doc

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

    def postXML(self):
        """Последующая постобработка XML"""
        pass

    def _join(self, new_doc, old_doc):
        """Объединение корневой ноды шаблона и корневой ноды файла"""
        for k in new_doc.keys():
            # удаление ключа
            if k.startswith('!'):
                k = k[1:]
                if k in old_doc:
                    old_doc.pop(k)
            else:
                if k not in old_doc or k.startswith("-"):
                    k2 = k
                    if k.startswith('-'):
                        k = k[1:]
                    old_doc[k] = new_doc[k2]
                else:
                    if type(old_doc[k]) != dict or type(new_doc[k]) != dict:
                        old_doc[k] = new_doc[k]
                    else:
                        self._join(old_doc[k], new_doc[k])
        return True

    def joinDoc(self, doc):
        """Объединение документа шаблона и документа файла"""
        if self.doc is False:
            self.setError(_("The source text file is not JSON"))
            return False
        if doc is False:
            self.setError(_("The template text file is not JSON"))
            return False
        # объединяем документы
        if not self._join(doc, self.doc):
            return False
        return True

    def getConfig(self):
        """Получение текстового файла из XML документа"""
        return _u(json_module.dumps(self.doc, indent=4))
