# -*- 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.

from __future__ import absolute_import
import re
from .generic import objShare
from calculate.lib.cl_template import blocText
from calculate.lib.cl_xml import xmlDoc


class bind(objShare):
    """Класс для обработки конфигурационного файла типа bind

    """
    _comment = "//"
    configName = "bind"
    configVersion = "0.1"
    __openArea = "{"
    __closeArea = "[ \t]*\}[ \t]*;[ \t]*"
    sepFields = ";"
    reOpen = re.compile(__openArea)
    reClose = re.compile(__closeArea)
    reCloseArea = re.compile(__closeArea + "\s*\Z")
    reComment = re.compile(
        "[ \t]+%s|^%s|(?<=;)%s" % (_comment, _comment, _comment))
    reSepFields = re.compile(sepFields)
    reSeparator = re.compile("[ \t]+")

    def prepare(self):
        self.blocTextObj = blocText()
        # Объект документ
        self.docObj = self.textToXML()
        # Создаем поля-массивы
        self.docObj.postParserList()
        # XML документ
        self.doc = self.docObj.doc

    # Делим область на составные части
    def findOpenClose(self, text, reOpen, reClose, reComment):
        """Делит область на составные части

        начальный текстовый блок,
        открывающий блок,
        блок-тело,
        закрывающий блок
        """
        first_bloc = ""
        start_bloc = ""
        end_bloc = ""
        # если в одной строки и закрывающий и открывающий блок
        text_lines = text.replace("} ", "}\n").splitlines()
        find_open = False
        if text_lines:
            find_open = reOpen.search(text_lines[0])
        open_bl = reOpen.search(text)
        if find_open and reComment.split(text)[0].strip():
            bloc_a = text[open_bl.end():]
            first_bloc = text[:open_bl.start()]
            start_bloc = text[open_bl.start():open_bl.end()]
            close_bl = reClose.search(bloc_a)
            end_bloc = bloc_a[close_bl.start():close_bl.end()]
            body_bloc = bloc_a[:close_bl.start()]
            return first_bloc, start_bloc, body_bloc, end_bloc
        else:
            return first_bloc, start_bloc, text, end_bloc

    # Делим текст на области включая вложенные (areas массив областей)
    def splitToAllArea(self, text, areas, reOpen, reClose, reCloseArea,
                       reComment, reSepFields):
        """Делит текст на области включая вложенные

        возвращает список объектов областей (переменная areas)
        """

        class area:
            def __init__(self):
                self.header = False
                self.start = False
                self.fields = []
                self.end = False

        blocs = self.blocTextObj.splitTxtToBloc(text, reOpen, reClose,
                                                reComment, reSepFields)
        for i in blocs:
            areaA = area()
            first, start, body, end = self.findOpenClose(i, reOpen, reCloseArea,
                                                         reComment)
            areaA.header = first.replace(" ", "").replace("\t", "")
            areaA.start = first + start
            areaA.end = end

            if areaA.end:
                blocsA = self.blocTextObj.splitTxtToBloc(body, reOpen, reClose,
                                                         reComment, reSepFields)
                if blocsA and blocsA[0] == body:
                    areaA.fields.append(body)
                    areas.append(areaA)
                else:
                    for ar in blocsA:
                        self.splitToAllArea(ar, areaA.fields, reOpen,
                                            reClose,
                                            reCloseArea, reComment,
                                            reSepFields)
                    areas.append(areaA)
            else:
                areaA.fields.append(body)
                areas.append(areaA)
        return areas

    def setDataField(self, txtLines, endtxtLines):
        """Создаем список объектов с переменными"""

        class fieldData:
            def __init__(self):
                self.name = False
                self.value = False
                self.comment = False
                self.br = False

        fields = []
        field = fieldData()
        z = 0
        for k in txtLines:
            textLine = k + endtxtLines[z]
            z += 1
            findComment = self.reComment.search(textLine)
            if not textLine.strip():
                field.br = textLine
                fields.append(field)
                field = fieldData()
            elif findComment:
                field.comment = textLine
                fields.append(field)
                field = fieldData()
            else:
                pars = textLine.strip()
                nameValue = self.reSeparator.split(pars)
                if len(nameValue) == 1:
                    field.name = ""
                    field.value = textLine.replace(self.sepFields, "")
                    field.br = textLine
                    fields.append(field)
                    field = fieldData()

                if len(nameValue) > 2:
                    valueList = nameValue[1:]
                    nameValue = [nameValue[0], " ".join(valueList).replace(
                        self.sepFields, "")]
                if len(nameValue) == 2:
                    name = nameValue[0]
                    value = nameValue[1].replace(self.sepFields, "")
                    field.name = name.replace(" ", "").replace("\t", "")
                    field.value = value
                    field.br = textLine
                    fields.append(field)
                    field = fieldData()
        return fields

    def createCaptionTerm(self, header, start, end, docObj):
        """Создание пустой области с заголовком

        при создании области проверяется первый символ заголовка
        и добавляется тег action
        "!" - <action>drop</action>
        "-" - <action>replace</action>
        """
        areaAction = False
        if header:
            if header[0] == "!":
                docObj.createCaption(header[1:], [start,
                                                  end.replace("\n", "")])
                areaAction = "drop"
            elif header[0] == "-":
                docObj.createCaption(header[1:], [start,
                                                  end.replace("\n", "")])
                areaAction = "replace"
            else:
                docObj.createCaption(header, [start,
                                              end.replace("\n", "")])
        else:
            docObj.createCaption(header, [start,
                                          end.replace("\n", "")])

        areaXML = docObj.createArea()
        if areaAction:
            docObj.setActionArea(areaXML, areaAction)
        return areaXML

    def createXML(self, areas, rootNode, docObj):
        """Создаем из массивов областей XML"""
        for i in areas:
            if str(i.__class__.__name__) == "area":
                if i.header and i.start:
                    areaXML = self.createCaptionTerm(i.header, i.start,
                                                     i.end.replace("\n", ""),
                                                     docObj)
                else:
                    areaXML = rootNode
                for f in i.fields:
                    if str(f.__class__.__name__) == "area":
                        if f.header and f.start:
                            areaXMLChild = self.createCaptionTerm(f.header,
                                                                  f.start,
                                                                  f.end.replace(
                                                                      "\n", ""),
                                                                  docObj)

                            self.createXML(f.fields, areaXMLChild, docObj)

                            areaXML.appendChild(areaXMLChild)
                        else:
                            self.createXML(f.fields, areaXML, docObj)
                        if "\n" in f.end:
                            fieldXMLBr = docObj.createField("br", [],
                                                            "", [],
                                                            False, False)
                            areaXML.appendChild(fieldXMLBr)
                    else:
                        if not f:
                            continue
                        fields = self.splitToFields(f)
                        for field in fields:
                            if field.name is not False:
                                fieldXML = self.createFieldTerm(field.name,
                                                                field.value,
                                                                field.br,
                                                                docObj)
                                areaXML.appendChild(fieldXML)
                                if field.br[-1] == "\n":
                                    fieldXMLBr = docObj.createField("br", [],
                                                                    "", [],
                                                                    False,
                                                                    False)
                                    areaXML.appendChild(fieldXMLBr)
                            elif field.comment is not False:
                                fieldXML = docObj.createField("comment",
                                                              [field.comment],
                                                              "", [],
                                                              False, False)
                                areaXML.appendChild(fieldXML)
                            elif field.br is not False:
                                brText = field.br.replace("\n", "")
                                if brText:
                                    fieldXML = docObj.createField('br',
                                                                  [brText],
                                                                  "", [],
                                                                  False, False)
                                else:
                                    fieldXML = docObj.createField('br',
                                                                  [],
                                                                  "", [],
                                                                  False, False)
                                areaXML.appendChild(fieldXML)

                if i.header and i.start:
                    rootNode.appendChild(areaXML)
                if "\n" in i.end:
                    fieldXMLBr = docObj.createField("br", [], "", [],
                                                    False, False)
                    rootNode.appendChild(fieldXMLBr)

            else:
                fields = self.splitToFields(i)
                for field in fields:
                    if field.name is not False:
                        fieldXML = self.createFieldTerm(field.name,
                                                        field.value,
                                                        field.br, docObj)
                        rootNode.appendChild(fieldXML)
                        if field.br[-1] == "\n":
                            fieldXMLBr = docObj.createField("br", [], "", [],
                                                            False, False)
                            rootNode.appendChild(fieldXMLBr)
                    elif field.comment is not False:
                        fieldXML = docObj.createField("comment",
                                                      [field.comment],
                                                      "", [],
                                                      False, False)
                        rootNode.appendChild(fieldXML)
                    elif field.br is not False:
                        brText = field.br.replace("\n", "")
                        if brText:
                            fieldXML = docObj.createField('br', [brText], "",
                                                          [],
                                                          False, False)
                        else:
                            fieldXML = docObj.createField('br', [], "", [],
                                                          False, False)
                        rootNode.appendChild(fieldXML)
                        # rootNode.appendChild(areaXML)

    def textToXML(self):
        """Преобразуем текст в XML"""
        areas = []
        if self.text.strip():
            self.splitToAllArea(self.text, areas, self.reOpen, self.reClose,
                                self.reCloseArea, self.reComment,
                                self.reSepFields)
        docObj = xmlDoc()
        # Создание объекта документ c пустым разделителем между полями
        docObj.createDoc(self.configName, self.configVersion)
        if not areas:
            return docObj
        self.createXML(areas, docObj.getNodeBody(), docObj)
        return docObj

    def join(self, bindObj):
        """Объединяем конфигурации"""
        if isinstance(bindObj, bind):
            self.docObj.joinDoc(bindObj.doc)
