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

# Copyright 2008-2010 Mir Calculate Ltd. 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
import os
import cl_base
import stat
import re
import xml.dom.minidom
from xml import xpath
import subprocess
import types
import copy
import random
import string
import time

tr = cl_base.lang()
tr.setLocalDomain('cl_lib')
tr.setLanguage(sys.modules[__name__])


class _error:
    # Здесь ошибки, если они есть
    error = []
    def getError(self):
        """Выдать ошибки"""
        if not self.error:
            return False
        error = ""
        for e in self.error:
            error += e + "\n"
        return error

    def setError(self, error):
        """Установка ошибки"""
        self.error.append(error)
        return True


class _terms(_error):
    """Вычисление условий применяемых в профилях

    """
    # регулярное выражение для не версии
    _re_not_Version = re.compile("[^0-9\.]")

    def _convertVers(self, verA, verB):
        """Конвертирование номеров версий для корректного сравнения
        """
        elemA = verA.split(".")
        elemB = verB.split(".")
        if len(elemA) > len(elemB):
            maxElemB = len(elemB)-1
            for i in range(len(elemA)):
                if i > maxElemB:
                   elemB.append("0")
        else:
            maxElemA = len(elemA)-1
            for i in range(len(elemB)):
                if i > maxElemA:
                   elemA.append("0")
        for i in range(len(elemB)):
            lenA = len(elemA[i])
            lenB = len(elemB[i])
            if lenA == lenB:
                pass
            elif lenA > lenB:
                res = lenA - lenB
                for z in range(res):
                    elemB[i] = "0" + elemB[i]
            elif lenB > lenA:
                res = lenB - lenA
                for z in range(res):
                    elemA[i] = "0" + elemA[i]
        return  (".".join(elemA), ".".join(elemB))

    def _equalTerm(self, term, textError, function=False):
        """Вычисление логических выражений для условий

        Для корректной работы в классе который наследует этот класс
        должен быть объявлен аттрибут self.objVar
        (объект для работы с переменными)
        function - функция для  для обработки функций в заголовке блока
        """
        trm = {"&":" and ","||":" or "}
        rule = ["==", "!=", ">=", "<=", ">", "<"]
        listEqual = []
        for k in trm.keys():
            if k in term:
               term = term.replace(k,trm[k])
        trs = term.split(" ")
        for t in trs:
            flagRule = False
            for sepF in rule:
                if sepF in t:
                    flagRule = True
                    vals = t.split(sepF)
                    break

            if not flagRule:
                flagLog = False
                for k in trm.values():
                    if k.strip() == t:
                        flagLog = True
                        break
                if not flagLog:
                    self.setError("'%s'"%term + " " + _("incorrect"))
                    self.setError (textError)
                    return False
                else:
                    listEqual.append(k)
            else:
                #проверка на допустимость названия переменной
                reDenyName = re.compile("[^a-zA-Z0-9\_\-]")
                flagFunction = False
                if reDenyName.search(vals[0]):
                    #проверка на допустимость функции
                    flagError = True
                    if function:
                        reFunction = re.compile(\
                        "([a-zA-Z0-9\_\-]+)\([a-zA-Z0-9_\-\+\,\*\/\.\'\"~]+\)")
                        searchFunct = reFunction.search(vals[0])
                        if searchFunct:
                            flagError = False
                            flagFunction = True
                    if flagError:
                        self.setError("'%s'"%term + " " + _("incorrect"))
                        self.setError(textError)
                        return False
                #проверка на допустимость значения
                reDenyValue = re.compile("[^0-9a-zA-Z_\.-]")
                if reDenyValue.search(vals[1]):
                    self.setError("'%s'"%term + " " + _("incorrect"))
                    self.setError(textError)
                    return False
                flagIntTypeVar = None
                if flagFunction:
                    valVars = function("#-%s-#"%vals[0])
                    if valVars == "":
                        flagFunction = False
                    if valVars == False:
                        self.setError("'%s'"%term + " " + _("incorrect"))
                        self.setError(textError)
                        return False
                    if "load" == searchFunct.group(1):
                        if re.search("\(\s*num\s*,",vals[0]):
                            if valVars:
                                try:
                                    valVars = int(valVars)
                                except:
                                    self.setError("'%s'"%term + " " + \
                                    _("incorrect"))
                                    self.setError (textError)
                                    return False
                                flagIntTypeVar = True
                        else:
                            flagIntTypeVar = False
                else:
                    try:
                        valVars = self.objVar.Get(vals[0])
                    except self.objVar.DataVarsError, e:
                        print textError
                        print e
                        cl_base.exit(1)
                # Номера версий для ini
                flagNotIniFunct = True
                if flagFunction and "ini" == searchFunct.group(1):
                    # Если значение функции и значение версия
                    if not self._re_not_Version.search(vals[1]):
                        if not valVars:
                            valVars = "0"
                        if not self._re_not_Version.search(valVars):
                            verFile, verVar = self._convertVers(vals[1],valVars)
                            exec(\
                                "res=("+"'"+verVar+"'"+sepF+"'"+verFile+"'"+")")
                            if res:
                                listEqual.append("1")
                            else:
                                listEqual.append("0")
                            flagNotIniFunct = False
                # Cравниваем номера версий
                if flagNotIniFunct:
                    if "_ver" in vals[0] or \
                        (flagFunction and "pkg" == searchFunct.group(1)) or\
                        (flagFunction and "load" == searchFunct.group(1) and\
                        re.search("\(\s*ver\s*,",vals[0])):
                        # Проверка значения на версию
                        if self._re_not_Version.search(vals[1]):
                            self.setError("'%s'"%term + " " + _("incorrect"))
                            self.setError (_("Value is not version"))
                            return False
                        # Проверка значения функции на версию
                        if self._re_not_Version.search(valVars):
                            self.setError("'%s'"%term + " " + _("incorrect"))
                            self.setError (_("Value function is not version"))
                            return False
                        verFile, verVar = self._convertVers(vals[1],valVars)
                        exec("res=("+"'"+verVar+"'"+sepF+"'"+verFile+"'"+")")
                        if res:
                            listEqual.append("1")
                        else:
                            listEqual.append("0")
                    else:
                        if flagIntTypeVar == None:
                            flagIntTypeVar = True
                            try:
                                valVars = int(valVars)
                            except:
                                flagIntTypeVar = False
                        if flagIntTypeVar:
                            if not vals[1].strip():
                                vals[1] = 0
                            try:
                                valFile = int(vals[1])
                            except:
                                self.setError("'%s'"%term +" " +_("incorrect"))
                                self.setError (textError)
                                return False
                            valVar = valVars
                            exec("res=(%d%s%d)"%(valVar,sepF,valFile))
                            if res:
                                listEqual.append("1")
                            else:
                                listEqual.append("0")
                        else:
                            if sepF == "!=" or sepF == "==":
                                if not vals[1].strip():
                                    vals[1] = ""
                                valFile = vals[1]
                                valVar = valVars
                                exec(\
                                "res=("+'"""'+valVar+'"""'+sepF+"'"+valFile+\
                                        "'"+")")
                                if res:
                                    listEqual.append("1")
                                else:
                                    listEqual.append("0")
                            else:
                                if valVars == "":
                                    listEqual.append("0")
                                else:
                                    self.setError("'%s'"%term + " "\
                                        + _("incorrect"))
                                    self.setError (textError)
                                    return False
        exec("res=(%s)"%("".join(listEqual)))
        return res

class fileHeader(_terms):
    """Обработка заголовков профилей и конфигурационных файлов

    """
    # Допустимые параметры заголовка
    allowParam = ["format", "format_conf", "comment", "append", "force",
                  "link", "mirror", "symbolic", "chmod", "chown", "name"]
    # Корректность заголовка
    headerCorrect = True

    # Тип профиля
    fileType = ""
    # Тип вставки профиля
    typeAppend = ""
    # Возможные типы вставки профилей
    _fileAppend = "join", "before", "after", "replace", "remove"
    # Интерпретатор (#!/bin/bash) (#!/usr/bin/python)
    execStr = ""
    # Символ комментария
    comment = False
    # Выражение для поиска строки интерпретатора
    reExecStr = re.compile("^#!.+\s*",re.I)
    # условные операторы
    terms = ('>', '<', '==', '!=', '>=', '<=')
    # параметры без значения
    listParNotVal = ("symbolic", "force", "mirror")
    # Результат вычисления условия в заголовке
    headerTerm = True
    # Сообщение о ошибке
    errorMessage = ""

    def __init__(self, text, comment=False, fileType=False, objVar=False,
                 function=False):
        self.body = text
        # Объект с переменными
        self.objVar=objVar
        # Параметры описанные в заголовке файла профиля
        self.params = {}
        # некорректные параметры
        incorrectParams = set([])
        # Удаление Заголовка Calculate
        if comment:
            # В случае текста XML
            if type(comment) == types.TupleType and len(comment) == 2:
                _titleList = (_("Modified"), _("File of a profile"))
                reCalcHeader =\
                re.compile(u"\s*%s\s+%s.+Calculate.+\s+%s.+\s+%s\s?"%(\
                                                                     comment[0],
                                                  _titleList[0].decode("UTF-8"),
                                                  _titleList[1].decode("UTF-8"),
                                                                     comment[1],
                                                                        ),
                                                                 re.M|re.I|re.U)
                textUnicode = text.decode("UTF-8")
                reS = reCalcHeader.search(textUnicode)
                if reS:
                    textBody = textUnicode[:reS.start()]+textUnicode[reS.end():]
                    if textBody:
                        self.body = textBody.encode("UTF-8")
            else:
                reCalcHeader =\
                re.compile("\s*%s\-+\s+%s.+Calculate.+\s+%s.+\s+%s\-+\s?"%(\
                                                                        comment,
                                                                        comment,
                                                                        comment,
                                                                        comment,
                                                                        ),
                                                                      re.M|re.I)
                reS = reCalcHeader.search(text)
                if reS:
                    self.body = text[reS.end():]

        if fileType != False:
            if fileType=="bin":
                self.params["format"] = fileType
                self.fileType = self._getType()
                self.typeAppend = self._getAppend()
            else:
                textLines = text.splitlines()
                if textLines:
                    textLine = textLines[0]
                    rePar = re.compile("\s*#\s*calculate\s+",re.I)
                    reP = rePar.search(textLine)
                    if reP:
                        reL = False
                        reLns = re.compile(r"\A([^\\\n]*\\\n)+[^\n]*\n*",re.M)
                        reLs = reLns.search(text)
                        if reLs:
                            reL = reLs
                            paramLine = text[reP.end():reLs.end()]
                            paramLine = paramLine.replace("\\"," ")
                        else:
                            reLn = re.compile("\n")
                            reL = reLn.search(text)
                            paramLine = textLine[reP.end():]
                        if reL:
                            self.body = text[reL.end():]
                        else:
                            self.body = ""
                        paramList = re.split("\s+",paramLine)
                        if paramList:
                            for i in paramList:
                                foundTerm = False
                                for term in self.terms:
                                    if term in i:
                                        foundTerm = True
                                        if function:
                                            rezTerm = self._equalTerm(i,\
                                            _("header profile not valid: ") + \
                                              i,function)
                                        else:
                                            rezTerm = self._equalTerm(i,\
                                            _("header profile not valid: ") + \
                                              i)
                                        if not rezTerm:
                                            self.headerTerm = False
                                        break
                                if not foundTerm:
                                    par = i.split("=")
                                    if len(par) == 1:
                                        if i in self.listParNotVal:
                                            self.params[i] = "True"
                                        else:
                                            if i.strip():
                                                incorrectParams = set([i])
                                    elif len(par) == 2:
                                        self.params[par[0]] = par[1]

                    self.comment = self._getComment()
                self.fileType = self._getType()
                self.typeAppend = self._getAppend()
                reExecRes = self.reExecStr.search(self.body)
                if reExecRes:
                    self.execStr = self.body[reExecRes.start():reExecRes.end()]
                    self.body = self.body[reExecRes.end():]
        if not incorrectParams:
            incorrectParams = set(self.params.keys()) - set(self.allowParam)
        if incorrectParams:
            self.headerTerm = False
            self.headerCorrect = False
            self.errorMessage = _("incorrect header parameters - '%s'")\
            % " ".join(list(incorrectParams))

    def _getType(self):
        """Выдать тип файла"""
        if self.params.has_key("format"):
            return self.params["format"]
        else:
            return "raw"

    def _getAppend(self):
        """Выдать тип добавления файла"""
        if self.params.has_key("append") and self.params["append"] in\
            self._fileAppend:
            return self.params["append"]
        else:
            if self.fileType != "raw" and self.fileType != "bin" and\
                self.fileType != "":
                self.params["append"] = "join"
                return "join"
            self.params["append"] = "replace"
            return "replace"

    def _getComment(self):
        """Выдать символ комментария файла"""
        if self.params.has_key("comment"):
            return self.params["comment"]
        else:
            return False


class dirHeader(_terms):
    """Обработка заголовков профилей директорий

    """
    # Допустимые параметры заголовка
    allowParam = ["append", "chmod", "chown", "name"]
    # Корректность заголовка
    headerCorrect = True

    # Тип вставки профиля
    typeAppend = ""
    # Возможные типы вставки профилей
    _fileAppend = "join", "remove"
    # условные операторы
    terms = ('>', '<', '==', '!=', '>=', '<=')
    # параметры без значения
    listParNotVal = ("symbolic", "force")
    # Результат вычисления условия в заголовке
    headerTerm = True
    # Сообщение о ошибке
    errorMessage = ""

    def __init__(self, text, objVar=False, function=False):
        self.body = text
        # Объект с переменными
        self.objVar=objVar
        # Параметры описанные в заголовке файла профиля
        self.params = {}
        # некорректные параметры
        incorrectParams = set([])

        textLines = text.splitlines()
        flagErrorBody = False
        if textLines:
            textLine = textLines[0]
            rePar = re.compile("\s*#\s*calculate\s+",re.I)
            reP = rePar.search(textLine)
            if reP:
                reL = False
                reLns = re.compile(r"\A([^\\\n]*\\\n)+[^\n]*\n*",re.M)
                reLs = reLns.search(text)
                if reLs:
                    reL = reLs
                    paramLine = text[reP.end():reLs.end()]
                    paramLine = paramLine.replace("\\"," ")
                else:
                    reLn = re.compile("\n")
                    reL = reLn.search(text)
                    paramLine = textLine[reP.end():]
                if reL:
                    self.body = text[reL.end():]
                else:
                    self.body = ""
                if self.body.strip():
                    self.headerTerm = False
                    self.headerCorrect = False
                    self.errorMessage = _("incorrect text in profile: '%s'")\
                                          %self.body
                    flagErrorBody = True
                if not flagErrorBody:
                    paramList = re.split("\s+",paramLine)
                    if paramList:
                        for i in paramList:
                            foundTerm = False
                            for term in self.terms:
                                if term in i:
                                    foundTerm = True
                                    if function:
                                        rezTerm = self._equalTerm(i,\
                                        _("header profile not valid: ") + \
                                            i,function)
                                    else:
                                        rezTerm = self._equalTerm(i,\
                                        _("header profile not valid: ") + \
                                            i)
                                    if not rezTerm:
                                        self.headerTerm = False
                                    break
                            if not foundTerm:
                                par = i.split("=")
                                if len(par) == 1:
                                    if i in self.listParNotVal:
                                        self.params[i] = "True"
                                    else:
                                        if i.strip():
                                            incorrectParams = set([i])
                                elif len(par) == 2:
                                    self.params[par[0]] = par[1]
                    self.typeAppend = self._getAppend()
        if not flagErrorBody:
            if not incorrectParams:
                incorrectParams = set(self.params.keys()) - set(self.allowParam)
            if incorrectParams:
                self.headerTerm = False
                self.headerCorrect = False
                self.errorMessage = _("incorrect header parameters - '%s'")\
                % " ".join(list(incorrectParams))

    def _getAppend(self):
        """Выдать тип добавления директории"""
        if self.params.has_key("append") and self.params["append"] in\
            self._fileAppend:
            return self.params["append"]
        else:
            return "join"

class objShare:
    """Общий клас для объектов, наследуем

    """

    def createFieldTerm(self, name, value, quote, docObj):
        """Создание поля переменная - значение

        при создании поля проверяется первый символ названия переменной
        и добавляется тег action
        "!" - <action>drop</action> удаляет
        "+" - <action>join</action> добавляет
        "-" - <action>replace</action> заменяет
        """
        fieldAction = False
        if name:
            if name[0] == "!" or name[0] == "-" or name[0] == "+":
                qnt = self.removeSymbolTerm(quote)
                fieldXML = docObj.createField("var",[qnt],
                                              name[1:], [value],
                                              False, False)
                if name[0] == "!":
                    fieldAction = "drop"
                elif name[0] == "+":
                    fieldXML.setAttribute("type", "seplist")
                    fieldAction = "join"
            else:
                fieldXML = docObj.createField("var",
                                              [quote.replace("\n","")],
                                              name, [value],
                                              False, False)
        else:
            fieldXML = docObj.createField("var",
                                          [quote.replace("\n","")],
                                          name, [value],
                                          False, False)
        if fieldAction:
            docObj.setActionField(fieldXML, fieldAction)
        return fieldXML

    def removeSymbolTerm(self, text):
        """Удаляет первый символ названия переменной в строке

        Если первый встречающийся символ с начала строки
        '+', '-', '!' то он из этой строки будет удален,
        если перед этим символом были пробельные символы,
        то они будут сохранены, так-же если в строке есть символ
        перевода строки он будет удален.
        """
        reTerm = re.compile("^[ \t]*(\!|\+|\-)")
        textNS = text.replace("\n","")
        res = reTerm.search(textNS)
        if res:
            textNS = textNS[res.start():res.end()-1] + textNS[res.end():]
        return textNS

    def getConfig(self):
        """Выдает конфигурационный файл"""
        listConfigTxt = []
        childNodes = self.docObj.getNodeBody().childNodes
        for node in childNodes:
            if node.nodeType == node.ELEMENT_NODE:
                if node.tagName == "field":
                    listConfigTxt.append(self.docObj.getQuoteField(node))
                elif node.tagName == "area":
                    self.docObj.xmlToText([node], listConfigTxt)
        return "".join(listConfigTxt)


    def splitToFields(self, txtBloc):
        """Разбиваем текст на поля (объекты) которые имеют следующие аттрибуты

        self.name  - если переменная то имя переменной
        self.value  - если у переменной есть значение то значение переменной
        self.comment - если комментарий то текст комментария
        self.br - если перевод строки то текст перед переводом из пробелов

        Результат список объектов полей
        """
        finBloc = "\n"
        if txtBloc[-1] != "\n":
            finBloc = ""

        linesBlocTmp = txtBloc.splitlines()
        linesBloc = []
        brBloc = []
        z = 0
        lenLines = len(linesBlocTmp)
        for i in linesBlocTmp:

            if self.reComment.split(i)[0]:
                findCooment = self.reComment.search(i)
                comment = False
                par = i
                if findCooment:
                    par = i[:findCooment.start()]
                    comment = i[findCooment.start():]
                fields = self.reSepFields.split(par)
                lenFields = len(fields)

                if lenFields>1:
                    for fi in range(lenFields-1):
                        linesBloc.append(fields[fi]+ self.sepFields)
                        if fi == lenFields-2:
                            if comment:
                                brBloc.append("")
                            else:
                                if (lenLines-1)== z:
                                    brBloc.append(finBloc)
                                else:
                                    brBloc.append("\n")
                        else:
                            brBloc.append("")
                    if comment:
                        linesBloc.append(comment)
                        if (lenLines-1)== z:
                            brBloc.append(finBloc)
                        else:
                            brBloc.append("\n")
                else:
                    linesBloc.append(i)
                    if (lenLines-1)== z:
                        brBloc.append(finBloc)
                    else:
                        brBloc.append("\n")
            else:
                linesBloc.append(i)
                if (lenLines-1)== z:
                    brBloc.append(finBloc)
                else:
                    brBloc.append("\n")
            z +=1
        fields = self.setDataField(linesBloc, brBloc)
        return fields

class xmlShare:
    """Общий класс для объектов XML, наследуем

    """
    def _createElement(self, doc, tagName, text="", attributes={}):
        """Создание нового XML элемента"""
        element = doc.createElement(tagName)
        if text:
            txtNode = doc.createTextNode(self._toUNICODE(text))
            element.appendChild(txtNode)
        for attr in attributes.keys():
            attribute = doc.createAttribute(attr)
            attribute.nodeValue = attributes[attr]
            element.setAttributeNode(attribute)
        return element

    def _toUNICODE(self,val):
        """перевод текста в юникод"""
        if 'unicode' in "%s" %(type(val)):
            return val
        else:
            return val.decode('UTF-8')


class xmlNode(xmlShare):
    """Класс для создания нод без аттрибутов

    """
    def __init__(self):
        self.node = False


    def createNode(self, doc, tagName, text=""):
        """Создает XML элемент без аттрибутов"""
        self.node=self._createElement(doc, tagName, text)
        return self.node

    def getNode(self):
        return self.node


class xmlCaption:
    """Класс XML заголовок

    """
    def __init__(self):
        #Заголовок области XML нода
        self.caption = False


    def createCaption(self, doc, name, quotes, action=False):
        """Создание заголовка области"""
        tmpNode = xmlNode()
        self.caption = tmpNode.createNode(doc, "caption")
        nameNode = tmpNode.createNode(doc, "name",name)
        self.caption.appendChild(nameNode)
        if action:
           actNode = tmpNode.createNode(doc, "action", action)
           self.caption.appendChild(actNode)
        for q in quotes:
            quoteNode = tmpNode.createNode(doc, "quote", q)
            self.caption.appendChild(quoteNode)
        return self.caption

    def getCaption(self):
        """Выдает XML ноду заголовка области"""
        return self.caption

class xmlField(xmlShare):
    """Класс для работы с XML полем

    """
    def __init__(self):
        # XML нода поле
        self.field = False


    def createField(self, doc, typeField, quotes, name="",
                    values=[],action=False):
        """Cоздание XML ноды поле"""
        self.field = self._createElement(doc, "field", "", {"type":typeField})
        if name:
            nameNode = self._createElement(doc, "name", name)
            self.field.appendChild(nameNode)
        for v in values:
            valueNode = self._createElement(doc, "value", v)
            self.field.appendChild(valueNode)
        if action:
           actNode = self._createElement(doc, "action", action)
           self.field.appendChild(actNode)
        for q in quotes:
            quoteNode = self._createElement(doc, "quote", q)
            self.field.appendChild(quoteNode)
        return self.field



class xmlFields:
    """Класс, в котором находится список ХМL нод field

    """
    def __init__(self):
        self.fields = []

    def appendField(self, field):
        """Добавить XML ноду field"""
        self.fields.append(field)
        return self.fields

    def getFields(self):
        """Выдать список XML нод"""
        return self.fields


class xmlArea:
    """Класс для работы с XML областью

    """
    def __init__(self):
        # Область
        self.area = False

    def createArea(self, doc, xmlCaption, xmlFields):
        """Создание XML области"""
        tmpNode = xmlNode()
        self.area = tmpNode.createNode(doc, "area")
        if xmlCaption and xmlCaption.getCaption():
            self.area.appendChild(xmlCaption.getCaption())
        if xmlFields:
            fields = xmlFields.getFields()
            for field in fields:
                self.area.appendChild(field)
        return self.area

class xmlDoc:
    """Класс для работы с XML документом

    """
    def __init__(self):
        # документ
        self.doc = False
        # главная нода
        self.root = False
        # тело документа
        self.body = False
        # Заголовок области - временный (в реальности один объект заголовок)
        self.tmpCaption = False
        # Поля - временные (в реальности один объект поля)
        self.tmpFields = False
        # Разделитель областей - по умолчанию перевод строки "\n"
        self.sepAreas  = False
        # Разделитель разделенных списков - по умолчанию перевод строки "\n"
        #self.sepSplitFields  = False


    def createDoc(self, typeDoc, version):
        """Создание нового документа новый документ"""
        docTxt = '<?xml version="1.0" encoding="UTF-8"?><cxmlconf><head>'
        docTxt += '<ver>%s</ver>'% version
        docTxt += '<format>%s</format>' % typeDoc
        docTxt += '</head><body></body></cxmlconf>'
        self.doc = xml.dom.minidom.parseString(docTxt)
        self.root = self.doc.documentElement
        self.body = xpath.Evaluate('child::body',self.root)[0]
        # установка разделителя областей
        self.sepAreas  = self.createField("br",[],"",[],False,False)
        # установка разделителя областей разделенных списков
        #self.sepSplitFields  = self.createField("br",[],"",[],False,False)
        return self.doc

    def addField(self, field):
        """Добавляет поле во временный список

        Из этого списка в дальнейшем формируется XML область
        """
        if not self.tmpFields:
            self.tmpFields = xmlFields()
        self.tmpFields.appendField(field)

    def createCaption(self, name, quotes, action=False):
        """Cоздает заголовок области

        Помещает заголовок в временный артибут
        Используется при создании области
        """
        self.tmpCaption = xmlCaption()
        return self.tmpCaption.createCaption(self.doc, name, quotes, action)

    def createField(self, typeField, quotes=[], name="",
                    values=[] ,action=False,addTmpField=True):
        """Cоздает поле

        Если установлена переменнная addTmpField
        добавляет поле во временный список
        """
        fieldObj = xmlField()
        field = fieldObj.createField(self.doc, typeField, quotes, name,
                                    values, action)
        if addTmpField:
            self.addField(field)
        return field

    def clearTmpFields(self):
        """Очищает временный список"""
        self.tmpFields = False

    def createArea(self):
        """Cоздает область

        Область создается на основании временного атрибута и временного списка
        """
        areaObj = xmlArea()
        area = areaObj.createArea(self.doc, self.tmpCaption, self.tmpFields)
        self.clearTmpCaptionAndFields()
        return area

    def clearTmpCaptionAndFields(self):
        """Очищает временный аттрибут и временный список"""
        self.tmpCaption = False
        self.tmpFields = False

    def getNodeRoot(self):
        """Выдает корневую ноду"""
        return self.root

    def getNodeBody(self):
        """Выдает ноду body"""
        return self.body

    def setActionField(self, xmlField, actionTxt):
        """Устанавливает свойство action для XML поля"""
        xmlActions = xpath.Evaluate('child::action',xmlField)
        if xmlActions and xmlActions[0].firstChild:
            xmlActions[0].firstChild.nodeValue = actionTxt
        else:
            nodeObj = xmlNode()
            newNode = nodeObj.createNode(self.doc, "action", actionTxt)
            xmlField.appendChild(newNode)


    def setActionArea(self, xmlArea, actionTxt):
        """Устанавливает свойство action для XML области"""
        xmlActions = xpath.Evaluate('child::caption/action',xmlArea)
        xmlCaptions = xpath.Evaluate('child::caption',xmlArea)
        if xmlActions and xmlActions[0].firstChild:
            xmlActions[0].firstChild.nodeValue = actionTxt
        else:
            if xmlCaptions:
                nodeObj = xmlNode()
                newNode = nodeObj.createNode(self.doc, "action", actionTxt)
                xmlCaptions[0].appendChild(newNode)

    def joinField(self, xmlArea, xmlNewField):
        """Объединяет XML ноду область и XML ноду поле"""
        newNameField = self.getNameField(xmlNewField)
        if not newNameField or not newNameField.strip():
            return False
        fieldsOldComp = xpath.Evaluate("child::field[child::name='%s']"\
                                    %(newNameField), xmlArea)
        # Если поле не найдено добавляем его
        typeNewField = self.getTypeField(xmlNewField)
        if not fieldsOldComp and typeNewField  != "seplist":
            if self.getActionField(xmlNewField) != "drop":
                self.setActionField(xmlNewField, "append")
                xmlArea.appendChild(xmlNewField)
            return True
        newFieldsAction = self.getActionField(xmlNewField)
        newValues = self.getFieldValues(xmlNewField)
        flagCompare = True

        for nodeFieldOld in fieldsOldComp:
            if newFieldsAction == "drop":
                if nodeFieldOld.nextSibling and\
                    self.getTypeField(nodeFieldOld.nextSibling) == "br":
                        xmlArea.removeChild(nodeFieldOld.nextSibling)
                elif nodeFieldOld.previousSibling and\
                    self.getTypeField(nodeFieldOld.previousSibling) == "br":
                        xmlArea.removeChild(nodeFieldOld.previousSibling)
                xmlArea.removeChild(nodeFieldOld)
                continue
            oldValues = self.getFieldValues(nodeFieldOld)
            # Сравнение значений переменной профиля и файла
            if set(newValues) != set(oldValues):
                flagCompare = False
        if self.getActionField(xmlNewField) == "drop":
            return True
        appSplLst = []
        insSplLst = []
        if typeNewField  == "seplist":
            if fieldsOldComp:
                xmlOldField = fieldsOldComp[-1]
            else:
                xmlOldField = False
            seplistNewXML = self.getSepListToField(xmlNewField)
            if seplistNewXML:
                for nodeSeplist in seplistNewXML:
                    if self.getActionField(nodeSeplist) != "drop":
                        if newFieldsAction == "join":
                            flagCompareSeplist = False
                            newValues = self.getFieldValues(nodeSeplist)
                            for nodeFieldOld in fieldsOldComp:
                                oldValues = self.getFieldValues(nodeFieldOld)
                                for newValue in newValues:
                                    if newValue in oldValues:
                                        flagCompareSeplist = True
                                        break
                            if not flagCompareSeplist:
                                nextNode = xmlOldField.nextSibling
                                newInsNode = nodeSeplist.cloneNode(True)
                                self.setActionField(newInsNode,"append")

                                if nextNode:
                                    appSplLst.append((newInsNode,
                                                        nextNode,
                                                        "insert"))
                                else:
                                    appSplLst.append((newInsNode,
                                                        False,
                                                        "append"))
                        else:
                            newInsNode = nodeSeplist.cloneNode(True)
                            if self.getActionField(newInsNode) == "join":
                                self.setActionField(newInsNode,"append")
                            if xmlOldField:
                                insSplLst.append((newInsNode,
                                                  xmlOldField,
                                                  "insert"))
                            else:
                                insSplLst.append((newInsNode,
                                                  False,
                                                  "append"))

                            #xmlArea.insertBefore(\
                                #nodeSeplist.cloneNode(True),
                                #xmlOldField)

                        parentNode = nodeSeplist.parentNode
                        parentNode.removeChild(nodeSeplist)

                insNodesRepl = []
                for newNode, nxtNode, app in insSplLst:
                    flagCompareSeplist = False
                    newValues = self.getFieldValues(newNode)
                    for nodeRepl, nxtNode, app in insNodesRepl:
                        oldValues = self.getFieldValues(nodeRepl)
                        for newValue in newValues:
                            if newValue in oldValues:
                                flagCompareSeplist = True
                                break
                    if not flagCompareSeplist:
                        if xmlOldField:
                            insNodesRepl.append((newNode, nxtNode, app))

                for newNode, nxtNode, app in insNodesRepl:
                    if app == "insert":
                        xmlArea.insertBefore(newNode,nxtNode)
                    elif app == "append":
                        xmlArea.appendChild(newNode)
                if xmlOldField:
                    parentNode = xmlOldField.parentNode
                    if parentNode and newFieldsAction != "join":
                        parentNode.removeChild(xmlOldField)

        for newNode, nxtNode, app in appSplLst:
            if app == "insert":
                xmlArea.insertBefore(newNode,nxtNode)
            elif app == "append":
                xmlArea.appendChild(newNode)

        if not flagCompare and typeNewField  != "seplist":
            # Устанавливаем action=replace
            self.setActionField(xmlNewField, "replace")
            # Если параметры поля не сходятся заменяем поле
            xmlArea.replaceChild(xmlNewField.cloneNode(True),
                                             fieldsOldComp[-1])

        if newFieldsAction == "join":
            fieldsOldRemove = []
        else:
            fieldsOldRemove = fieldsOldComp[:-1]

        for nodeFieldOld in fieldsOldRemove:
            actionOldNode = self.getActionField(nodeFieldOld)
            if actionOldNode == "insert" or actionOldNode == "append":
                pass
            else:
                if nodeFieldOld.nextSibling and\
                    self.getTypeField(nodeFieldOld.nextSibling) == "br":
                        xmlArea.removeChild(nodeFieldOld.nextSibling)
                xmlArea.removeChild(nodeFieldOld)
        return True


    def getSepListToField(self, xmlField):
        """Выдает элементы распределенного массива

        Область предок поля, в этой области ищутся
        элементы распределенного массива
        """
        nameField = self.getNameField(xmlField)
        if not nameField:
            return []
        parentNode = xmlField.parentNode
        #print parentNode.toprettyxml()
        if parentNode:
            fieldsVal = xpath.Evaluate(\
            "child::field[attribute::type='seplist'][child::name='%s'] "\
            %(nameField), parentNode)
            #print nameField
            return fieldsVal
        else:
            return []

    def removeComment(self, xmlArea):
        """Удаляет комментарии в XML области"""
        fieldNodes = xpath.Evaluate('descendant::field',xmlArea)
        for fieldNode in fieldNodes:
            if fieldNode.hasAttribute("type"):
                if fieldNode.getAttribute("type") == "comment" or\
                    fieldNode.getAttribute("type") == "br":
                    parentNode = fieldNode.parentNode
                    parentNode.removeChild(fieldNode)
                else:
                    if self.getActionField(fieldNode) == "drop":
                        pass
                    elif self.getActionField(fieldNode) == "join":
                        pass
                    else:
                        self.setActionField(fieldNode,"append")


    def joinBody(self, baseBody, newBody):
        """Объединяет две области Body"""
        newFields = xpath.Evaluate('child::field',newBody)
        xmlNewAreas = xpath.Evaluate('child::area',newBody)
        for xmlNewArea in xmlNewAreas:
            self.joinArea(baseBody,xmlNewArea)
        joinNewFields = xpath.Evaluate("child::field[child::action='join']"
                                       ,newBody)
        self.addNewFielsOldArea(newFields, joinNewFields, baseBody)


    def getRemoveNodeSepList(self, removeNodesDict, baseNode, xmNewlField):
        """Находит элементы разделенного списка

        Параметры:
        removeNodesDict - Cловарь удаляемых полей разделенного списка
                          формируется программой
        baseNode        - Нода в которой идет поиск
        xmNewlField     - Нода field которая проверяется на принадлежность
                          к разделенному списку
        """
        flagNewNodeSeplist = False
        if self.getTypeField(xmNewlField) == "seplist":
            flagNewNodeSeplist = True
        nameNewField = self.getNameField(xmNewlField)
        if nameNewField:
            if removeNodesDict.has_key(nameNewField):
                return removeNodesDict[nameNewField]
            else:
                oldFields = xpath.Evaluate('child::field', baseNode)
                removeNodes = []
                lenOldFields = len(oldFields)
                for i in range(lenOldFields):
                    oldNode = oldFields[i]
                    flagSep = self.getTypeField(oldNode) == "seplist"
                    if flagNewNodeSeplist:
                        flagSep = True
                    if  flagSep and\
                        nameNewField == self.getNameField(oldNode):
                        removeNodes.append(oldNode)
                        if i+1<lenOldFields:
                            nextNode = oldFields[i+1]
                            if self.getTypeField(nextNode) == "br":
                                removeNodes.append(nextNode)
                removeNodesDict[nameNewField] = removeNodes
                return removeNodes


    def addNewFielsOldArea(self, newFields, joinNewFields, xmlOldArea):
        """Добавляет новые XML поля в область профиля"""
        removeNodesDict = {}
        notRemoveNodesDict = {}
        for notRemNode in joinNewFields:
            nameField = self.getNameField(notRemNode)
            if not notRemoveNodesDict.has_key(nameField):
                notRemoveNodesDict[nameField] = []
                notRemoveNodesDict[nameField].append(notRemNode)
            else:
                notRemoveNodesDict[nameField].append(notRemNode)
        notSepListField = []
        sepListField = []
        for nField in newFields:
            if self.getRemoveNodeSepList(removeNodesDict, xmlOldArea,
                                         nField):
                sepListField.append(nField)
            else:
                if self.getNameField(nField):
                    notSepListField.append(nField)
        for name in notRemoveNodesDict.keys():
            if removeNodesDict.has_key(name):
                removeNodesDict[name] = []
        for removeNodes in  removeNodesDict.values():
            if removeNodes:
                if self.getTypeField(removeNodes[-1]) == "seplist":
                    removeNodes = removeNodes[:-1]
                else:
                    removeNodes = removeNodes[:-2]

            for removeNode in removeNodes:
                xmlOldArea.removeChild(removeNode)
        for node in sepListField:
            node.setAttribute("type", "seplist")
            if not (self.getActionField(node) == "join" or\
            self.getActionField(node) == "drop"):
                self.setActionField(node,"insert")
            self.joinField(xmlOldArea, node)
            #else:
                #self.setActionField(node, "append")
                #baseBody.appendChild(node)
        for node in notSepListField:
            if self.getTypeField(node) == "seplist":
                #if removeNodesDict.has_key(self.getNameField(node)):
                    #print removeNodesDict[self.getNameField(node)]
                self.setActionField(node, "append")
                xmlOldArea.appendChild(node)
            else:
                self.joinField(xmlOldArea, node)

    def insertBeforeSepAreas(self, xmlArea):
        """Добавляет разделитель областей перед каждой областью"""
        if not self.sepAreas:
            return False
        areaNodes = xpath.Evaluate('descendant::area',xmlArea)
        for areaNode in areaNodes:
            prevNode = areaNode.previousSibling
            if prevNode:
                parentNode = areaNode.parentNode
                parentNode.insertBefore(self.sepAreas.cloneNode(True),
                                        areaNode)
        return True

    def getAreaFields(self, nameArea, xmlArea):
        """По имени области выводит названия и значения всех переменных

        поиск ведется только в 1-х потомках области xmlArea
        на выход словарь переменных {имя:значение}
        """
        namesAreaComare = xpath.Evaluate(\
            "child::area/child::caption[child::name='%s']" %(nameArea),
                    xmlArea)
        if not namesAreaComare:
            return False
        fields = xpath.Evaluate("child::field/child::name",
                                 namesAreaComare[0].parentNode)
        dictVar = {}
        for fieldName in fields:
            nodeField = fieldName.parentNode
            fieldValue = xpath.Evaluate("child::value",nodeField)
            name = fieldName.firstChild.nodeValue
            value = ""
            if fieldValue and fieldValue[0].firstChild:
                value = fieldValue[0].firstChild.nodeValue
            dictVar[name] = value
        return dictVar

    def getAreaFieldValues(self, nameArea, nameField, xmlArea):
        """По имени области и имени переменной выводит значениe переменной

        поиск ведется только в 1-х потомках области xmlArea
        """
        namesAreaComare = xpath.Evaluate(\
            "child::area/child::caption[child::name='%s']" %(nameArea),
                    xmlArea)
        fieldsVal = False
        for areaComp in namesAreaComare:
            fieldsVal = xpath.Evaluate(\
            "child::field[child::name='%s'] "\
            %(nameField), areaComp.parentNode)
            if fieldsVal:
                break
        if not fieldsVal:
            return False
        fieldValue = xpath.Evaluate("child::value",
             fieldsVal[0])
        return fieldValue[0].firstChild.nodeValue

    def getAllAreas(self):
        """Выдает все области"""
        return xpath.Evaluate('descendant::area', self.body)

    def getArea(self, nameArea, xmlArea):
        """По имени области находит области (первый потомок xmlArea)"""
        namesAreaComare = xpath.Evaluate(\
            "child::area/child::caption[child::name='%s']" %(nameArea),
                    xmlArea)
        return map(lambda x: x.parentNode, namesAreaComare)


    def joinArea(self, baseNode, xmlNewArea):
        """Объединяет область c областью Body (xmlNewArea c baseNode)"""
        def appendArea(baseNode, xmlNewArea):
            fieldsRemove = xpath.Evaluate(\
            "descendant::field[child::action='drop']", xmlNewArea)
            for rmNode in fieldsRemove:
                parentNode = rmNode.parentNode
                parentNode.removeChild(rmNode)
            captionAreasRemove = xpath.Evaluate(\
                    "descendant::area/child::caption[child::action='drop']",
                    xmlNewArea)
            for rmNodeCapt in captionAreasRemove:
                rmNode = rmNodeCapt.parentNode
                parentNode = rmNode.parentNode
                parentNode.removeChild(rmNode)
            self.setActionArea(xmlNewArea, "append")
            # Добавляем разделитель областей во вложенные области
            areaNodes = xpath.Evaluate('descendant::area',xmlNewArea)
            for areaNode in areaNodes:
                self.setActionArea(areaNode,"append")
                parentNode = areaNode.parentNode
                parentNode.insertBefore(self.sepAreas.cloneNode(True),
                                        areaNode)
            baseNode.appendChild(xmlNewArea)
            # Добавляем разделитель областей
            baseNode.insertBefore(self.sepAreas.cloneNode(True), xmlNewArea)

        nodesNames = xpath.Evaluate('child::area/caption/name',baseNode)
        nodesNewArea = xpath.Evaluate('child::caption/name',xmlNewArea)
        if not nodesNames:
            # Добавляем область
            if nodesNewArea:
                newAreaAction = self.getActionArea(xmlNewArea)
                if not (newAreaAction == "drop" or newAreaAction == "replace"):
                    appendArea(baseNode, xmlNewArea)
            return True
        if not nodesNames or not nodesNewArea:
            return False
        nameArea = ""
        if nodesNewArea[0].firstChild:
            nameArea = nodesNewArea[0].firstChild.nodeValue.strip()
        flagFindArea = False
        baseNodes = []
        for oName in nodesNames:
            newAreaAction = self.getActionArea(xmlNewArea)
            oArea = oName.parentNode.parentNode
            oNameTxt = ""
            if oName.firstChild:
                oNameTxt = oName.firstChild.nodeValue
            if nameArea == oNameTxt:
                flagFindArea = True
                # При использовании удаления
                if newAreaAction == "drop":
                    prevNode = oName.parentNode.parentNode.previousSibling
                    removePrevNodes = []
                    while (prevNode) and self.getTypeField(prevNode) == "br":
                        removePrevNodes.append(prevNode)
                        prevNode = prevNode.previousSibling
                    for removeNode in removePrevNodes:
                        baseNode.removeChild(removeNode)
                    baseNode.removeChild(oName.parentNode.parentNode)
                    continue
                elif newAreaAction == "replace":
                    oldAreaNode = oName.parentNode.parentNode
                    newAreaCaption = xpath.Evaluate('child::caption',
                                                    xmlNewArea)[0]
                    oldAreaCaption = xpath.Evaluate('child::caption',
                                                    oldAreaNode)[0]
                    if newAreaCaption and oldAreaCaption:
                        xmlNewArea.replaceChild(oldAreaCaption,newAreaCaption)
                        self.setActionArea(xmlNewArea,"replace")
                    baseNode.replaceChild(xmlNewArea,
                                          oldAreaNode)
                    continue
                baseNodes.append(oName.parentNode.parentNode)
                newFields = xpath.Evaluate('child::field',xmlNewArea)

                joinNewFields = xpath.Evaluate(\
                    "child::field[child::action='join']"
                                       ,xmlNewArea)
                self.addNewFielsOldArea(newFields, joinNewFields, oArea)


        if not flagFindArea:
            # Добавляем область
            if not (newAreaAction == "drop" or\
                    newAreaAction == "replace"):
                appendArea(baseNode, xmlNewArea)
        else:
            tmpXmlNewAreas = xpath.Evaluate('child::area',xmlNewArea)
            for na in tmpXmlNewAreas:
                for bn in baseNodes:
                    self.joinArea(bn, na)
        return True


    def joinDoc(self, xmlNewDoc):
        """Объединяет два документа"""
        newRootNode = xmlNewDoc.documentElement
        newBodyNode = xpath.Evaluate('child::body',newRootNode)[0]
        newImportBodyNode = self.doc.importNode(newBodyNode, True)
        # Перед объединение области с документом
        # удаляем комментарии
        self.removeComment(newImportBodyNode)
        self.joinBody(self.body, newImportBodyNode)
        # расставляем BR
        self.insertBRtoBody(self.body)

    def getQuoteField(self, xmlField):
        """Выдает текст из поля"""
        xmlQuotes = xpath.Evaluate('child::quote',xmlField)
        br = ""
        if xmlField.hasAttribute("type") and\
            xmlField.getAttribute("type") == "br":
            br = "\n"
        if xmlQuotes:
            field = xmlQuotes[0]
            if field.firstChild:
                return field.firstChild.nodeValue + br
        return "" + br

    def getFieldsArea(self, xmlArea):
        """Выдает потомков XML области"""
        xmlFields = []
        childNodes = xmlArea.childNodes
        for node in childNodes:
            if node.nodeType == node.ELEMENT_NODE:
                if node.tagName == "area" or node.tagName == "field":
                    xmlFields.append(node)
        return xmlFields

    def getTypeField(self, xmlField):
        """Выдает тип поля"""
        if xmlField.hasAttribute("type"):
            return xmlField.getAttribute("type")
        else:
            return False

    def getNameField(self, xmlField):
        """Выдает имя поля"""
        xmlNameFields = xpath.Evaluate('child::name', xmlField)
        if xmlNameFields and xmlNameFields[0].firstChild:
            return xmlNameFields[0].firstChild.nodeValue
        else:
            return False

    def getNameArea(self, xmlArea):
        """Выдает имя области"""
        xmlNameAreas = xpath.Evaluate('child::caption/name', xmlArea)
        if xmlNameAreas and xmlNameAreas[0].firstChild:
            return xmlNameAreas[0].firstChild.nodeValue
        else:
            return False

    def xmlToText(self, xmlAreas, text):
        """Преобразует список XML областей в текст"""
        def getQuotesArea(xmlArea):
            quotes = []
            xmlQuotes = xpath.Evaluate('child::caption/quote',xmlArea)
            for node in xmlQuotes:
                if node.firstChild:
                    quotes.append(node.firstChild.nodeValue)
            if len(quotes) == 0:
                quotes.append("")
                quotes.append("")
            elif len(quotes) == 1:
                quotes.append("")
            return quotes

        for i in xmlAreas:
            if i.tagName == "area":
                quotesI = getQuotesArea(i)
                startAreaI = quotesI[0]
                endAreaI = quotesI[1]
                text.append(startAreaI)
                xmlFieldsI = self.getFieldsArea(i)
                for f in xmlFieldsI:
                    if f.tagName == "area":
                        quotesF = getQuotesArea(f)
                        startAreaF = quotesF[0]
                        endAreaF = quotesF[1]
                        text.append(startAreaF)
                        xmlFieldsF = self.getFieldsArea(f)
                        self.xmlToText(xmlFieldsF, text)
                        text.append(endAreaF)
                    else:
                        fieldF = self.getQuoteField(f)
                        text.append(fieldF)
                text.append(endAreaI)
            else:
                fieldI = self.getQuoteField(i)
                text.append(fieldI)

    def getActionField(self, xmlField):
        """Выдает свойство action XML поля"""
        xmlActions = xpath.Evaluate('child::action',xmlField)
        if xmlActions and xmlActions[0].firstChild:
            return xmlActions[0].firstChild.nodeValue
        else:
            return False

    def getFieldValues(self, xmlField):
        """Выдает значения XML поля в виде массива"""
        vals = []
        xmlValues = xpath.Evaluate('child::value',xmlField)
        if xmlValues:
            for node in xmlValues:
                if node.firstChild:
                    vals.append(node.firstChild.nodeValue)
        return vals

    def getActionArea(self, xmlArea):
        """Выдает свойство action XML области"""
        xmlActions = xpath.Evaluate('child::caption/action',xmlArea)
        if xmlActions and xmlActions[0].firstChild:
            return xmlActions[0].firstChild.nodeValue
        else:
            return False

    def delActionNodeArea(self, xmlArea):
        """Удаляет свойство action XML области"""
        xmlActions = xpath.Evaluate('child::caption/action',xmlArea)
        if xmlActions and xmlActions[0].firstChild:
            parentNode = xmlActions[0].parentNode
            parentNode.removeChild(xmlActions[0])
            return True
        else:
            return False

    def delActionNodeField(self, xmlField):
        """Удаляет свойство action XML поля"""
        xmlActions = xpath.Evaluate('child::action',xmlField)
        if xmlActions and xmlActions[0].firstChild:
            parentNode = xmlActions[0].parentNode
            parentNode.removeChild(xmlActions[0])
            return True
        else:
            return False

    # Создает распределенные списки
    def postParserListSeplist(self, xmlArea):
        """Создает распределенные списки из элементов области"""
        # Потомки
        childNodes = self.getFieldsArea(xmlArea)
        # содержит списки нод полей с одинаковыми именами в одной области
        fieldsSeplist = {}
        for node in childNodes:
            if node.tagName == "area":
                self.postParserListSeplist(node)
            else:
                fieldName = False
                xmlFieldNameNodes = xpath.Evaluate('child::name',node)
                if xmlFieldNameNodes and xmlFieldNameNodes[0].firstChild:
                    fieldName = xmlFieldNameNodes[0].firstChild.nodeValue
                if fieldName:
                    if  fieldsSeplist.has_key(fieldName):
                        fieldsSeplist[fieldName].append(node)
                    else:
                        fieldsSeplist[fieldName] = []
                        fieldsSeplist[fieldName].append(node)
        for listNodes in fieldsSeplist.values():
            if len(listNodes) > 1:
                for node in listNodes:
                    node.setAttribute("type", "seplist")

    def insertBRtoBody(self, xmlArea):
        """Добавляет необходимые переводы строк
        """
        # Потомки
        childNodes = self.getFieldsArea(xmlArea)
        # нода BR
        fieldXMLBr = self.createField("br",[],"",[],False, False)
        # разделитель поля
        fieldSplit = False
        # Предыдущая нода
        lastNode = False
        # Cледующая нода
        nextNode = False
        lenChildNodes = len(childNodes)
        for i in range(lenChildNodes):
            node = childNodes[i]
            lastTmpNode = node
            # Нода area
            if node.tagName == "area":
                if self.getActionArea(node) == "append" or\
                    self.getActionArea(node) == "join":
                    self.delActionNodeArea(node)
                    if lastNode and lastNode.hasAttribute("type") and\
                        lastNode.getAttribute("type") == "br" or\
                        lastNode and lastNode.hasAttribute("type") and\
                        lastNode.getAttribute("type") == "comment":
                        indNext = i + 1
                        if indNext == lenChildNodes:
                            xmlArea.appendChild(fieldXMLBr.cloneNode(True))
                        else:
                            nextNode = childNodes[indNext]
                            lastTmpNode = xmlArea.insertBefore(\
                                                    fieldXMLBr.cloneNode(True),
                                                    nextNode)
                    else:
                        xmlArea.insertBefore(fieldXMLBr.cloneNode(True),
                                             node)
                self.insertBRtoBody(node)
            # Нода field
            else:
                if self.getActionField(node) == "append" or\
                self.getActionField(node) == "join":
                    self.delActionNodeField(node)
                    if lastNode and lastNode.hasAttribute("type") and\
                        lastNode.getAttribute("type") == "br" or\
                        lastNode and lastNode.hasAttribute("type") and\
                        lastNode.getAttribute("type") == "comment":
                        indNext = i + 1
                        if indNext == lenChildNodes:
                            xmlArea.appendChild(fieldXMLBr.cloneNode(True))
                        else:
                            nextNode = childNodes[indNext]
                            lastTmpNode = xmlArea.insertBefore(\
                                                    fieldXMLBr.cloneNode(True),
                                                    nextNode)
                    else:
                        xmlArea.insertBefore(fieldXMLBr.cloneNode(True),
                                             node)
            lastNode = lastTmpNode



    def postParserList(self):
        """Находит подходящие XML области и делаем из них поля-массивы"""
        xmlAreas = xpath.Evaluate('descendant::area', self.body)
        for xmlArea in xmlAreas:
            flagListXml = True
            fieldValues = []
            xmlFields = xpath.Evaluate('child::field',xmlArea)
            if not xmlFields:
                flagListXml = False
            lenXmlFields = len(xmlFields)
            lenBrArea = 0
            for xmlField in xmlFields:
                xmlNames = xpath.Evaluate('child::name',xmlField)
                xmlVals = xpath.Evaluate('child::value',xmlField)
                if xmlField.hasAttribute("type") and\
                    xmlField.getAttribute("type") == "br":
                    lenBrArea += 1
                    continue
                if not xmlNames and not xmlVals:
                    flagListXml = False
                    break
                if xmlNames and xmlNames[0].firstChild and\
                    xmlNames[0].firstChild.nodeValue:
                    flagListXml = False
                    break
                if not (xmlVals and xmlVals[0].firstChild and\
                xmlVals[0].firstChild.nodeValue):
                    flagListXml = False
                    break
                else:
                   fieldValues.append(xmlVals[0].firstChild.nodeValue)

            if lenXmlFields == lenBrArea:
                flagListXml = False
            if flagListXml:
                nameNode = xpath.Evaluate('child::caption/name',xmlArea)[0]
                fieldName = ""
                if nameNode.firstChild:
                    fieldName = nameNode.firstChild.nodeValue
                listArea = []
                self.xmlToText([xmlArea],listArea)
                fieldQuote = "".join(listArea)
                fieldXMLBr = False
                if fieldQuote and fieldQuote[-1] == "\n":
                    fieldQuote = fieldQuote[:-1]
                    fieldXMLBr = self.createField("br",[],"",[],False, False)
                fieldXML = self.createField("list",
                                        [fieldQuote],
                                        fieldName, fieldValues,
                                        False, False)
                areaAction = self.getActionArea(xmlArea)
                if areaAction:
                    self.setActionField(fieldXML, areaAction)
                parentNode = xmlArea.parentNode
                parentNode.insertBefore(fieldXML,xmlArea)
                if fieldXMLBr:
                    parentNode.insertBefore(fieldXMLBr,xmlArea)
                parentNode.removeChild(xmlArea)


class blocText:
    """Разбиваем текст на блоки"""

    def splitTxtToBloc(self, text ,openTxtBloc,closeTxtBloc,
                       commentTxtBloc, sepField):
        """Делит текст на блоки (без заголовков)

        openTxtBloc  - регулярное выражение для начала блока
        closeTxtBloc - регулярное выражение для конца блока
        commentTxtBloc  - регулярное выражение - комментарий
        возвращает блоки текста
        """
        blocs = []
        level = 0
        # Нахождение нескольких блоков в строке
        # разделители линий, разделителями могут быть ("","\n")
        sepsLines = []
        # линии
        txtLines = []
        # Исходные строки
        txtLinesSrc = text.splitlines()
        for line in txtLinesSrc:
            lineBR = ""
            lineTmpA = line
            closeBl = False
            txtLinesTmp = []
            commentSpl = commentTxtBloc.split(line)
            flagCommentLine = False
            if commentSpl[0].strip():
                closeBl = True
                if len(commentSpl) > 1:
                    commentBl = commentTxtBloc.search(line)
                    textLine =commentSpl[0]
                    commentLine = line[commentBl.start(0):]
                    lineTmpA = textLine
                    flagCommentLine = True

            while (closeBl):
                closeBl = sepField.search(lineTmpA)
                if closeBl:
                    lineTmpB = lineTmpA[closeBl.end(0):]
                    txtLinesTmp.append(lineTmpA[:closeBl.end(0)])
                    lineTmpA = lineTmpB
            if lineTmpA.strip():
                txtLinesTmp.append(lineTmpA)
            # Если есть значение и комментарий в строке
            if flagCommentLine:
                for l in txtLinesTmp:
                    txtLines.append(l)
                    sepsLines.append("")
                if not txtLinesTmp:
                    txtLines.append(textLine)
                    sepsLines.append("")
                txtLines.append(commentLine)
                sepsLines.append("\n")
            # Если есть несколько блоков в строке
            elif len(txtLinesTmp)>1 and txtLinesTmp[1].strip():
                lenTmpLines = len(txtLinesTmp)
                for l in range(lenTmpLines):
                    txtLines.append(txtLinesTmp[l])
                    if l == lenTmpLines-1:
                        sepsLines.append("\n")
                    else:
                        sepsLines.append("")
            # Cтрока не преобразована
            else:
                txtLines.append(line)
                sepsLines.append("\n")

        # разбивание на блоки
        z = 0
        bl = ""
        for i in txtLines:
            if commentTxtBloc.split(i)[0].strip() and openTxtBloc.search(i):
                level += len(openTxtBloc.split(i)) - 1
            if commentTxtBloc.split(i)[0].strip() and closeTxtBloc.search(i):
                level -= len(closeTxtBloc.split(i)) - 1
            bl += i + sepsLines[z]
            if level == 0:
                if bl:
                    blocs.append(bl)
                bl = ""
            z += 1
        # cоздание блоков с элементами не входящими в блоки
        realBlocs = []
        z = 0
        bl = ""
        for i in blocs:
            txtLines = i.splitlines()
            if len(txtLines) > 0:
                line = txtLines[0]
            else:
                line = i
            if commentTxtBloc.split(i)[0].strip() and openTxtBloc.search(line):
                if bl:
                    realBlocs.append(bl)
                    bl = ""
                realBlocs.append(i)
            else:
                bl += i
            z += 1
        if bl:
            realBlocs.append(bl)
            bl = ""
        if level == 0:
            if text and text[-1] != "\n":
                tmpBlocs = realBlocs.pop()
                tmpBlocs = tmpBlocs[:-1]
                realBlocs.append(tmpBlocs)
            return realBlocs
        else:
            return []

    def findArea(self, text, reTextHeader, reTextArea, numGroupArea=0):
        """ Делит текст на области (с заголовками)

        reTextHeader  - регулярное выражение для заголовка области
        reTextArea - регулярное выражение для всей области
        numGroupArea - номер групы результата поиска по регулярному выражению
        по всей области
        возвращает два списка: первый - заголовки, второй - тела областей без
        заголоков
        """
        # Заголовки областей
        headersArea = []
        # Тексты областей без заголовков
        textBodyArea = []
        r = reTextArea.search(text)
        if not r:
            headersArea.append("")
            textBodyArea.append(text)
            return (headersArea, textBodyArea)

        txtWr = text
        while r:
            textArea = r.group(numGroupArea)
            txtSpl = txtWr.split(textArea)
            area =  txtSpl[0]
            txtWr = txtSpl[1]
            if area:
                headersArea.append("")
                textBodyArea.append(area)
            res = reTextHeader.search(textArea)
            header = textArea[:res.end()]
            body = textArea[res.end():]

            headersArea.append(header)
            textBodyArea.append(body)

            if txtWr:
                r = reTextArea.search(txtWr)
            else:
                r = False
        if txtWr:
            headersArea.append("")
            textBodyArea.append(txtWr)
        return (headersArea, textBodyArea)


    def findBloc(self, text, captionTxtBloc, bodyTxtBloc):
        """ Делит текст на блоки (с заголовками)

        captionTxtBloc  - регулярное выражение для заголовка блока
        bodyTxtBloc - регулярное выражение для тела блока
        возвращает два списка: первый - заголовки, второй - тела блоков
        """
        # Заголовки блоков
        headersTxt = []
        # Тексты блоков
        blocsTxt = []
        r = captionTxtBloc.search(text)
        if r:
            headersTxt.append(r.group(0))
            txtSpl = text.split(r.group(0))
            blocTxt =  txtSpl[0]
            txtWr = txtSpl[1]
            rb = bodyTxtBloc.search(blocTxt)
            if not blocTxt:
                blocsTxt.append(blocTxt)
            if rb:
                blocsTxt.append(rb.group(0))
            while (r):
                r = captionTxtBloc.search(txtWr)
                if r:
                    headersTxt.append(r.group(0))
                    txtSpl = txtWr.split(r.group(0))
                    blocTxt =  txtSpl[0]
                    txtWr = txtSpl[1]
                    rb = bodyTxtBloc.search(blocTxt)
                    if rb:
                        blocsTxt.append(rb.group(0))
                else:
                    blocsTxt.append(txtWr)
        if headersTxt and blocsTxt:
            if len(headersTxt)>len(blocsTxt):
                blocsTxt.insert(0,"")
            elif len(headersTxt)<len(blocsTxt):
                headersTxt.insert(0,"")
            if len(headersTxt)!=len(blocsTxt):
                return False
            return (headersTxt, blocsTxt)
        else:
            return False


class _file(_error):
    """Класс для работы с файлами

    """
    def __init__(self):
        # Имя файла старого профиля
        self.nameFileOld = ""
        # Старый профиль
        self.oldProfile = ""
        # Имя файла нового профиля
        self.nameFileNew = ""
        # Новый профиль
        self.newProfile = ""
        # Дескриптор файла нового профиля
        self.FN = False
        # Дескриптор файла старого профиля
        self.FO = False

        # Владелец и режим доступа файла профиля
        self._mode = False
        self._uid = False
        self._gid = False

        self.openNewFile = self.__openNewFile
        self.absFileName = self.__absFileName
        self.closeNewFile = self.__closeNewFile

    def getFileType(self, profile="New"):
        """выдать тип файла (text, bin)
        """
        if self.nameFileNew:
            nameFile = self.nameFileNew
            if profile=="Old" and self.nameFileOld:
                nameFile = self.nameFileOld
        sp = subprocess.Popen("file '%s'"%nameFile, stdin=subprocess.PIPE,
                              stdout=subprocess.PIPE, stderr=subprocess.PIPE,
                              close_fds=True, shell=True)
        fout, fin, ferr = (sp.stdout, sp.stdin, sp.stderr)
        fin.close()
        textLine = fout.readline()
        fout.readlines()
        fout.close()
        retText = ""
        if textLine:
            listTextLine = textLine.split(":")
            if len(listTextLine) == 2:
                textFormats = ["text", "XML"]
                retText = "bin"
                fileTypeString = listTextLine[1]
                for textFormat in textFormats:
                    if textFormat in fileTypeString:
                        retText = "text"
                        break
        ferr.close()
        return retText

    def scanDirs(self, profilesDirs):
        """Сканирует дерево каталогов выдает два списка: директории, файлы"""
        dirs = []
        class dirProf:
            def __init__(self):
                self.baseDir = False
                self.dirs = []
                self.files = []
                self.links = []
                self.sockets = []
        def getFilesDir(dirP, dirname,names):
            for nameFile in names:
                absNameFile = dirname + "/" + nameFile
                if os.path.islink(absNameFile):
                    dest = absNameFile
                    src = os.readlink(absNameFile)
                    dirP.links.append((src,dest))
                elif os.path.isfile(absNameFile):
                    dirP.files.append(absNameFile)
                elif os.path.isdir(absNameFile):
                    dirP.dirs.append(absNameFile)
                elif stat.S_ISSOCK(os.stat(absNameFile)[stat.ST_MODE]):
                    dirP.sockets.append(absNameFile)
        for profileDir in profilesDirs:
            if profileDir:
                dirP = dirProf()
                dirP.baseDir = profileDir
                dirs.append(dirP)
                os.path.walk(profileDir,getFilesDir, dirP)
        return dirs

    def __absFileName(self, nameFile):
        """Вычисление пути к файлу"""
        pathList = nameFile.split("/")
        chortNameFile = pathList.pop()
        absPath = os.path.abspath("/".join(pathList))
        File = absPath + "/" + chortNameFile
        return File

    def saveOldFile(self):
        """Записать конфигурацию"""
        if self.FO:
            self.FO.truncate(0)
            self.FO.seek(0)
            if not self.oldProfile:
                self.oldProfile = self.newProfile
            try:
                self.FO.write(self.oldProfile)
            except:
                self.setError (_("not open file:" ) + self.nameFileOld)
                return False
            self.FO.flush()
            return True

    def getModeFile(self, nameFile):
        """Выдает информацию о файле

        права файла, владелец, группа файла (777,test, group)
        """
        fd = os.open(nameFile, os.O_RDONLY)
        fst = os.fstat(fd)
        uid = fst.st_uid
        gid = fst.st_gid
        mode = stat.S_IMODE(fst.st_mode)
        os.close(fd)
        return (mode,uid,gid)

    def __openNewFile(self, nameFileNew):
        """Открыть файл профиля"""
        FN = False
        try:
            FN = open (nameFileNew, "r")
            self._mode,self._uid,self._gid = self.getModeFile(nameFileNew)
        except:
            self.setError (_("not open file:" ) + nameFileNew)
            return False
        return FN

    def __closeNewFile(self):
        if self.FN:
            self.FN.close()
            self.FN = False

    def __closeOldFile(self):
        if self.FO:
            self.FO.close()
            self.FO = False

    def __openOldFile(self, nameFileOld, mode, uid, gid):
        """Октрыть конфигурационный файл"""
        FO = False
        try:
            if os.path.islink(nameFileOld):
                # если ссылка то удаляем её
                os.unlink(nameFileOld)
            FO = open (nameFileOld, "r+")
        except:
            try:
                fd = os.open(nameFileOld, os.O_CREAT)
                os.close(fd)
                os.chmod(nameFileOld, mode)
                os.chown(nameFileOld,uid,gid)
                FO = open(nameFileOld, "r+")
            except:
                self.setError (_("not open file:" ) + nameFileOld)
                return False
        return FO


    def openFiles(self, nameFileNew, nameFileOld):
        """Открывает два профайла новый и старый"""
        self.oldProfile = ""
        self.newProfile = ""
        self.closeFiles()
        self.FN = False
        self.FO = False
        self.nameFileOld = self.__absFileName(nameFileOld)
        self.nameFileNew = self.__absFileName(nameFileNew)
        self.FN = self.__openNewFile(self.nameFileNew)
        self.FO = self.__openOldFile(self.nameFileOld,
                                     self._mode, self._uid, self._gid)
        if self.FN and self.FO:
            self.newProfile = self.FN.read()
            self.oldProfile = self.FO.read()

    def __del__(self):
        self.closeFiles()

    def closeFiles(self):
        """Закрытие файлов"""
        self.__closeNewFile()
        self.__closeOldFile()


class utfBin:
    """Класс для преобразования в utf-8

    преобразование бинарного или смеси бинарного и utf-8 кода в utf-8 и
    обратное преобразование 
    методы класса encode и decode
    """
    def _retUTF(self, char):
        byte = ord(char)
        if byte<=127:
            return ('_ch_',1)
        elif byte<=191:
            return ('_nb_',1)
        elif byte<=223:
            return ('_fb_',2)
        elif byte<=239:
            return ('_fb_',3)
        elif byte<=247:
            return ('_fb_',4)
        else:
            return ('_er_',1)

    def _sumbUtf(self, symbols, lenTail):
        if not symbols:
            return (False,0)
        lenSymb = len(symbols)
        if lenSymb >= 4:
            l = 4
        elif lenSymb >= 3:
            l = 3
        elif lenSymb >= 2:
            l = 2
        else:
            if symbols[0] == '_ch_':
                return (True,1)
            else:
                return (False,1)
        result = False
        for i in range(l):
            if i == 0 and symbols[i] != '_fb_':
                break
            elif i > 0 and symbols[i] != '_nb_':
                break 
        if lenTail>1 and lenTail != i:
            return (False,1)
        if i > 0:
            result = True
        return (result, i)


    def _intToChar(self, x):
        he = hex(x)[2:]
        exec("ret = '\\x%s'" %he)
        return ret

    def _hexToChar(self, he):
        exec("ret = '\\x%s'" %he)
        return ret

    def encode(self, text):
        """Кодирует смешанный формат в UTF-8"""
        ind = 0
        l = 0
        utf = []
        lenUtf = []
        indErr = []
        i = 0
        for ch in text:
            r, l = self._retUTF(ch)
            utf.append(r)
            lenUtf.append(l)
            i+=1
        while 1:
            if utf[ind] == '_fb_':
                res, l = self._sumbUtf(utf[ind:],lenUtf[ind])
                if res == False:
                    indErr.append(ind)
                if l>0:
                    ind +=l
                    if ind >= len(utf):
                        break
            else:
                if utf[ind] != '_ch_':
                    indErr.append(ind)
                ind +=1
                if ind >= len(utf):
                    break
        if indErr:
            lenIndErr = len(indErr)
            block = []
            blocks = []
            if lenIndErr > 1:
                i = 1
                while 1:
                    if i == 1:
                        block.append(indErr[i-1])
                    if indErr[i] - indErr[i-1] == 1:
                        block.append(indErr[i])
                    else:
                        if block:
                            blocks.append(block)
                        block = []
                        block.append(indErr[i])
                    i +=1
                    if i >= lenIndErr:
                        break
            else:
                block.append(indErr[0])
            if block:
                blocks.append(block)
            listErr = []
            for block in blocks:
                string = ""
                for elem in block:
                    string += hex(ord(text[elem]))[-2:]
                listErr.append((block[0],"__hex__?%s?__hex__" %string,elem))
            textOut = text
            deltaInd = 0
            for erEl in listErr:
                startInd = erEl[0] + deltaInd
                endInd = erEl[2] + 1 + deltaInd
                textOut = textOut[:startInd] + erEl[1] + textOut[endInd:]
                deltaInd += len(erEl[1])-(erEl[2]-erEl[0]+1)
                #if i == 1:
                    #break
                #i += 1
            return textOut

    def decode(self, text):
        """Декодирует UTF-8 в смешанный формат"""
        varStart = "__hex__\?"
        varEnd = "\?__hex__"
        # -1 Это экранирование '?' которое тоже считается
        deltVarStart = len(varStart)-1
        deltVarEnd = len(varEnd)-1
        reVar = re.compile(("%s[a-f0-9]+%s")%(varStart,varEnd),re.M)
        resS = reVar.search(text)
        textProfileTmp = text
        while resS:
            mark = textProfileTmp[resS.start():resS.end()]
            hexString = mark[deltVarStart:-deltVarEnd]
            i = 0
            stringInsert = ""
            hexCode = ""
            for ch in hexString:
                if i>=1:
                    hexCode += ch
                    stringInsert += self._hexToChar(hexCode)
                    hexCode = ""
                    i = 0
                else:
                    hexCode += ch
                    i += 1
            textProfileTmp = textProfileTmp.replace(mark, stringInsert)
            resS = reVar.search(textProfileTmp)
        return textProfileTmp

    def getUserDataInLDAP(self, userName):
        """Получаем домашнюю директорию пользователя из LDAP"""
        if not self.conLdap:
            import cl_utils2
            data = self.getLDAPDataInConfig()
            if not data:
                return ""
            serverName, usersDN, bindDN, bindPW = data
            # Подключаемся к LDAP
            ldapObj = cl_utils2.ldapFun(bindDN, bindPW, serverName)
            if self.getError():
                return ""
            self.conLdap = ldapObj.conLdap
        searchScope = ldap.SCOPE_ONELEVEL
        searchFilter = "uid=%s" %(userName)
        retrieveAttributes = ["uidNumber",
                              "gidNumber"
                              "homeDirectory"]
        resSearch = ldapObj.ldapSearch(usersDN, searchScope,
                                            searchFilter, retrieveAttributes)
        if resSearch:
            if resSearch[0][0][1].has_key('uidNumber') and\
                resSearch[0][0][1].has_key('gidNumber') and\
                resSearch[0][0][1].has_key('homeDirectory'):
                uid = searchUser[0][0][1]['uidNumber'][0]
                gid = searchUser[0][0][1]['gidNumber'][0]
                homeDir = resSearch[0][0][1]['homeDirectory'][0]
                return uid, gid, homeDir
        return ""


class processingTemplates:
    """Класс для обработки шаблонов"""

    def processingFile(self, path, prefix):
        """Обработка в случае профиля файла"""
        return True

    def processingDirectory(self, path, prefix):
        """Обработка в случае директории если возвращаем None то пропуск дир."""
        return True

    def scanningTemplates(self, scanDir, skipFile=[], skipDir=[],
                          prefix=None, flagDir=False):
        """Время последней модификации внутри директории scanDir"""
        ret = True
        if not prefix:
            prefix = os.path.join(scanDir,"")[:-1]
        if not flagDir:
            # проверка корневой директории
            retDir = self.processingDirectory(scanDir, scanDir)
            if retDir is None:
                return None
            elif retDir is False:
                return False
        if flagDir or stat.S_ISDIR(os.lstat(scanDir)[stat.ST_MODE]):
            for fileOrDir in sorted(os.listdir(scanDir)):
                absPath = os.path.join(scanDir,fileOrDir)
                relPath = absPath.split(prefix)[1]
                stInfo = os.lstat(absPath)
                statInfo = stInfo[stat.ST_MODE]
                if stat.S_ISREG(statInfo):
                    # Обработка файла
                    if relPath in skipFile:
                        continue
                    if not self.processingFile(absPath, prefix):
                        ret = False
                        break
                elif stat.S_ISDIR(statInfo):
                    # Обработка директории
                    if relPath in skipDir:
                        continue
                    retDir = self.processingDirectory(absPath, prefix)
                    if retDir is None:
                        continue
                    elif retDir is False:
                        ret = False
                        break
                    ret = self.scanningTemplates(absPath, skipFile,
                                                 skipDir, prefix, True)
                    if ret is False:
                        break
        return ret


class profile(_file, _terms, xmlShare, processingTemplates):
    """Класс для работы с профилями

    На вход 2 параметра: объект хранения переменных, имя сервиса - не
    обязательный параметр

    """
    # Словарь установленных программ {"имя программы":[версии]}
    installProg = {}

    # Cписок просканированных категорий установленных программ
    installCategory = []

    # Флаг сканирования всех установленных программ
    flagAllPkgScan = False

    # Название файла профиля директории
    profDirNameFile = ".calculate_directory"

    # стек глобальных переменных
    stackGlobalVars = []

    # директория установленных программ
    basePkgDir = "/var/db/pkg"

    # регулярное выражение для поиска версии
    reFindVer = re.compile("(?<=\-)\d+\.?\d*\.?\d*")

    def __init__(self, objVar, servDir=False, dirsFilter=[], filesFilter=[]):
        # Необрабатываемые директории
        self.dirsFilter = dirsFilter
        # Необрабатываемые файлы
        self.filesFilter = filesFilter
        _file.__init__(self)
        # Словарь для создания объектов новых классов по образцу
        self.newObjProt = {'proftpd':(apache,),}
        # Заголовок title
        self.__titleHead = "--------------------------------------\
----------------------------------------"
        self._titleBody = ""
        self._titleList = (_("Modified"), _("File of a profile"))

        # Метки
        varStart = "#-"
        varEnd = "-#"
        self._reVar = re.compile(("%s[a-zA-Z0-9_-]+%s")%(varStart,varEnd),re.M)
        self._reFunc = re.compile(("%s[a-zA-Z0-9_\-\+\(\)\, \*\/\.\'\"~]+%s")\
            %(varStart,varEnd),re.M)
        self._deltVarStart = len(varStart)
        self._deltVarEnd = len(varEnd)
        # Условия
        self._reTermBloc = re.compile("#\?(?P<rTerm>[a-zA-Z0-9\-_]+)\
(?P<func>\([a-zA-Z0-9_\-\+\,\*\/\.\'\"~]+\))?\
(?P<lTerm>[\>\<\=\!\&\|]+\
[a-zA-Z0-9\>\<\=\!\|\&\-\+\*\/_\.\,\(\)\'\"~]*)#\
\n*(?P<body>.+?)\n*#(?P=rTerm)#(?P<end>[ ,\t]*\n?)",re.M|re.S)
        # Объект с переменными
        self.objVar = objVar
        # Базовая директория переноса профилей "/mnt/calculate" или "/" и.т.д
        baseDir = self.objVar.Get("cl_root_path")
        #self._baseDir = os.path.split(baseDir)[0]
        self._baseDir = baseDir
        if self._baseDir == "/":
            self._baseDir = ""
        # Последняя часть директории профиля (имя сервиса: samba, mail)
        self._servDir = servDir 
        if self._servDir:
            if self._servDir[0] != "/":
                self._servDir = "/" + self._servDir
            if self._servDir[-1] != "/":
                self._servDir += "/"
            self._servDir = os.path.split(self._servDir)[0]
        # Созданные директории
        self.createdDirs = []
        # Примененные файлы
        self.filesApply = []
        # номер обрабатываемого файла
        self.numberProcessProf = 0
        # имя текущей программы
        _nameProgram = self.objVar.Get("cl_name").capitalize()
        # версия текущей программы
        _versionProgram = self.objVar.Get("cl_ver")
        # имя и версия текущей программы
        self.programVersion = "%s %s"%(_nameProgram, _versionProgram)
        # Словарь измененных директорий
        self.changeDirs = {}
        # Словарь директорий с количесвом файлов шаблонов
        self.dictTemplates = {}
        # Общее количество шаблонов
        self.allTemplates = 0
        # Аттрибуты для функции шаблона ini()
        # Первоначальный словарь переменных для ini()
        self.prevDictIni = {}
        # Текущий словарь переменных для ini()
        self.currDictIni = {}
        # Время модификации конфигурационного файла для ini() 
        self.timeIni = -1
        self.uid, self.gid, self.homeDir = self.getDataUser()
        # Путь к конфигурационному файлу для ini() 
        self.pathConfigIni = os.path.join(self.homeDir, ".calculate")
        self.fileConfigIni = os.path.join(self.pathConfigIni,"ini.env")
        # Словарь времен модификации env файлов
        self.timeConfigsIni = {}

    def getDataUser(self):
        """Получить информацию о пользователе"""
        userName = self.objVar.Get("ur_login")
        if not userName:
            userName = "root"
        import pwd
        try:
            pwdObj = pwd.getpwnam(userName)
            uid = pwdObj.pw_uid
            gid = pwdObj.pw_gid
            homeDir = pwdObj.pw_dir
        except:
            print _("error in profile %s")%nameProfile
            print _("error profile term %s")%str(funTxt)
            print _("Can not found user %s")%str(userName)
            cl_base.exit(1)
        return uid, gid, homeDir


    # Преобразование восьмеричного в целое (ввод строка, вывод число)
    def __octToInt(self, strOct):
        if strOct:
            try:
                exec("res =" + "0" + strOct)
            except:
                self.setError (_("Not valid oct value: ") + str(strOct))
                return False
            return res
        else:
            self.setError (_("Empty oct value"))
            return False

    def removeDir(self, rmDir):
        """Рекурсивное удаление директории

        входной параметр директория
        Обязательно должен быть определен метод self.printERROR
        """
        if not os.path.exists(rmDir):
            self.printERROR(_("Not found remove dir %s") %rmDir)
            return False
        fileObj = _file()
        # Сканируем директорию
        scanObjs = fileObj.scanDirs([rmDir])
        for socketRm in scanObjs[0].sockets:
            # Удаляем сокеты
            if os.path.exists(socketRm):
                os.remove(socketRm)
        for linkRm in scanObjs[0].links:
            # Удаляем ссылки
            os.unlink(linkRm[1])
        for fileRm in scanObjs[0].files:
            # Удаляем файлы
            os.remove(fileRm)
        scanObjs[0].dirs.sort(lambda x, y: cmp(len(y), len(x)))
        for dirRm in scanObjs[0].dirs:
            # Удаляем директории
            os.rmdir(dirRm)
        if rmDir:
            os.rmdir(rmDir)
        return True


    def createDir(self, baseProfDir, profDir, baseDirMv, createDir):
        """Создает директорию

        baseDirMv + результат вычитания из profDir baseProfDir
        createDir - создаваемая директория
        """
        if baseDirMv and not os.access(baseDirMv, os.F_OK):
            os.makedirs(baseDirMv)
        # Созданные директории
        createDirs = []
        baseDir = baseProfDir
        if baseProfDir[-1] == "/":
            baseDir = baseProfDir[:-1]
        # Директория в системе относительно baseDirMv без условий
        if baseDirMv:
            dirMvNoTerm = createDir.partition(baseDirMv)[2]
        else:
            dirMvNoTerm = createDir
        # директория в системе
        dirMv = profDir.partition(baseDir)[2]
        if len(dirMv)>1 and dirMv[-1] == "/":
            dirMv = dirMv[:-1]
        ## директория в системе без условий
        #dirMvNoTerm = "/".join(map(lambda x:x.split("?")[0],\
                                   #dirMv.split("/")))
        listDirMv = dirMv.split("/")
        listDirMvNoTerm = dirMvNoTerm.split("/")
        if len(listDirMv) != len(listDirMvNoTerm):
            self.setError (_("Error in profile") + " :" + profDir)
            return False
        genIn = listDirMv.__iter__()
        genOut = listDirMvNoTerm.__iter__()
        inAndOutDirs = map(lambda x: [x,genOut.next()], genIn)
        createDirs = []
        createDir = []
        while (len(inAndOutDirs)>1):
            tmpDirIn = baseDir+"/".join(map(lambda x:x[0], inAndOutDirs))
            tmpDirOut = baseDirMv + "/".join(map(lambda x:x[1],\
                                                 inAndOutDirs))
            if os.access(tmpDirOut, os.F_OK):
                break
            else:
                createDir.append((tmpDirIn, tmpDirOut))
            inAndOutDirs.pop()
        createDir.reverse()
        for crDirIn,crDirOut in createDir:
            try:
                mode,uid,gid = self.getModeFile(crDirIn)
            except OSError:
                self.setError (_("not access dir:" ) + crDirIn)
                return False
            createDirs.append(crDirOut)
            os.mkdir(crDirOut, mode)
            os.chown(crDirOut, uid, gid)
        return createDirs


    def applyVarsProfile(self, textProfile, nameProfile):
        """ Заменяет переменные на их значения
        """
        resS = self._reVar.search(textProfile)
        textProfileTmp = textProfile
        while resS:
            mark = textProfileTmp[resS.start():resS.end()]
            varName = mark[self._deltVarStart:-self._deltVarEnd]
            varValue = ""
            try:
                varValue = str(self.objVar.Get(varName))
            except self.objVar.DataVarsError, e:
                print _("error in profile %s")%nameProfile
                print e
                cl_base.exit(1)
            textProfileTmp = textProfileTmp.replace(mark, varValue)
            resS = self._reVar.search(textProfileTmp)
        return textProfileTmp


    def applyFuncProfile(self, textProfile, nameProfile, nameSystemFile):
        """ Применяет функции к тексту профиля
        """
        def equalTerm(term, sNum, sMD, localVars):
            """Локальная функция для вычисления выражения"""
            terms = sNum.findall(term)
            if terms:
                strNumers = []
                for n in terms:
                    strNum = n.strip()
                    if "*" in strNum or "/" in strNum:
                        strNum = multAndDiv(strNum,sNum,sMD,localVars)
                    try:
                        num = int(strNum)
                    except:
                        minus = False
                        if strNum[:1] == "-":
                            minus = True
                            strNum = strNum[1:]
                        if localVars.has_key(strNum):
                            try:
                                num = int(localVars[strNum])
                            except:
                                print _("error in profile %s")%nameProfile
                                print _("error local var %s not int")\
                                        %str(strNum)
                                cl_base.exit(1)
                        elif self.objVar.exists(strNum):
                            try:
                                num = int(self.objVar.Get(strNum))
                            except:
                                print _("error in profile %s")%nameProfile
                                print _("error var %s not int")%str(strNum)
                                cl_base.exit(1)
                        else:
                            print _("error in profile %s")%nameProfile
                            print _("error local var %s not defined")\
                                %str(strNum)
                            cl_base.exit(1)
                        if minus:
                            num =-num
                    strNumers.append(num)
                return sum(strNumers)
            print _("error in profile %s")%nameProfile
            print _("error profile term %s, incorrect data")%str(term)
            cl_base.exit(1)

        def multAndDiv(term,sNum,sMD,localVars):
            """локальная функция для умножения и деления"""
            termTmp = term
            varsLocal = sMD.findall(term)
            for var in varsLocal:
                flagVarTxt = True
                try:
                    int(var)
                except:
                    flagVarTxt = False
                if flagVarTxt:
                    continue
                varReplace = str(equalTerm(var,sNum,sMD,localVars))
                termTmp = termTmp.replace(var,varReplace)
            ret = eval(termTmp)
            return ret

        def funcSum(funTxt,resS,localVars,textProfileTmp):
            """локальная функция вычисляет первую функцию sum() в профиле"""
            terms = funTxt[4:-1].replace(" ","").split(",")
            # Название локальной переменной
            nameLocVar = terms[0]
            if not localVars.has_key(nameLocVar):
                localVars[nameLocVar] = 0
            if len(terms) == 2:
                if terms[1].strip():
                    localVars[nameLocVar] = equalTerm(terms[1],sNum,sMD,
                                                        localVars)
                    replace = str(localVars[nameLocVar])
                else:
                    replace = ""
                textProfileTmp = textProfileTmp[:resS.start()] + replace +\
                    textProfileTmp[resS.end():]
            elif len(terms) == 3:
                if terms[1].strip():
                    replaceInt = equalTerm(terms[1],sNum,sMD,localVars)
                    replace = str(replaceInt)
                else:
                    replace = ""
                localVars[nameLocVar] =  equalTerm(terms[2],
                                                   sNum,sMD,localVars)
                textProfileTmp = textProfileTmp[:resS.start()] + replace +\
                    textProfileTmp[resS.end():]
            else:
                print _("error in profile %s")%nameProfile
                print _("error profile term %s")%str(funTxt)
                cl_base.exit(1)
            return textProfileTmp


        def funcExists(funTxt,resS,textProfileTmp):
            """если файл существует читает из файла локальную переменную

            если один параметр - выводит значение локальной переменной
            """
            terms = funTxt[7:-1].replace(" ","").split(",")
            if len(terms) !=1:
                print _("error in profile %s")%nameProfile
                print _("error profile term %s")%str(funTxt)
                cl_base.exit(1)
            fileName = terms[0].strip()
            if fileName[0] == "~":
                # Получаем директорию пользователя
                fileName = os.path.join(self.homeDir,
                                        fileName.partition("/")[2],"")[:-1]
            elif fileName[0] != "/":
                path = os.path.split(nameSystemFile)[0]
                fileName=os.path.join(path,fileName)
            replace = ""
            if os.path.exists(fileName):
                replace = "1"
            textProfileTmp = textProfileTmp[:resS.start()] + replace +\
                    textProfileTmp[resS.end():]
            return textProfileTmp

        def funcLoad(funTxt,resS,textProfileTmp):
            """если файл существует читает из файла локальную переменную

            если один параметр - выводит значение локальной переменной
            """
            terms = funTxt[5:-1].replace(" ","").split(",")
            if not terms[0].strip() or\
                (len(terms)==2 and not terms[1].strip()) or\
                len(terms)>2:
                print _("error in profile %s")%nameProfile
                print _("error profile term %s")%str(funTxt)
                cl_base.exit(1)
            if len(terms) == 2:
                if not terms[0] in ["ver","num","char","key"]:
                    print _("error in profile %s")%nameProfile
                    print _("error profile term %s")%str(funTxt)
                    print _("first argument function is not 'ver' or 'num' or\
 'char'")
                    cl_base.exit(1)
            if len(terms) == 1:
                fileName = terms[0].strip()
                # Если домашняя директория
                if fileName[0] == "~":
                    # Получаем директорию пользователя
                    fileName = os.path.join(self.homeDir,
                                            fileName.partition("/")[2],"")[:-1]
                elif fileName[0] != "/":
                    path = os.path.split(nameSystemFile)[0]
                    fileName=os.path.join(path,fileName)
            else:
                fileName = terms[1].strip()
                # Если домашняя директория
                if fileName[0] == "~":
                    # Получаем директорию пользователя
                    fileName = os.path.join(self.homeDir,
                                            fileName.partition("/")[2],"")[:-1]
                elif fileName[1] != "/":
                    path = os.path.split(nameSystemFile)[0]
                    fileName=os.path.join(path,fileName)
            replace = ""
            if os.path.exists(fileName):
                FD = open(fileName)
                replace = FD.read().strip()
                FD.close
            if not replace and len(terms) == 2 and terms[0] in ["ver","num"]:
                replace = "0"
            textProfileTmp = textProfileTmp[:resS.start()] + replace +\
                    textProfileTmp[resS.end():]
            return textProfileTmp

        def getInstallPkgGentoo():
            """Выдает словарь инсталлированных программ и номеров версий"""
            pkgs = []
            def getFilesDir(pkgs, dirname, names):
                for nameFile in names:
                    absNameFile = os.path.join(dirname,nameFile)
                    if os.path.isdir(absNameFile):
                        tail = absNameFile.split(self.basePkgDir)
                        if len(tail)==2:
                            tail = tail[1].split('/')
                            if len(tail)==3 and tail[1]!='virtual': 
                                pkgs.append(tail[2])
                return True
            os.path.walk(self.basePkgDir,getFilesDir, pkgs)
            return sharePkg(pkgs)

        def sharePkg(pkgs):
            """Получение имен и номеров версий программ"""
            pkgs.sort()
            installProg = {}
            for pkg in pkgs:
                findVer = self.reFindVer.search(pkg)
                if findVer:
                    version = findVer.group()
                    name = pkg.split(version)[0][:-1]
                    if name in installProg:
                        installProg[name].append(version)
                    else:
                        installProg[name] = [version]
            return installProg

        def pkg(nameProg, installProg):
            """Выдает установленные версии по имени программы"""
            if nameProg in installProg:
                return installProg[nameProg][-1]
            else:
                return ""

        def funcPkg(funTxt,resS,textProfileTmp):
            """локальная функция выдает номер версии программы"""
            terms = funTxt[4:-1].replace(" ","")
            # Название программы
            nameProg = terms
            # Замена функции в тексте шаблона
            replace = ""
            if "/" in nameProg:
                if nameProg in self.installProg:
                    replace = pkg(nameProg, self.installProg)
                else:
                    category, spl, nProg = terms.partition("/")
                    if not category in self.installCategory:
                        self.installCategory.append(category)
                        pathCategory = os.path.join(self.basePkgDir, category)
                        if os.path.exists(pathCategory):
                            pkgs = os.listdir(pathCategory)
                            pkgs = map(lambda x: os.path.join(category,x),
                                       pkgs)
                            installProg = sharePkg(pkgs)
                            replace = pkg(nameProg, installProg)
                            self.installProg.update(installProg)
            else:
                if not self.flagAllPkgScan:
                    installProg = getInstallPkgGentoo()
                    self.installProg.update(installProg)
                    profile.flagAllPkgScan = True
                replace = pkg(nameProg, self.installProg)
            textProfileTmp = textProfileTmp[:resS.start()] + replace +\
                    textProfileTmp[resS.end():]
            return textProfileTmp

        def funcRnd(funTxt,resS,textProfileTmp):
            """локальная функция выдает строку случайных символов

            первый аргумент:
              'num' - числа,
              'pas' - цифры и буквы
            второй аргумент:
              количество символов
            """
            terms = funTxt[4:-1].replace(" ","").split(",")
            if  not terms[0].strip() or\
                (len(terms)==2 and not terms[1].strip()) or\
                len(terms)!=2:
                print _("error in profile %s")%nameProfile
                print _("error profile term %s")%str(funTxt)
                cl_base.exit(1)
            fArgvNames = ['num','pas']
            if not terms[0] in fArgvNames:
                print _("error in profile %s")%nameProfile
                print _("error profile term %s")%str(funTxt)
                print _("first argument function is not 'num' or 'pas'")
                cl_base.exit(1)
            try:
                lenStr = int(terms[1])
            except:
                print _("error in profile %s")%nameProfile
                print _("error profile term %s")%str(funTxt)
                print _("two argument function is not number")
                cl_base.exit(1)
            if terms[0] == fArgvNames[0]:
                replace=''.join([random.choice(string.digits)\
                                for i in xrange(lenStr)])
            elif terms[0] == fArgvNames[1]:
                replace=''.join([random.choice(string.ascii_letters + \
                                 string.digits) for i in xrange(lenStr)])
            else:
                print _("error in profile %s")%nameProfile
                print _("error profile term %s")%str(funTxt)
                cl_base.exit(1)
            textProfileTmp = textProfileTmp[:resS.start()] + replace +\
                    textProfileTmp[resS.end():]
            return textProfileTmp

        def funcCase(funTxt,resS,textProfileTmp):
            """локальная функция выдает переменную в определенном регистре

            первый аргумент:
              'upper' - верхний регистр,
              'lower' - нижний регистр,
              'capitalize' - первая буква в верхнем регистре
            второй аргумент:
              название переменной
            """
            terms = funTxt[5:-1].replace(" ","").split(",")
            if  not terms[0].strip() or\
                (len(terms)==2 and not terms[1].strip()) or len(terms)!=2:
                print _("error in profile %s")%nameProfile
                print _("error profile term %s")%str(funTxt)
                cl_base.exit(1)
            fArgvNames = ['upper','lower','capitalize']
            if not terms[0] in fArgvNames:
                print _("error in profile %s")%nameProfile
                print _("error profile term %s")%str(funTxt)
                print _("first argument function is not 'upper' or 'lower' or\
 'capitalize'")
                cl_base.exit(1)
            try:
                strValue = str(self.objVar.Get(terms[1]))
            except:
                print _("error in profile %s")%nameProfile
                print _("error var %s not found")%str(terms[1])
                cl_base.exit(1)
            replace = ""
            strValue = self._toUNICODE(strValue)
            if terms[0] == 'upper':
                replace = strValue.upper()
            elif terms[0] == 'lower':
                replace = strValue.lower()
            elif terms[0] == 'capitalize':
                replace = strValue.capitalize()
            if replace:
                replace = replace.encode("UTF-8")
            textProfileTmp = textProfileTmp[:resS.start()] + replace +\
                    textProfileTmp[resS.end():]
            return textProfileTmp

        def funcPush(funTxt,resS,localVars,textProfileTmp):
            """локальная функция записывает значение переменной 

            в стек глобальных переменных
            """
            terms = funTxt[5:-1].replace(" ","").split(",")
            # Название локальной переменной
            nameLocVar = terms[0]
            flagFoundVar = False
            if nameLocVar in localVars.keys():
                    flagFoundVar = True
                    value = localVars[nameLocVar]
            else:
                try:
                    value =  self.objVar.Get(nameLocVar)
                    flagFoundVar = True
                except:
                    pass
            if flagFoundVar:
                # Если переменная существует
                if len(terms) == 1:
                    self.stackGlobalVars.append(str(value))
                else:
                    print _("error in profile %s")%nameProfile
                    print _("error profile term %s")%str(funTxt)
                    print _("error var %s exists")%str(nameLocVar)
                    cl_base.exit(1)
            else:
                # Если переменная не существует
                if len(terms) == 1:
                    print _("error in profile %s")%nameProfile
                    print _("error profile term %s")%str(funTxt)
                    print _("error var %s not exists")%str(nameLocVar)
                    cl_base.exit(1)
                elif len(terms) == 2:
                    value = terms[1].strip()
                    self.stackGlobalVars.append(str(value))
                    localVars[nameLocVar] = value
                else:
                    print _("error in profile %s")%nameProfile
                    print _("error profile term %s")%str(funTxt)
                    cl_base.exit(1)
            replace = ""
            textProfileTmp = textProfileTmp[:resS.start()] + replace +\
                    textProfileTmp[resS.end():]
            return textProfileTmp

        def funcPop(funTxt,resS,localVars,textProfileTmp):
            """локальная функция получает значение

            из стека глобальных переменных и присвает локальной переменной 

            """
            terms = funTxt[4:-1].replace(" ","").split(",")
            # Название локальной переменной
            nameLocVar = terms[0]
            if len(terms) == 1:
                if self.stackGlobalVars:
                    localVars[nameLocVar] = self.stackGlobalVars.pop()
                else:
                    print _("error in profile %s")%nameProfile
                    print _("error profile term %s")%str(funTxt)
                    print _("error, gloval variables stack is empty")
                    cl_base.exit(1)
            else:
                print _("error in profile %s")%nameProfile
                print _("error profile term %s")%str(funTxt)
                cl_base.exit(1)
            replace = ""
            textProfileTmp = textProfileTmp[:resS.start()] + replace +\
                    textProfileTmp[resS.end():]
            return textProfileTmp

        def loadVarsIni(iniFileName):
            """ Читает файл fileName
            создает и заполняет переменные на основе этого файла
            Используеться совместно c funcIni
            """
            localVarsIni = {}
            # Выходим если есть предыдущие ошибки
            if self.getError():
                return False
            # получить объект ini файла
            config = cl_base.iniParser(iniFileName)
            # получаем все секции из конфигурационного файла
            allsect = config.getAllSectionNames()
            if not allsect:
                if self.getError():
                    # Очистка ошибки
                    _error.error = []
                return localVarsIni
            # Заполняем переменные для funcIni
            for sect in allsect:
                sectVars = config.getAreaVars(sect)
                for name in sectVars.keys():
                    nameVar = "%s.%s"%(sect,name) 
                    valueVar = sectVars[name]
                    localVarsIni[nameVar] = valueVar
            return localVarsIni

        def getTimeFile(fileName):
            # Получаем время модификации файла
            if fileName in self.timeConfigsIni:
                return self.timeConfigsIni[fileName]
            return 0

        def funcIni(funTxt, resS, textProfileTmp):
            """локальная функция записывает и считывает значение переменной 

            из ini файла ~./calculate/ini.env
            """
            # Создаем директорию
            if not os.path.exists(self.pathConfigIni):
                os.makedirs(self.pathConfigIni)
                os.chown(self.pathConfigIni, int(self.uid), int(self.gid))
            termsRaw = funTxt[4:-1].split(",")
            flagFirst = True
            terms = []
            for term in termsRaw:
                if flagFirst:
                    terms.append(term.replace(" ",""))
                    flagFirst = False
                else:
                    val = term.strip()
                    # Флаг (не найдены кавычки)
                    flagNotFoundQuote = True
                    for el in ('"',"'"):
                        if val.startswith(el) and val.endswith(el):
                            terms.append(val[1:-1])
                            flagNotFoundQuote = False
                            break
                    if flagNotFoundQuote:
                        terms.append(val)
            # Название локальной переменной
            nameLocVar = terms[0]
            namesVar = nameLocVar.split(".")
            if len(namesVar) == 1:
                nameLocVar = "main.%s"%nameLocVar
            elif len(namesVar)>2:
                print _("error in profile %s")%nameProfile
                print _("error profile term %s")%str(funTxt)
                cl_base.exit(1)
            replace = ""
            # Получаем время модификации конфигурационного файла
            curTime = getTimeFile(self.fileConfigIni)
            if len(terms) == 1:
                if self.timeIni != curTime:
                    # читаем переменные из файла
                    self.prevDictIni = loadVarsIni(self.fileConfigIni)
                    self.currDictIni.update(self.prevDictIni)
                    self.timeIni = getTimeFile(self.fileConfigIni)
                if nameLocVar in self.currDictIni.keys():
                    replace = self.currDictIni[nameLocVar]
            elif len(terms) == 2:
                if self.timeIni != curTime:
                    # читаем переменные из файла
                    self.prevDictIni = loadVarsIni(self.fileConfigIni)
                    self.currDictIni.update(self.prevDictIni)
                    self.timeIni = getTimeFile(self.fileConfigIni)
                # Значение локальной переменной
                valueLocVar = terms[1]
                self.currDictIni[nameLocVar] = valueLocVar
            else:
                print _("error in profile %s")%nameProfile
                print _("error profile term %s")%str(funTxt)
                cl_base.exit(1)
            textProfileTmp = textProfileTmp[:resS.start()] + replace +\
                    textProfileTmp[resS.end():]
            return (textProfileTmp)

        # Локальные переменные
        localVars = {}
        # Регулярное выражние для сложения
        sNum = re.compile("\-[^\-\+]+|[^\-\+]+")
        # Регулярное выражение для умножениея и деления
        sMD = re.compile("[^\-\+\*\/]+")
        resS = self._reFunc.search(textProfile)
        textProfileTmp = textProfile
        flagIniFunc = False
        while resS:
            mark = textProfileTmp[resS.start():resS.end()]
            funTxt = mark[self._deltVarStart:-self._deltVarEnd]
            # Функция sum
            if funTxt.startswith("sum("):
                textProfileTmp = funcSum(funTxt,resS,localVars,textProfileTmp)
                resS = self._reFunc.search(textProfileTmp)
            # Функция load
            elif funTxt.startswith("load("):
                textProfileTmp = funcLoad(funTxt,resS,textProfileTmp)
                resS = self._reFunc.search(textProfileTmp)
            elif funTxt.startswith("pkg("):
                textProfileTmp = funcPkg(funTxt,resS,textProfileTmp)
                resS = self._reFunc.search(textProfileTmp)
            elif funTxt.startswith("rnd("):
                textProfileTmp = funcRnd(funTxt,resS,textProfileTmp)
                resS = self._reFunc.search(textProfileTmp)
            elif funTxt.startswith("case("):
                textProfileTmp = funcCase(funTxt,resS,textProfileTmp)
                resS = self._reFunc.search(textProfileTmp)
            elif funTxt.startswith("pop("):
                textProfileTmp = funcPop(funTxt,resS,localVars,textProfileTmp)
                resS = self._reFunc.search(textProfileTmp)
            elif funTxt.startswith("push("):
                textProfileTmp = funcPush(funTxt,resS,localVars,textProfileTmp)
                resS = self._reFunc.search(textProfileTmp)
            elif funTxt.startswith("ini("):
                flagIniFunc = True
                textProfileTmp = funcIni(funTxt, resS, textProfileTmp)
                resS = self._reFunc.search(textProfileTmp)
            elif funTxt.startswith("exists("):
                textProfileTmp = funcExists(funTxt, resS, textProfileTmp)
                resS = self._reFunc.search(textProfileTmp)
            else:
                resS = False
        if flagIniFunc:
            # Очистка файла в случае его ошибочного чтения
            if not self.prevDictIni and os.path.exists(self.fileConfigIni):
                FD = open(self.fileConfigIni, "r+")
                FD.truncate(0)
                FD.seek(0)
                FD.close()
            # Если конф. файл модифицирован шаблоном
            curTime = getTimeFile(self.fileConfigIni)
            if curTime != self.timeIni:
                # Считаем переменные из конф. файла
                self.prevDictIni = loadVarsIni(self.fileConfigIni)
                self.currDictIni.update(self.prevDictIni)
                self.timeIni = curTime
            # Если словари переменных не совпадают
            if self.prevDictIni != self.currDictIni:
                # Запишем переменные в конфигурационный файл
                # Создание объекта парсера
                config = cl_base.iniParser(self.fileConfigIni)
                # секции будущего конфигурационного файла
                sects = list(set(map(lambda x: x.split(".")[0],\
                                     self.currDictIni.keys())))
                # запись переменных в файл
                for sect in sects:
                    dictVar = {}
                    for varName in self.currDictIni.keys():
                        if varName.startswith("%s."%sect):
                            nameVar = varName.rpartition(".")[2]
                            valueVar = self.currDictIni[varName]
                            if valueVar:
                                dictVar[nameVar] = valueVar
                    if dictVar:
                        # Запись переменных в секцию
                        config.setVar(sect, dictVar)
                # читаем переменные из файла
                self.prevDictIni = loadVarsIni(self.fileConfigIni)
                self.currDictIni.update(self.prevDictIni)
                self.timeConfigsIni[self.fileConfigIni] = float(time.time())
                self.timeIni = getTimeFile(self.fileConfigIni)
            # Меняем владельца в случае необходимости
            if os.path.exists(self.fileConfigIni):
                fd = os.open(self.fileConfigIni, os.O_RDONLY)
                fst = os.fstat(fd)
                uid = fst.st_uid
                gid = fst.st_gid
                os.close(fd)
                if self.uid!=uid or self.gid!=gid:
                    os.chown(self.fileConfigIni, int(self.uid), int(self.gid))
        return textProfileTmp

    def applyTermsProfile(self, textProfile, nameProfile, nameSystemFile=False):
        """ Применяет условия, к условным блокам текста
        """
        textTerm = ""
        resS = self._reTermBloc.search(textProfile)
        textProfileTmp = textProfile
        def function(text):
            """Функция обработки функций в заголовке"""
            return self.applyFuncProfile(text, nameProfile, nameSystemFile)
        if nameSystemFile:
            while resS:
                mark = resS.group(0)
                body = resS.group("body")
                end = resS.group("end")
                parent = resS.group("func")
                if not parent:
                    parent = ""
                term = resS.group("rTerm") + parent +\
                    resS.group("lTerm")
                if self._equalTerm(term, _("content profile not valid: ")+\
                                                    nameProfile, function):
                    textProfileTmp = textProfileTmp.replace(mark, body+end)
                else:
                    textProfileTmp = textProfileTmp.replace(mark, "")
                resS = self._reTermBloc.search(textProfileTmp)
        else:
            while resS:
                mark = resS.group(0)
                body = resS.group("body")
                end = resS.group("end")
                term = resS.group("rTerm") + resS.group("lTerm")
                if self._equalTerm(term, _("content profile not valid: ")+\
                                                    nameProfile):
                    textProfileTmp = textProfileTmp.replace(mark, body+end)
                else:
                    textProfileTmp = textProfileTmp.replace(mark, "")
                resS = self._reTermBloc.search(textProfileTmp)
        return textProfileTmp

    def getNeedProfile(self, fileProfile):
        """Применяем правила к названию файла"""
        dirP,fileP = os.path.split(fileProfile)
        if fileP:
            spFile = fileP.split("?")
            realFileName = spFile[0]
            if len(spFile)>1:
                flagTrue = False
                for term in spFile[1:]:
                    if self._equalTerm(term, _("name profile not valid: ")+\
                                                fileProfile):
                        flagTrue = True
                        break
                if flagTrue:
                    return True
                else:
                    return False
            else:
                return True
        else:
            self.setError (_("name profile not valid: ")+ str(fileProfile))
            return False

    def getTitle(self, comment, commentList):
        """Выдает заголовок профиля ( версия и.т.д)"""
        if comment:
            commentFirst = comment
            commentInsert = comment
            commentLast = comment
            flagList = False
            # В случае открывающего и закрывающего комментария
            if type(comment) == types.TupleType and len(comment) == 2:
                commentFirst = comment[0]
                commentInsert = ""
                commentLast = comment[1]
                flagList = True
            if flagList:
                self._titleBody = commentFirst + "\n"
            else:
                self._titleBody = commentFirst + self.__titleHead + "\n"
            z = 0
            lenCommentList = len(commentList) - 1
            for com in self._titleList:
                if lenCommentList < z:
                    self._titleBody += commentInsert + " " + com + "\n"
                else:
                    self._titleBody += commentInsert + " " + com +\
                                   " " + commentList[z] + "\n"
                z += 1
            if flagList:
                self._titleBody +=  commentLast +"\n"
            else:
                self._titleBody += commentLast + self.__titleHead + "\n"
            return self._titleBody
        else:
            return ""

    def numberAllProfiles(self, number):
        """Количество профилей

        Вызов происходит перед наложением профилей
        в момент вызова в number находится количество обрабатываемых файлов
        Наследуемая функция
        Используется для отображения прогресса при наложениии профилей
        """
        return True

    def  numberProcessProfiles(self, number):
        """Номер текущего обрабатываемого профиля

        Вызов происходит при наложении профиля
        в момент вызова в number находится номер обрабатываемого профиля
        Наследуемая функция
        Используется для отображения прогресса при наложениии профилей
        """
        return True


    def scanDirs(self, profilesDirs, objVar=False):
        """Измененный метод сканирования директорий"""
        dirs = []
        class dirProf:
            def __init__(self):
                self.baseDir = False
                self.dirs = []
                self.files = []
                self.links = []
                self.sockets = []
        flagError = False
        blockDirs = []
        def getFilesDir(dirP, dirname, names):
            for nameFile in names:
                absNameFile = dirname + "/" + nameFile
                findBlock = False
                for blDir in blockDirs:
                    st,mid,end = absNameFile.partition(blDir)
                    if (not st) and mid and end:
                        findBlock = True
                        break
                if not findBlock:
                    if os.path.islink(absNameFile):
                        dest = absNameFile
                        src = os.readlink(absNameFile)
                        dirP.links.append((src,dest))
                    elif os.path.isfile(absNameFile):
                        # Добавляем файлы кроме описаний директорий
                        if self.profDirNameFile != nameFile:
                            dirP.files.append(absNameFile)
                    elif os.path.isdir(absNameFile):
                        # Обработка условий в названии директории
                        if self.getNeedProfile(absNameFile):
                            if self.getError():
                                blockDirs.append(absNameFile)
                                flagError = True
                                break
                            dirP.dirs.append(absNameFile)
                        else:
                            if self.getError():
                                blockDirs.append(absNameFile)
                                flagError = True
                                break
                            blockDirs.append(absNameFile)
                    elif stat.S_ISSOCK(os.stat(absNameFile)[stat.ST_MODE]):
                        dirP.sockets.append(absNameFile)
        for profileDir in profilesDirs:
            if profileDir:
                # Обработка условий в названии директории
                if self.getNeedProfile(profileDir):
                    if self.getError():
                        flagError = True
                        break
                    dirP = dirProf()
                    dirP.baseDir = profileDir
                    dirs.append(dirP)
                    os.path.walk(profileDir, getFilesDir, dirP)
                else:
                    if self.getError():
                        flagError = True
                        break
        if flagError:
            return []
        return dirs


    def applyProfiles(self):
        """Применяет профили к конфигурационным файлам"""

        def createDictTemplates(path, prefix, dictTemplates):
            """Создает словарь {"директория":"кол-во шаблонов" ...}

            и считает общее количество шаблонов
            """
            # Количество шаблонов
            self.allTemplates += 1
            dirTemplate = os.path.split(path)[0]
            while(True):
                if dirTemplate in dictTemplates.keys():
                    dictTemplates[dirTemplate] += 1
                else:
                    dictTemplates[dirTemplate] = 1
                if dirTemplate == prefix:
                    break
                dirTemplate = os.path.split(dirTemplate)[0]
            return dictTemplates

        if not self.objVar.defined("cl_profile_path"):
            self.setError (_("not defined Var: ") + "cl_profile_path")
            return False
        dirsProfiles = self.objVar.Get("cl_profile_path")
        dirsProfiles.sort()
        # Словарь измененных директорий
        self.changeDirs = {}
        # Созданные директории
        self.createdDirs = []
        # Примененные файлы
        self.filesApply = []
        # Номер применяемого шаблона
        self.numberProcessProf = 0
        # Словарь директорий с количеством файлов шаблонов
        self.dictTemplates = {}
        # Количество шаблонов
        self.allTemplates = 0
        # Время доступа к конфигурационному файлу функции шаблона ini()
        self.timeIni = -1
        # Первоначальный словарь переменных для ini()
        self.prevDictIni = {}
        # Текущий словарь переменных для ini()
        self.currDictIni = {}
        # Словарь времен модификации env файлов
        self.timeConfigsIni = {}
        if self._servDir:
            tmpDirsProfiles = []
            for dirP in dirsProfiles:
                dirProf = dirP + self._servDir
                if os.access(dirProf, os.F_OK):
                    # Если директория существует
                    tmpDirsProfiles.append(dirProf)
            dirsProfiles = tmpDirsProfiles
        scanObj = processingTemplates()
        scanObj.processingFile = lambda x,y: createDictTemplates(x, y,\
                                                             self.dictTemplates)
        # Считаем количество шаблонов
        for dirTemplate in dirsProfiles:
            scanObj.scanningTemplates(dirTemplate,
                                      skipFile=self.filesFilter,
                                      skipDir=self.dirsFilter)
        self.numberAllProfiles(self.allTemplates)
        for dirTemplate in dirsProfiles:
            if self.scanningTemplates(dirTemplate,
                                          skipFile=self.filesFilter,
                                          skipDir=self.dirsFilter) is False:
                return False
        return (self.createdDirs, self.filesApply)


    def processingFile(self, path, prefix):
        """Обработка в случае профиля файла"""
        self.numberProcessProf += 1
        self.numberProcessProfiles(self.numberProcessProf)
        # Пропуск шаблонов директорий
        if self.profDirNameFile == os.path.split(path)[1]:
            return True
        if self.getNeedProfile(path):
            if self.getError():
                return False
            fileProfileChange = path
            findChangeDir = False
            listD = self.changeDirs.items()
            listD.reverse()
            for dirChangeIn, dirChangeOut in listD:
                st,mid,end = path.partition(dirChangeIn)
                if (not st) and mid and end:
                    findChangeDir = True
                    break
            if findChangeDir:
                oldFile = dirChangeOut + end
            else:
                oldFile = path.partition(prefix)[2]
            # файл в системе без условий
            oldFile = "/".join(map(lambda x:x.split("?")[0],\
                            oldFile.split("/")))
            if not findChangeDir:
                oldFile = self._baseDir + oldFile
            # Фильтрация профилей по названию файла
            if oldFile in self.filesFilter:
                return True
            listProfTitle = prefix.split("/")[-2:]
            profTitle = '"' + "/".join(listProfTitle) + '"'
            # Записываем в переменную обрабатываемый файл
            self.objVar.Set("cl_pass_file",oldFile)
            # Пишем время модификации *.env файлов
            if oldFile.endswith(".env"):
                self.timeConfigsIni[oldFile] = float(time.time())
            filesApl = self.join(path, oldFile,
                        (self.programVersion,profTitle))
            if filesApl:
                self.filesApply += filesApl
        else:
            if self.getError():
                #print self.getError()
                return False
        return True

    def processingDirectory(self, path, prefix):
        """Обработка в случае директории если возвращаем None то пропуск дир."""
        # Файл шаблона директории
        dirInfoFile = os.path.join(path, self.profDirNameFile)
        # Проверяем заголовок
        ret = self.__isApplyHeadDir(dirInfoFile)
        if not ret:
            if self.getError():
                self.setError(_("Incorrect profile: " ) + dirInfoFile)
                return False
            # Добавление количества файлов в пропущенной директории
            if path in self.dictTemplates.keys():
                self.numberProcessProf += self.dictTemplates[path]
            return None
        newDir = self._baseDir + path.partition(prefix)[2]
        newDir = "/".join(map(lambda x:x.split("?")[0],\
                            newDir.split("/")))
        # Применяем шаблон
        pathDir, objHeadDir = self.__getApplyHeadDir(newDir,
                                                     dirInfoFile,
                                                     self.changeDirs)
        # Фильтрация профилей по названию директории
        if pathDir in self.dirsFilter:
            # Добавление количества файлов в пропущенной директории
            if path in self.dictTemplates.keys():
                self.numberProcessProf += self.dictTemplates[path]
            return None
        if objHeadDir:
            if isinstance(objHeadDir, dirHeader):
                if not objHeadDir.headerCorrect:
                    self.setError(_("Incorrect profile: " ) +\
                                    dirInfoFile)
                    self.setError(objHeadDir.errorMessage)
                    return False
                if not objHeadDir.headerTerm:
                    if objHeadDir.getError():
                        self.setError(_("Incorrect profile: " ) +\
                                        dirInfoFile)
                        return False
                if objHeadDir.params.has_key("name"):
                        self.changeDirs[path] = pathDir
            crDirs = self.createDir(prefix, path,
                                self._baseDir, pathDir)
            if crDirs == False:
                return False
            self.createdDirs += crDirs
        else:
            if self.getError():
                self.setError(_("Incorrect profile: " ) +\
                                dirInfoFile)
                return False
            # Добавление количества файлов в пропущенной директории
            if path in self.dictTemplates.keys():
                self.numberProcessProf += self.dictTemplates[path]
            return None
        return True

    def __getGenHeadDir(self, newDir, profileDirFile, changeDirs):
        """Определяет название создаваемой директории"""

        def function(text):
            """Функция обработки функций в заголовке"""
            return self.applyFuncProfile(text, newDir, profileDirFile)

        newDirMv = newDir
        findChangeDir = False
        #Меняем путь к директории
        listD = changeDirs.items()
        listD.reverse()
        for dirChangeIn, dirChangeOut in listD:
            st,mid,end = profileDirFile.partition(dirChangeIn)
            if (not st) and mid:
                findChangeDir = True
                break
        if findChangeDir:
            pathRel = dirChangeOut
            lenPathRel = len(pathRel.split("/"))
            lenNewDir = len(newDir.split("/"))
            lenEndDir =  lenNewDir - lenPathRel
            tmpDir = newDir
            namesDirs = []
            for i in range(lenEndDir):
                namesDirs.append(os.path.split(tmpDir)[1])
                tmpDir = os.path.split(tmpDir)[0]
            namesDirs.reverse()
            nameDir = "/".join(namesDirs)
            newDirMv = os.path.join(pathRel, nameDir)
        applyDir = newDirMv
        if not os.path.exists(profileDirFile):
            return (applyDir, True)
        try:
            FD = open(profileDirFile)
            textProfile = FD.read()
            FD.close()
        except:
            self.setError(_("Error open profile: " ) +\
                               profileDirFile)
            return (applyDir, False)
        objHead = dirHeader(textProfile, self.objVar,function)
        if not objHead.headerCorrect:
            self.setError(_("Incorrect profile: " ) +\
                               profileDirFile)
            self.setError(objHead.errorMessage)
            return (applyDir, False)
        if not objHead.headerTerm:
                if objHead.getError():
                     self.setError(_("Incorrect profile: " ) +\
                               profileDirFile)
                return (applyDir, False)
        # Изменяем название директории
        if objHead.params.has_key("name"):
            nameDir = objHead.params['name']
            if "/" in nameDir or nameDir == ".." or nameDir == ".":
                self.setError (_("False value 'name' in profile: " ) +\
                               profileDirFile)
                return (applyDir, False)
            if not findChangeDir:
                pathRel = os.path.split(os.path.abspath(newDirMv))[0]
            # Новый путь к оригинальному файлу
            newDirMv = os.path.join(pathRel, nameDir)
            applyDir = newDirMv
        # При удаленнии директории
        if objHead.typeAppend == "remove":
            return (applyDir, False)
        return (applyDir, objHead)

    def scanProfiles(self, serviceName=False, dirObjs=False):
        """Сканирует директории профилей - выводит список файлов"""
        if not self.objVar.defined("cl_profile_path"):
            self.setError (_("not defined Var: ") + "cl_profile_path")
            return False
        if not dirObjs:
            if serviceName :
                self._servDir = serviceName
                if self._servDir:
                    if self._servDir[0] != "/":
                        self._servDir = "/" + self._servDir
                    if self._servDir[-1] != "/":
                        self._servDir += "/"
                    self._servDir = os.path.split(self._servDir)[0]
            dirsProfiles = self.objVar.Get("cl_profile_path")
            if self._servDir:
                tmpDirsProfiles = []
                for dirP in dirsProfiles:
                    dirProf = dirP + self._servDir
                    if os.access(dirProf, os.F_OK):
                        # Если директория существует
                        tmpDirsProfiles.append(dirProf)
                    else:
                        tmpDirsProfiles.append(False)
                dirsProfiles = tmpDirsProfiles
            dirObjs = self.scanDirs(dirsProfiles,self.objVar)
        #файлы к которым были применены профили
        filesApply = []
        # Словарь измененных директорий
        changeDirs = {}
        dirObjsApply = []
        for dirObj in dirObjs:
            dirInfoFile = os.path.join(dirObj.baseDir, self.profDirNameFile)
            ret = self.__isApplyHeadDir(dirInfoFile)
            if ret:
                dirObjsApply.append(dirObj)
            else:
                if self.getError():
                    self.setError(_("Incorrect profile: " ) +\
                                        dirInfoFile)
                    return False
        for dirObj in dirObjsApply:
            # сортируем файлы по названию
            if dirObj.files:
                dirObj.files.sort()
            # сортируем директории по названию
            if dirObj.dirs:
                dirObj.dirs.sort()
            blockDirs = []
            for dirProfile in dirObj.dirs:
                newDir = self._baseDir + dirProfile.partition(dirObj.baseDir)[2]
                newDir = "/".join(map(lambda x:x.split("?")[0],\
                                   newDir.split("/")))
                # Проверяем условие на директорию
                dirInfoFile = os.path.join(dirProfile, self.profDirNameFile)
                pathDir, objHeadDir = self.__getGenHeadDir(newDir,
                                                            dirInfoFile,
                                                            changeDirs)
                # Фильтрация профилей по названию директории
                if pathDir in self.dirsFilter:
                    blockDirs.append(dirProfile)
                    continue
                if objHeadDir:
                    if isinstance(objHeadDir, dirHeader):
                        if not objHeadDir.headerCorrect:
                            self.setError(_("Incorrect profile: " ) +\
                                            dirInfoFile)
                            self.setError(objHeadDir.errorMessage)
                            return False
                        if not objHeadDir.headerTerm:
                            if objHeadDir.getError():
                                self.setError(_("Incorrect profile: " ) +\
                                                dirInfoFile)
                                return False
                        if objHeadDir.params.has_key("name"):
                             changeDirs[dirProfile] = pathDir
                else:
                    if self.getError():
                        self.setError(_("Incorrect profile: " ) +\
                                        dirInfoFile)
                        return False
                    blockDirs.append(dirProfile)
            for fileProfile in dirObj.files:
                findBlock = False
                for blDir in blockDirs:
                    st,mid,end = fileProfile.partition(blDir)
                    if (not st) and mid and end:
                        findBlock = True
                        break
                if findBlock:
                    continue
                if self.getNeedProfile(fileProfile):
                    if self.getError():
                        #print self.getError()
                        return False
                    fileProfileChange = fileProfile
                    findChangeDir = False
                    listD = changeDirs.items()
                    listD.reverse()
                    for dirChangeIn, dirChangeOut in listD:
                        st,mid,end = fileProfile.partition(dirChangeIn)
                        if (not st) and mid and end:
                            findChangeDir = True
                            break
                    if findChangeDir:
                        oldFile = dirChangeOut + end
                    else:
                        oldFile = fileProfile.partition(dirObj.baseDir)[2]
                    # файл в системе без условий
                    oldFile = "/".join(map(lambda x:x.split("?")[0],\
                                   oldFile.split("/")))
                    if not findChangeDir:
                        oldFile = self._baseDir + oldFile
                    # Фильтрация профилей по названию файла
                    if oldFile in self.filesFilter:
                        continue
                    filesApply.append(oldFile)
                else:
                    if self.getError():
                        return False
        return filesApply

    def __isApplyHeadDir(self, profileDirFile):
        """Будет ли применен профиль корневой директории 

        Возвращает True, False
        """

        def function(text):
            """Функция обработки функций в заголовке"""
            return self.applyFuncProfile(text, "", profileDirFile)

        if not os.path.exists(profileDirFile):
            return True
        try:
            FD = open(profileDirFile)
            textProfile = FD.read()
            FD.close()
        except:
            self.setError(_("Error open profile: " ) +\
                               profileDirFile)
            return False
        # Заменяем переменные на их значения
        textProfile = self.applyVarsProfile(textProfile, profileDirFile)
        # Обработка заголовка
        objHead = dirHeader(textProfile, self.objVar,function)
        if not objHead.headerCorrect:
            self.setError(_("Incorrect profile: " ) +\
                               profileDirFile)
            self.setError(objHead.errorMessage)
            return False
        if not objHead.headerTerm:
                if objHead.getError():
                     self.setError(_("Incorrect profile: " ) +\
                               profileDirFile)
                return False

        ## Изменяем название директории
        #if objHead.params.has_key("name"):
            #self.setError (_("Invalid name 'name' in profile: " ) +\
                               #profileDirFile)
            #return False

        ## Удаляем директорию
        #if objHead.typeAppend == "remove":
            #self.setError (_("Invalid name 'remove' in profile: " ) +\
                               #profileDirFile)
            #return False

        ## chmod - изменяем права
        #if objHead.params.has_key("chmod"):
            #self.setError (_("Invalid name 'chmod' in profile: " ) +\
                               #profileDirFile)
            #return False

        ## chown - изменяем владельца и группу
        #if objHead.params.has_key("chown"):
            #self.setError (_("Invalid name 'chown' in profile: " ) +\
                               #profileDirFile)
            #return False
        return True

    def __getApplyHeadDir(self, newDir, profileDirFile, changeDirs):
        """Применяет профиль к директории (права, владелец, и.т. д)"""

        def function(text):
            """Функция обработки функций в заголовке"""
            return self.applyFuncProfile(text, newDir, profileDirFile)

        newDirMv = newDir
        findChangeDir = False
        #Меняем путь к директории
        listD = changeDirs.items()
        listD.reverse()
        for dirChangeIn, dirChangeOut in listD:
            st,mid,end = profileDirFile.partition(dirChangeIn)
            if (not st) and mid:
                findChangeDir = True
                break
        if findChangeDir:
            pathRel = dirChangeOut
            lenPathRel = len(pathRel.split("/"))
            lenNewDir = len(newDir.split("/"))
            lenEndDir =  lenNewDir - lenPathRel
            tmpDir = newDir
            namesDirs = []
            for i in range(lenEndDir):
                namesDirs.append(os.path.split(tmpDir)[1])
                tmpDir = os.path.split(tmpDir)[0]
            namesDirs.reverse()
            nameDir = "/".join(namesDirs)
            newDirMv = os.path.join(pathRel, nameDir)
        applyDir = newDirMv
        if not os.path.exists(profileDirFile):
            return (applyDir, True)
        try:
            FD = open(profileDirFile)
            textProfile = FD.read()
            FD.close()
        except:
            self.setError(_("Error open profile: " ) +\
                               profileDirFile)
            return (applyDir, False)
        # Заменяем переменные на их значения
        textProfile = self.applyVarsProfile(textProfile, profileDirFile)
        # Обработка заголовка
        objHead = dirHeader(textProfile, self.objVar,function)
        if not objHead.headerCorrect:
            self.setError(_("Incorrect profile: " ) +\
                               profileDirFile)
            self.setError(objHead.errorMessage)
            return (applyDir, False)
        if not objHead.headerTerm:
                if objHead.getError():
                     self.setError(_("Incorrect profile: " ) +\
                               profileDirFile)
                return (applyDir, False)

        # Изменяем название директории
        if objHead.params.has_key("name"):
            nameDir = objHead.params['name']
            if "/" in nameDir or nameDir == ".." or nameDir == ".":
                self.setError (_("False value 'name' in profile: " ) +\
                               profileDirFile)
                return (applyDir, False)
            if not findChangeDir:
                pathRel = os.path.split(os.path.abspath(newDirMv))[0]
            # Новый путь к оригинальному файлу
            newDirMv = os.path.join(pathRel, nameDir)
            applyDir = newDirMv

        # Удаляем директорию
        if objHead.typeAppend == "remove":
            if os.path.isdir(newDirMv):
                # удаляем директорию
                try:
                    self.removeDir(newDirMv)
                except:
                     self.setError(_("Can not delete dir: " ) +\
                                   newDirMv)
            return (applyDir, False)

        # chmod - изменяем права
        if objHead.params.has_key("chmod"):
            mode = self.__octToInt(objHead.params['chmod'])
            if mode:
                if not os.path.exists(newDirMv):
                    os.mkdir(newDirMv, mode)
                else:
                    os.chmod(newDirMv, mode)
            else:
                self.setError (_("False value 'chmod' in profile: " ) +\
                               profileDirFile)
                return (applyDir, False)
        # chown - изменяем владельца и группу
        if objHead.params.has_key("chown"):
            owner = objHead.params['chown']
            if owner:
                if  ":" in owner:
                    strUid, strGid = owner.split(":")
                    import pwd
                    try:
                        uid = pwd.getpwnam(strUid)[2]
                    except:
                        self.setError (_("Not user in this system: ") + strUid)
                        self.setError (_("False value 'chown' in profile: " )+\
                               profileDirFile)
                        return (applyDir, False)
                    try:
                        import grp
                        gid = grp.getgrnam(strGid)[2]
                    except:
                        self.setError (_("Not group in this system: ")+strGid)
                        self.setError (_("False value 'chown' in profile: " )+\
                               profileDirFile)
                        return (applyDir, False)

                    if not os.path.exists(newDirMv):
                        dirProfile = os.path.split(profileDirFile)[0]
                        try:
                            mode,uidTmp,gidTmp = self.getModeFile(dirProfile)
                        except OSError:
                            self.setError (_("not access dir:" ) + newDirMv)
                            return (applyDir, False)
                        os.mkdir(newDirMv, mode)
                    os.chown(newDirMv, uid, gid)
                else:
                    self.setError (_("False value 'chown' in profile: " ) +\
                               profileDirFile)
                    return (applyDir, False)
            else:
                self.setError (_("False value 'chown' in profile: " ) +\
                               profileDirFile)
                return (applyDir, False)
        return (applyDir, objHead)

    def __getApplyHeadProfile(self ,newFile, oldFile, copyFile):
        """Применяет заголовок к профилю (права, владелец, и.т. д)"""

        def function(text):
            """Функция обработки функций в заголовке"""
            return self.applyFuncProfile(text, newFile, oldFile)

        self.closeFiles()
        # Файлы в системе к которым были применены профили
        applyFiles = [oldFile]
        if copyFile:
            self.nameFileNew = self.absFileName(newFile)
            self.FN = self.openNewFile(self.nameFileNew)
            self.newProfile = self.FN.read()
            self.closeNewFile()
        objHeadNew = fileHeader(self.newProfile, False,
                                self.getFileType(),objVar=self.objVar,
                                function=function)
        if not objHeadNew.headerCorrect:
            self.setError(_("Incorrect profile: " ) +\
                               newFile)
            self.setError(objHeadNew.errorMessage)
            return (applyFiles, False)
        if not objHeadNew.headerTerm:
                if objHeadNew.getError():
                     self.setError(_("Incorrect profile: " ) +\
                               newFile)
                return (applyFiles, False)

        pathProg = ""
        # Путь к оригинальному файлу
        pathOldFile = oldFile
        # Изменяем путь к оригинальному файлу
        if objHeadNew.params.has_key("name"):
            nameFile = objHeadNew.params['name']
            if "/" in nameFile or nameFile == ".." or nameFile == ".":
                self.setError (_("False value 'name' in profile: " ) + newFile)
                return False
            pathRel = os.path.split(os.path.abspath(oldFile))[0]
            # Новый путь к оригинальному файлу
            pathOldFile = os.path.join(pathRel,nameFile)

        # В случае force
        if objHeadNew.params.has_key("force"):
            if os.path.islink(pathOldFile):
                # удаляем ссылку
                try:
                    os.unlink(pathOldFile)
                except:
                    self.setError(_("Can not delete link: " ) +\
                               pathOldFile)
                    return (applyFiles, False)
            if os.path.isfile(pathOldFile):
                # удаляем файл
                try:
                    os.remove(pathOldFile)
                except:
                    self.setError(_("Can not delete file: " ) +\
                               pathOldFile)
                    return (applyFiles, False)

        # Удаляем оригинальный файл
        if objHeadNew.typeAppend == "remove":
            if os.path.islink(pathOldFile):
                # удаляем ссылку
                try:
                    os.unlink(pathOldFile)
                except:
                    self.setError(_("Can not delete link: " ) +\
                               pathOldFile)
            if os.path.isfile(pathOldFile):
                # удаляем файл
                try:
                    os.remove(pathOldFile)
                except:
                    self.setError(_("Can not delete file: " ) +\
                               pathOldFile)
            return (applyFiles, False)

        flagSymlink = False
        flagForce = False
        # Если есть параметр mirror
        if objHeadNew.params.has_key("mirror"):
            if objHeadNew.params.has_key("link"):
                profileFile = objHeadNew.params['link']
                if not os.path.exists(profileFile):
                    if os.path.exists(pathOldFile):
                        os.remove(pathOldFile)
                    return (applyFiles, False)
            elif not os.path.exists(pathOldFile):
                return (applyFiles, False)
        # Если есть указатель на файл профиля (link)
        if objHeadNew.params.has_key("link") and\
            not objHeadNew.params.has_key("symbolic"):
            profileFile = objHeadNew.params['link']
            foundProfileFile = os.path.exists(profileFile)
            if foundProfileFile:
                FO = self.openNewFile(profileFile)
                buff = FO.read()
                FO.close()
            if os.path.exists(pathOldFile):
                os.remove(pathOldFile)
            if foundProfileFile:
                fd = os.open(pathOldFile, os.O_CREAT)
                os.close(fd)
                os.chmod(pathOldFile, self._mode)
                os.chown(pathOldFile, self._uid, self._gid)
                FON  = open (pathOldFile, "r+")
                FON.write(buff)
                FON.close()

        # Если символическая ссылка
        if objHeadNew.params.has_key("symbolic"):
            prevOldFile = pathOldFile
            pathOldFile = objHeadNew.params['link']
            flagSymlink = True
            if not "/" == pathOldFile[0]:
                pathLink = os.path.split(os.path.abspath(prevOldFile))[0]
                pathProg = os.getcwd()
                os.chdir(pathLink)

        # chmod - изменяем права
        if objHeadNew.params.has_key("chmod"):
            mode = self.__octToInt(objHeadNew.params['chmod'])
            if mode:
                if not os.path.exists(pathOldFile):
                    fd = os.open(pathOldFile, os.O_CREAT)
                    os.close(fd)
                os.chmod(pathOldFile, mode)
            else:
                self.setError (_("False value 'chmod' in profile: " ) +\
                               newFile)
                return (applyFiles, False)

        # chown - изменяем владельца и группу
        if objHeadNew.params.has_key("chown"):
            owner = objHeadNew.params['chown']
            if owner:
                if  ":" in owner:
                    strUid, strGid = owner.split(":")
                    import pwd
                    try:
                        uid = pwd.getpwnam(strUid)[2]
                    except:
                        self.setError (_("Not user in this system: ") + strUid)
                        self.setError (_("False value 'chown' in profile: " )+\
                               newFile)
                        return (applyFiles, False)
                    try:
                        import grp
                        gid = grp.getgrnam(strGid)[2]
                    except:
                        self.setError (_("Not group in this system: ")+strGid)
                        self.setError (_("False value 'chown' in profile: " )+\
                               newFile)
                        return (applyFiles, False)

                    if not os.path.exists(pathOldFile):
                        FO = self.openNewFile(newFile)
                        FO.close()
                        fd = os.open(pathOldFile, os.O_CREAT)
                        os.close(fd)
                        os.chmod(pathOldFile, self._mode)
                    os.chown(pathOldFile, uid, gid)
                else:
                    self.setError (_("False value 'chown' in profile: " ) +\
                               newFile)
                    return (applyFiles, False)
            else:
                self.setError (_("False value 'chown' in profile: " ) +\
                               newFile)
                return (applyFiles, False)

        self.openFiles(newFile, pathOldFile)
        if flagSymlink:
            if os.path.exists(prevOldFile) or os.path.islink(prevOldFile):
                if os.path.islink(prevOldFile):
                    # если ссылка то удаляем её
                    os.unlink(prevOldFile)
                else:
                    # иначе удаляем файл
                    os.remove(prevOldFile)
            if not "/" == pathOldFile[0]:
                os.symlink(pathOldFile, prevOldFile)
                applyFiles = [prevOldFile,os.path.join(pathLink,pathOldFile)]
            else:
                os.symlink(pathOldFile, prevOldFile)
                applyFiles = [prevOldFile,pathOldFile]
            if not objHeadNew.body.strip():
                return (applyFiles, False)
        else:
            applyFiles = [pathOldFile]
        if pathProg:
            os.chdir(pathProg)
        # Если файлы заменяются не нужно их обрабатывать дальше
        if objHeadNew.typeAppend == "replace" and\
            not objHeadNew.params.has_key("symbolic") and\
            objHeadNew.params.has_key("link"):
                return (applyFiles, False)
        return (applyFiles, objHeadNew)

    def createNewClass(self, name, bases, attrs={}):
        """Создает объект нового класса

        createNewClass(self, name, bases, attrs)
        name - имя класса - str,
        bases - cписок наследуемых классов - (tuple),
        attrs - аттрибуты класса - {dict}
        """
        class newMethod:
            #Объединяем конфигурации
            def join(self, newObj):
                if newObj.__class__.__name__ == self.__class__.__name__:
                    self.docObj.joinDoc(newObj.doc)
                    # Пост обработка
                    if 'postXML' in dir(self):
                        self.postXML()
        attrsNew = {}
        attrsNew["configName"] = name
        if attrs:
            for key in attrs.keys():
               attrsNew[key] = attrs[key]
        newCl = type(name, bases + (newMethod, object,), attrsNew)
        return newCl

    def fileIsUtf(self, fileName):
        """Проверяет файл на кодировку UTF-8"""
        if os.path.exists(fileName):
            FD = open(self.absFileName(fileName))
            newProfile = FD.read()
            FD.close()
            try:
                newProfile.decode("UTF-8")
            except:
                return False
        return True

    def join(self, newFile, oldFile, ListOptTitle):
        """Объединения профиля и конф. файла

        join(newFile, oldFile, ListOptTitle)
        Объединение профиля newFile и конф. файла oldFile,
        ListOptTitle - список строк которые добавятся в заголовок
        """
        # Выполняем условия для блока текста а так-же заменяем переменные
        self.nameFileNew = self.absFileName(newFile)
        self.FN = self.openNewFile(self.nameFileNew)
        self.newProfile = self.FN.read()
        self.closeNewFile()
        copyFile = True
        if self.getFileType() != "bin":
            # Вычисляем условные блоки
            self.newProfile = self.applyTermsProfile(self.newProfile,
                                                     newFile, oldFile)
            #print "|%s|" %(self.newProfile)
            # Заменяем переменные на их значения
            self.newProfile = self.applyVarsProfile(self.newProfile,
                                                    newFile)
            # Вычисляем функции
            self.newProfile = self.applyFuncProfile(self.newProfile,
                                                    newFile, oldFile)
            copyFile = False
        filesApply, objHeadNew = self.__getApplyHeadProfile(newFile, oldFile,
                                                            copyFile)
        if not objHeadNew:
            return filesApply
        # Флаг - кодировка с бинарными примесями у файла профиля включаем при
        # условии текстового файла и кодировки отличной от UTF-8
        flagNotUtf8New = False
         # Флаг - кодировка с бинарными примесями у оригинального файла
        flagNotUtf8Old = False 
        if not copyFile:
            # проверяем кодировку профиля
            if not self.fileIsUtf(newFile):
                flagNotUtf8New = True
        if not (objHeadNew.params.has_key("link") and\
            objHeadNew.params.has_key("symbolic")):
            # проверяем кодировку оригинального файла
            if not self.fileIsUtf(oldFile):
                flagNotUtf8Old = True
        self.newProfile = objHeadNew.body
        #if objHeadNew.fileType != "bin":
            #self.newProfile = self.applyTermsProfile(self.newProfile,
                                                     #newFile)
            #self.newProfile = self.applyVarsProfile(self.newProfile)

        # Титл конфигурационного файла
        title = ""
        if ListOptTitle:
            title = self.getTitle(objHeadNew.comment,
                              ListOptTitle)
            title = title.encode("UTF-8")

        objHeadOld = False
        if objHeadNew.comment:
            objHeadOld = fileHeader(self.oldProfile, objHeadNew.comment)
        # Тестирование
        #print self.nameFileOld
        #print objHeadNew.typeAppend
        if objHeadNew.fileType:
            # Создаем объект в случае параметра format в заголовке
            if (objHeadNew.typeAppend == "replace" or\
                objHeadNew.typeAppend == "before" or\
                objHeadNew.typeAppend == "after") and\
                not (objHeadNew.fileType == "bin" or\
                objHeadNew.fileType == "raw"):
                # Преобразовываем бинарные файлы
                if flagNotUtf8New:
                    objTxtCoder = utfBin()
                    self.newProfile = objTxtCoder.encode(self.newProfile)
                try:
                    exec ("objProfNew=%s(self.newProfile)"%\
                          (objHeadNew.fileType))
                except NameError:
                    #Создаем объект из self.newObjProt с помощью
                    # метаклассов
                    if self.newObjProt.has_key(objHeadNew.fileType):
                        objProfNewCl = self.createNewClass(\
                                          objHeadNew.fileType,
                                          self.newObjProt[objHeadNew.fileType])
                        objProfNew = objProfNewCl(self.newProfile)
                    else:
                        self.setError (\
                        _("False join profile for type profile: ")\
                                   + objHeadNew.fileType + " : " +\
                                   newFile)
                        return False

                if "xml_" in objHeadNew.fileType:
                    if objProfNew.getError():
                        self.setError (_("False profile: " ) + newFile)
                        return False
                    nameRootNode = oldFile.rpartition("/")[2].split(".")[0]
                    objProfNew.setNameBodyNode(nameRootNode)
                # Объект Документ
                docObj = objProfNew.docObj
                # Удаление комментариев из документа
                docObj.removeComment(docObj.getNodeBody())
                # Добавление необходимых переводов строк
                docObj.insertBRtoBody(docObj.getNodeBody())
                # Добавление необходимых разделителей между областями
                docObj.insertBeforeSepAreas(docObj.getNodeBody())
                # Пост обработка
                if 'postXML' in dir(objProfNew):
                    objProfNew.postXML()
                # Получение текстового файла из XML документа
                self.newProfile = objProfNew.getConfig().encode("UTF-8")
                # Если не UTF-8 производим преобразование
                if flagNotUtf8New:
                    self.newProfile = objTxtCoder.decode(self.newProfile)
                # Титл для объединения
                if ListOptTitle:
                    title = self.getTitle(objProfNew._comment,
                              ListOptTitle)
                    title = title.encode("UTF-8")
            # Замена
            if objHeadNew.typeAppend == "replace":
                if "xml_" in objHeadNew.fileType:
                    data = self.newProfile.split("\n")
                    data.insert(1,title)
                    self.oldProfile = "\n".join(data)
                else:
                    if objHeadNew.execStr:
                        self.oldProfile = objHeadNew.execStr+title+\
                                          self.newProfile
                    else:
                        self.oldProfile = title + self.newProfile
                self.saveOldFile()
                return filesApply
            # Впереди
            elif objHeadNew.typeAppend == "before":
                if "xml_" in objHeadNew.fileType:
                    self.setError (\
                        _("False option append=before in profile %s") %newFile)
                    return False
                if objHeadOld and objHeadOld.body:
                    self.oldProfile = objHeadOld.body
                if self.newProfile[-1] == "\n":
                    tmpProfile = self.newProfile + self.oldProfile
                else:
                    tmpProfile = self.newProfile + "\n" + self.oldProfile
                if objHeadNew.execStr:
                    self.oldProfile = objHeadNew.execStr + title + tmpProfile
                elif objHeadOld.execStr:
                    self.oldProfile = objHeadOld.execStr + title + tmpProfile
                else:
                    self.oldProfile = title + tmpProfile

                #print self.oldProfile
                self.saveOldFile()
                return filesApply
            # Cзади
            elif objHeadNew.typeAppend == "after":
                if "xml_" in objHeadNew.fileType:
                    self.setError (\
                        _("False option append=after in profile %s") %newFile)
                    return False
                if objHeadOld and objHeadOld.body:
                    self.oldProfile = objHeadOld.body
                if self.newProfile[-1] == "\n":
                    tmpProfile = self.oldProfile + self.newProfile
                else:
                    tmpProfile = self.oldProfile + "\n" + self.newProfile
                if objHeadNew.execStr:
                    self.oldProfile = objHeadNew.execStr + title + tmpProfile
                elif objHeadOld.execStr:
                    self.oldProfile = objHeadOld.execStr + title + tmpProfile
                else:
                    self.oldProfile = title + tmpProfile
                self.saveOldFile()
                return filesApply
            # Объединение
            elif objHeadNew.typeAppend == "join":
                if flagNotUtf8New:
                    objTxtCoder = utfBin()
                    self.newProfile = objTxtCoder.encode(self.newProfile)
                try:
                    exec ("objProfNew=%s(self.newProfile)"%\
                          (objHeadNew.fileType))
                except NameError:
                    #Создаем объект из self.newObjProt с помощью
                    # метаклассов
                    if self.newObjProt.has_key(objHeadNew.fileType):
                        objProfNewCl = self.createNewClass(\
                                          objHeadNew.fileType,
                                          self.newObjProt[objHeadNew.fileType])
                        objProfNew = objProfNewCl(self.newProfile)
                    else:
                        self.setError (\
                        _("False join profile for type profile: ")\
                                   + objHeadNew.fileType + " : " +\
                                   newFile)
                        return False
                if "xml_" in objHeadNew.fileType:
                    if objProfNew.getError():
                        self.setError (_("False profile: " ) + newFile)
                        return False
                    nameRootNode = oldFile.rpartition("/")[2].split(".")[0]
                    objProfNew.setNameBodyNode(nameRootNode)
                # Титл для объединения
                if ListOptTitle:
                    title = self.getTitle(objProfNew._comment,
                              ListOptTitle)
                    title = title.encode("UTF-8")

                # В случае пустого конфигурационного файла
                reNoClean = re.compile("[^\s]",re.M)
                if not self.oldProfile or\
                    not reNoClean.search(self.oldProfile):
                    self.oldProfile = ""
                    #if objHeadNew.execStr:
                        #self.oldProfile = objHeadNew.execStr + \
                            #title + objProfNew.getConfig().encode("UTF-8")
                    #else:
                        #self.oldProfile = title +\
                        #objProfNew.getConfig().encode("UTF-8")
                    #self.saveOldFile()
                    #return True

                objHeadOld = fileHeader(self.oldProfile, objProfNew._comment)
                if objHeadOld.body:
                    self.oldProfile = objHeadOld.body
                else:
                    self.oldProfile = ""
                if flagNotUtf8Old:
                    objTxtCoder = utfBin()
                    self.oldProfile = objTxtCoder.encode(self.oldProfile)
                if self.newObjProt.has_key(objHeadNew.fileType):
                    objProfOldCl = self.createNewClass(\
                                          objHeadNew.fileType,
                                          self.newObjProt[objHeadNew.fileType])
                    objProfOld = objProfOldCl(self.oldProfile)
                else:
                    exec ("objProfOld=%s(self.oldProfile)"%\
                         (objHeadNew.fileType))
                if "xml_" in objHeadNew.fileType:
                    if objProfOld.getError():
                        self.setError (_("False profile: " ) + oldFile)
                        return False
                    nameRootNode = oldFile.rpartition("/")[2].split(".")[0]
                    objProfOld.setNameBodyNode(nameRootNode)

                #print "#%s#" %(objProfOld.docObj.body.toprettyxml())
                #print "#%s#" %(objProfNew.docObj.body.toprettyxml())
                objProfOld.join(objProfNew)
                    #print objProfOld.doc.toprettyxml()
                    #print objProfNew.doc.toprettyxml()
                if "xml_" in objHeadNew.fileType:
                    if objProfOld.getError():
                        self.setError (_("False profile: " ) + newFile)
                        return False
                    data = \
                        objProfOld.getConfig().encode("UTF-8").split("\n")
                    data.insert(1,title)
                    self.oldProfile = "\n".join(data)
                else:
                    if objHeadNew.execStr:
                        self.oldProfile = objHeadNew.execStr + title +\
                                        objProfOld.getConfig().encode("UTF-8")
                    elif objHeadOld.execStr:
                        self.oldProfile = objHeadOld.execStr + title +\
                                        objProfOld.getConfig().encode("UTF-8")
                    else:
                        self.oldProfile = title +\
                                        objProfOld.getConfig().encode("UTF-8")
                # Декодируем если кодировка не UTF-8
                if flagNotUtf8New or flagNotUtf8Old:
                    self.newProfile = objTxtCoder.decode(self.newProfile)
                    self.oldProfile = objTxtCoder.decode(self.oldProfile)
                self.saveOldFile()
                return filesApply
            else:
                self.setError (_("False (type append) profile: " ) +\
                               objHeadNew.typeAppend)
                return False
        else:
            self.setError (_("Type profile not found: ") + newFile)
            return False
        return filesApply

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

    """
    _comment = "#"
    configName = "samba"
    configVersion = "0.1"
    reHeader = re.compile("^[\t ]*\[[^\[\]]+\].*\n",re.M)
    reBody = re.compile(".+",re.M|re.S)
    reComment = re.compile("\s*%s.*|\s*;.*"%(_comment))
    reSeparator = re.compile("\s*=\s*")
    sepFields = "\n"
    reSepFields = re.compile(sepFields)

    def __init__(self,text):
        self.text = text
        self.blocTextObj = blocText()
        self._splitToFields =  self.splitToFields
        # Объект документ
        self.docObj = self._textToXML()
        # XML документ
        self.doc = self.docObj.doc

    def postXML(self):
        """Последующая постобработка XML"""
        # Для добавления перевода строки между областями если его нет
        #print self.docObj.body.toprettyxml()
        xmlAreas = xpath.Evaluate("child::area", self.docObj.body)
        for xmlArea in xmlAreas:
            if xmlArea.previousSibling and\
            self.docObj.getTypeField(xmlArea.previousSibling) == "br":
                continue
            firstArea = False
            xmlFields = xpath.Evaluate("child::field", xmlArea)
            if not (xmlFields and\
                (self.docObj.getTypeField(xmlFields[-1]) == "br" or\
                    self.docObj.getTypeField(xmlFields[-1]) == "comment")):
                if xmlArea.nextSibling:
                    parentNode = xmlArea.parentNode
                    nextNode = xmlArea.nextSibling
                    parentNode.insertBefore(self.docObj.createField("br",
                                                            [],"",[],
                                                            False,False),
                                                            nextNode)
        # Удаление лишних переводов строк
        childNodes = self.docObj.getFieldsArea(self.docObj.body)
        lenBr = 0
        removeBrNodes = []
        for node in childNodes:
            if node.tagName == "field" and\
                self.docObj.getTypeField(node) == "br":
                lenBr += 1
                if lenBr > 2:
                    removeBrNodes.append(node)
            else:
                lenBr = 0
        # Удаление
        for rmNode in removeBrNodes:
           self.docObj.body.removeChild(rmNode)


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

    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) > 2:
                    valueList = nameValue[1:]
                    nameValue =[nameValue[0],"=".join(valueList)]
                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 splitCleanBloc(self, txtBloc):
        """Делим блок на две части (переменные, пустые строки в конце)"""
        txtLines = txtBloc.split("\n")
        firstBloc = []
        nextBloc = []
        txtLines.reverse()
        z = 0
        for txtLine in txtLines:
            if not txtLine.strip():
                nextBloc.append(txtLine)
            else:
                break
            z += 1
        txtLines.reverse()
        firstBloc = txtLines[:-z]
        nextBloc.reverse()
        if nextBloc:
            firstBloc.append("")
        if nextBloc and "\n".join(nextBloc):
            return ("\n".join(firstBloc), "\n".join(nextBloc))
        else:
            return False

    def getFullAreas(self, blocs):
        """Делит текст на области, (Заголовок, тело)

        Возвращает два списка: заголовки, тела
        """
        headsAreas = []
        bodyAreas = []
        if not blocs:
            return []
        lenBlocs = len(blocs[0])
        for i in range(lenBlocs):
            txtBloc = blocs[1][i]
            clean = self.splitCleanBloc(txtBloc)
            if clean:
                headsAreas.append(blocs[0][i])
                bodyAreas.append(clean[0])
                headsAreas.append("")
                bodyAreas.append(clean[1])
            else:
                headsAreas.append(blocs[0][i])
                bodyAreas.append(blocs[1][i])
        return (headsAreas, bodyAreas)

    def createTxtConfig(self, strHeader, dictVar):
        """Cоздает область с заголовком

        создает текст конфигурационного файла в формате samba из
        заголовка (строка) и словаря переменных
        """
        if not strHeader:
            return ""
        outTxt = "[" + strHeader + "]\n"
        for key in dictVar.keys():
            outTxt += "%s = %s\n" %(key,dictVar[key])
        return outTxt

    def _textToXML(self):
        """Преобразует текст в XML"""
        blTmp = self.blocTextObj.findBloc(self.text,self.reHeader,self.reBody)
        blocs = self.getFullAreas(blTmp)
        headers = []
        startHeaders = []
        finHeaders = []
        docObj = xmlDoc()
        docObj.createDoc(self.configName, self.configVersion)
        rootNode = docObj.getNodeBody()
        # Если пустой текст то создаем пустой документ
        if not blocs:
            return docObj

        for h in blocs[0]:
            listfinH = h.split("]")
            finH = listfinH[0]
            if "[" in finH:
                startHeaders.append(finH + "]")
            else:
                startHeaders.append(finH)
            if len(listfinH) == 2:
                finHeaders.append(listfinH[1])
            else:
                finHeaders.append("")
            headers.append(finH.replace("[","").replace("]","").strip())
        bodys = blocs[1]

        z = 0
        for h in headers:
            if not bodys[z]:
                z += 1
                continue
            areaAction = False
            if h:
                if h[0] == "!":
                    docObj.createCaption(h[1:], [startHeaders[z],""])
                    areaAction = "drop"
                elif h[0] == "-":
                    docObj.createCaption(h[1:], [startHeaders[z],""])
                    areaAction = "replace"
                else:
                    docObj.createCaption(h, [startHeaders[z],""])
            else:
                docObj.createCaption(h, [startHeaders[z],""])

            if "\n" in blocs[0][z]:
                if self.reComment.search(finHeaders[z]):
                        docObj.createField('comment', [finHeaders[z]])
                elif not finHeaders[z].strip() and\
                     finHeaders[z].replace("\n",""):
                        docObj.createField('br',
                                            [finHeaders[z].replace("\n","")])
                else:
                    docObj.createField('br')
            fields = self._splitToFields(bodys[z])
            for f in fields:
                if f.name != False and f.value!=False and f.br!=False:
                    # Обработка условий для samba
                    if f.name[0] == "!" or f.name[0] == "-" or\
                        f.name[0] == "+":
                        qns = self.removeSymbolTerm(f.br)
                        xmlField = docObj.createField("var",
                                                  [qns],
                                                  f.name[1:], [f.value])
                        if f.name[0] == "!":
                            # Удаляемое в дальнейшем поле
                            docObj.setActionField(xmlField, "drop")
                    else:
                        docObj.createField("var",[f.br.replace("\n","")],
                                           f.name, [f.value])
                    docObj.createField('br')
                elif f.comment != False:
                    docObj.createField('comment', [f.comment])
                elif f.br != False:
                    docObj.createField('br', [f.br.replace("\n","")])
            if h.strip():
                area = docObj.createArea()
                if areaAction:
                    docObj.setActionArea(area, areaAction)
                rootNode.appendChild(area)
            else:
                fieldsNodes = docObj.tmpFields.getFields()
                for fieldNode in fieldsNodes:
                    rootNode.appendChild(fieldNode)
                docObj.clearTmpFields()
            z += 1
        #print docObj.doc.toprettyxml()
        return docObj

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

    """
    _comment = "#"
    configName = "compiz"
    configVersion = "0.1"
    reHeader = re.compile("^[\t ]*\[[^\[\]]+\].*\n",re.M)
    reBody = re.compile(".+",re.M|re.S)
    reComment = re.compile("\s*%s.*"%(_comment))
    reSeparator = re.compile("\s*=\s*")
    sepFields = "\n"
    reSepFields = re.compile(sepFields)

    def __init__(self,text):
        samba.__init__(self,text)

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

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 __init__(self,text):
        self.text = text
        self.blocTextObj = blocText()
        # Объект документ
        self.docObj = self.textToXML()
        # Создаем поля-массивы
        self.docObj.postParserList()
        # XML документ
        self.doc = self.docObj.doc

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

        начальный текстовый блок,
        открывающий блок,
        блок-тело,
        закрывающий блок
        """
        firstBloc = ""
        startBloc = ""
        bodyBloc = ""
        endBloc = ""
        textLines = text.splitlines()
        findOpen = False
        if textLines:
            findOpen = reOpen.search(textLines[0])
        openBl = reOpen.search(text)
        if findOpen and reComment.split(text)[0].strip():
            blocA = text[openBl.end():]
            firstBloc = text[:openBl.start()]
            startBloc = text[openBl.start():openBl.end()]
            closeBl = reClose.search(blocA)
            endBloc = blocA[closeBl.start():closeBl.end()]
            bodyBloc = blocA[:closeBl.start()]
            return (firstBloc, startBloc, bodyBloc, endBloc)
        else:
            return (firstBloc, startBloc, text, endBloc)


    # Делим текст на области включая вложенные (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 != 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 != False:
                                fieldXML = docObj.createField("comment",
                                                              [field.comment],
                                                              "", [],
                                                              False, False)
                                areaXML.appendChild(fieldXML)
                            elif field.br != 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 != 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 != False:
                        fieldXML = docObj.createField("comment",
                                                      [field.comment],
                                                      "", [],
                                                      False, False)
                        rootNode.appendChild(fieldXML)
                    elif field.br != 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)

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

    """
    _comment = "#"
    configName = "apache"
    configVersion = "0.1"
    __headerArea = "[^\<\> \t]+[ \t]+[^\<\> \t]+"
    __openArea = "[ \t]*\<%s\>"%(__headerArea)
    __closeArea = "[ \t]*\<\/[^\<\>]+\>"
    sepFields = "\n"
    reOpen = re.compile(__openArea)
    reClose = re.compile(__closeArea)
    reCloseArea = re.compile(__closeArea + "\s*\Z")
    reComment = re.compile("[ \t]*%s"%(_comment))
    reSepFields = re.compile(sepFields)
    reSeparator = re.compile("[ \t]+")
    reHeader = re.compile(__headerArea)

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

    def postXML(self):
        """Последующая постобработка XML"""
        # Для добавления перевода строки перед закрывающим тегом
        # конфигурационного файла
        xmlFields = xpath.Evaluate("child::fields", self.docObj.body)
        if not (xmlFields and\
                self.docObj.getTypeField(xmlFields[-1]) == "br"):
                    self.docObj.body.appendChild(self.docObj.createField("br",
                                                            [],"",[],
                                                            False,False))
        xmlAreas = xpath.Evaluate("child::area", self.docObj.body)
        for xmlArea in xmlAreas:
            xmlFields = xpath.Evaluate("child::field", xmlArea)
            if not (xmlFields and\
                self.docObj.getTypeField(xmlFields[-1]) == "br"):
                    xmlArea.appendChild(self.docObj.createField("br",
                                                            [],"",[],
                                                            False,False))

    def join(self, apacheObj):
        """Объединяем конфигурации"""
        if isinstance(apacheObj, apache):
            #print self.docObj.doc.toprettyxml()
            self.docObj.joinDoc(apacheObj.doc)
            self.postXML()

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

        начальный текстовый блок,
        открывающий блок,
        блок-тело,
        закрывающий блок
        """
        firstBloc = ""
        startBloc = ""
        bodyBloc = ""
        endBloc = ""
        textLines = text.splitlines()
        findOpen = False
        if textLines:
            findOpen = reOpen.search(textLines[0])
        openBl = reOpen.search(text)
        if findOpen and reComment.split(text)[0].strip():
            blocA = text[openBl.end():]
            firstBloc = ""
            startBloc = text[openBl.start():openBl.end()]
            headBl = reHeader.search(startBloc)
            if headBl:
                firstBloc = headBl.group(0)
            closeBl = reClose.search(blocA)
            endBloc = blocA[closeBl.start():closeBl.end()]
            bodyBloc = blocA[:closeBl.start()]
            return (firstBloc, startBloc, bodyBloc, endBloc)
        else:
            return (firstBloc, startBloc, text, endBloc)

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

        возвращает список объектов областей (переменная 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, reHeader)
            areaA.header = first.replace(" ","").replace("\t","")
            areaA.start =  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, reHeader)
                    areas.append(areaA)
            else:
                areaA.fields.append(body)
                areas.append(areaA)


    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]
            #print "#"+brBloc[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) == 3:
                    valueList = nameValue[2:]
                    nameValue =["".join(nameValue[:2])," ".join(valueList)]

                if len(nameValue) > 3:
                    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 textToXML(self):
        """Преобразуем тект в XML"""
        areas = []
        self.splitToAllArea(self.text, areas, self.reOpen, self.reClose,
                       self.reCloseArea,self.reComment,self.reSepFields,
                       self.reHeader)
        docObj = xmlDoc()

        # Создание объекта документ c пустым разделителем между полями
        docObj.createDoc(self.configName, self.configVersion)
        if not areas:
            return docObj
        self.createXML(areas, docObj.getNodeBody(), docObj)
        return docObj

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

    """
    _comment = "#"
    configName = "postfix"
    configVersion = "0.1"
    sepFields = "\n"
    reComment = re.compile("[ \t]*%s"%(_comment))
    reSepFields = re.compile(sepFields)
    # разделитель названия и значения переменной
    reSeparator = re.compile("\s*=\s*")
    def __init__(self,text):
        self.text = text
        # Объект документ
        self.docObj = self.textToXML()
        # Создаем поля разделенные массивы
        self.docObj.postParserListSeplist(self.docObj.body)
        # XML документ
        self.doc = self.docObj.doc

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

    def textToXML(self):
        """Преобразуем текст в XML"""
        class area:
            def __init__(self):
                self.header = False
                self.start = False
                self.fields = []
                self.end = False
        areas = []
        oneArea = area()
        oneArea.header = ""
        oneArea.start = ""
        oneArea.fields = [self.text]
        oneArea.end = ""
        areas.append(oneArea)
        docObj = xmlDoc()
        # Создание объекта документ c пустым разделителем между полями
        docObj.createDoc(self.configName, self.configVersion)
        if not areas:
            return docObj
        self.createXML(areas, docObj.getNodeBody(), docObj)
        return docObj


    def setDataField(self, txtLines, endtxtLines):
        """Cоздаем список объектов с переменными"""
        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]
            #print "#"+brBloc[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

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

    """
    _comment = "#"
    configName = "ldap"
    configVersion = "0.1"
    # Регулярное выражение для заголовка области
    reHeader = re.compile("^[\t ]*(access|syncrepl)[^\n]+\n?")
    # Регулярное выражения для области
    reArea = re.compile("([\t ]*(access|syncrepl)[^\n]+\
\n([\t ]+[^\n]+\n?)+)",re.M|re.S)
    reComment = re.compile("\s*%s.*"%(_comment))
    # разделитель между переменной и значением переменной
    reSeparator = re.compile("\s+|\s*=\s*")
    # разделитель полей
    sepFields = "\n"
    # регулярное выражение для разделителя полей
    reSepFields = re.compile(sepFields)

    def __init__(self,text):
        self.text = text
        self.blocTextObj = blocText()
        self._splitToFields =  self.splitToFields
        # Объект документ
        self.docObj = self._textToXML()
        # Создаем поля-массивы
        self.docObj.postParserList()
        # Создаем поля разделенные массивы
        self.docObj.postParserListSeplist(self.docObj.body)
        # XML документ
        self.doc = self.docObj.doc

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

    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) > 2:
                    valueList = nameValue[2:]
                    nameValue =[nameValue[0]+nameValue[1]," ".join(valueList)]
                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 _textToXML(self):
        """Преобразует текст в XML"""
        blTmp = self.blocTextObj.findArea(self.text,self.reHeader,self.reArea)
        blocs = self.getFullAreas(blTmp)
        headers = []
        startHeaders = []
        finHeaders = []
        docObj = xmlDoc()
        docObj.createDoc(self.configName, self.configVersion)
        rootNode = docObj.getNodeBody()
        # Если пустой текст то создаем пустой документ
        if not blocs:
            return docObj

        for h in blocs[0]:
            headers.append(h.rstrip())
        bodys = blocs[1]

        z = 0
        for h in headers:
            if not bodys[z]:
                z += 1
                continue
            areaAction = False
            if h:
                if h[0] == "!":
                    header = self.removeSymbolTerm(h.strip())
                    headerQuote = self.removeSymbolTerm(h)
                    docObj.createCaption(header,[headerQuote,""])
                    areaAction = "drop"
                elif h[0] == "-":
                    header = self.removeSymbolTerm(h.strip())
                    headerQuote = self.removeSymbolTerm(h)
                    docObj.createCaption(header,[headerQuote,""])
                    areaAction = "replace"
                else:
                    docObj.createCaption(h.strip(), [h.rstrip(),""])
            else:
                docObj.createCaption(h.strip(), [h.rstrip(),""])

            if "\n" in blocs[0][z]:
                resHead = self.reComment.search(h)
                if resHead:
                        docObj.createField('comment',
                        blocs[0][z][resHead.start():])
                else:
                    docObj.createField('br')

            fields = self._splitToFields(bodys[z])
            for f in fields:
                if f.name != False and f.value!=False and f.br!=False:
                    # Обработка условий для samba
                    if f.name[0] == "!" or f.name[0] == "-" or\
                        f.name[0] == "+":
                        qns = self.removeSymbolTerm(f.br)
                        xmlField = docObj.createField("var",
                                                  [qns],
                                                  f.name[1:], [f.value])
                        if f.name[0] == "!":
                            # Удаляемое в дальнейшем поле
                            docObj.setActionField(xmlField, "drop")
                        elif f.name[0] == "+":
                            # Добавляем уникальное поле
                            xmlField.setAttribute("type", "seplist")
                            docObj.setActionField(xmlField, "join")
                    else:
                        docObj.createField("var",[f.br.replace("\n","")],
                                           f.name, [f.value])
                    docObj.createField('br')
                elif f.comment != False:
                    docObj.createField('comment', [f.comment])
                elif f.br != False:
                    docObj.createField('br', [f.br.replace("\n","")])
            if h.strip():
                area = docObj.createArea()
                if areaAction:
                    docObj.setActionArea(area, areaAction)
                rootNode.appendChild(area)
            else:
                fieldsNodes = docObj.tmpFields.getFields()
                for fieldNode in fieldsNodes:
                    rootNode.appendChild(fieldNode)
                docObj.clearTmpFields()
            z += 1
        #print docObj.doc.toprettyxml()
        return docObj

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

    """
    _comment = "#"
    configName = "dovecot"
    configVersion = "0.1"
    __openArea = "{"
    __closeArea = "[ \t]*\}[ \t]*"
    sepFields = "\n"
    reOpen = re.compile(__openArea)
    reClose = re.compile(__closeArea)
    reCloseArea = re.compile(__closeArea + "\s*\Z")
    reComment = re.compile("[ \t]*%s" %(_comment))
    reSepFields = re.compile(sepFields)
    # разделитель названия и значения переменной
    reSeparator = re.compile("\s*=\s*")

    def __init__(self, text):
        bind.__init__(self,text)

    def postXML(self, xmlArea=False):
        """Последующая постобработка XML"""
        # Добавляем перевод строки если его нет в конец области
        if not xmlArea:
            xmlArea = self.docObj.body
        xmlFields = xpath.Evaluate("child::field", xmlArea)
        if xmlFields and not (\
            self.docObj.getTypeField(xmlFields[-1]) == "br" or\
                self.docObj.getTypeField(xmlFields[-1]) == "comment"):
            xmlArea.appendChild(self.docObj.createField("br",
                                                        [],"",[],
                                                        False,False))
        xmlAreas = xpath.Evaluate("child::area", xmlArea)
        for area in xmlAreas:
            self.postXML(area)

    def join(self, dovecotObj):
        """Объединяем конфигурации"""
        if isinstance(dovecotObj, dovecot):
            #print self.docObj.doc.toprettyxml()
            self.docObj.joinDoc(dovecotObj.doc)
            # Для добавления перевода строки перед закрывающим тегом
            # конфигурационного файла
            self.postXML()


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

    """
    _comment = "#"
    configName = "procmail"
    configVersion = "0.1"
    sepFields = "\n"
    reComment = re.compile("[ \t]*%s" %(_comment))
    reSepFields = re.compile(sepFields)
    # разделитель названия и значения переменной
    reSeparator = re.compile("=")
    def __init__(self, text):
        self.text = text
        self.docObj = self.textToXML()
        self.doc = self.docObj.doc

    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) == 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 textToXML(self):
        docObj = xmlDoc()
        docObj.createDoc(self.configName, self.configVersion)
        if self.text:
            nodeBody = docObj.getNodeBody()
            fields = self.splitToFields(self.text)
            for field in fields:
                if field.name != False:
                    fieldXML = self.createFieldTerm(field.name,
                                                    field.value,
                                                field.br, docObj)
                    nodeBody.appendChild(fieldXML)
                    if field.br[-1] == "\n":
                        fieldXMLBr = docObj.createField("br",[],
                                                        "",[],
                                                    False, False)
                        nodeBody.appendChild(fieldXMLBr)
                elif field.comment != False:
                    fieldXML = docObj.createField("comment",
                                                    [field.comment],
                                                    "", [],
                                                    False, False)
                    nodeBody.appendChild(fieldXML)
                elif field.br != False:
                    brText = field.br.replace("\n","")
                    if brText:
                        fieldXML = docObj.createField('br',
                                                        [brText],
                                                        "", [],
                                                        False, False)
                    else:
                        fieldXML = docObj.createField('br',
                                                        [],
                                                        "", [],
                                                        False, False)
                    nodeBody.appendChild(fieldXML)
        return docObj

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

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

    """
    _comment = "#"
    configName = "kde"
    configVersion = "0.1"
    reHeader = re.compile("^[\t ]*\[[^\[\]]+\].*\n?",re.M)
    reBody = re.compile(".+",re.M|re.S)
    reComment = re.compile("^\s*%s.*"%(_comment))
    reSeparator = re.compile("=")
    sepFields = "\n"
    reSepFields = re.compile(sepFields)

    def __init__(self,text):
        samba.__init__(self,text)
    
    
    def _textToXML(self):
        """Преобразует текст в XML"""
        blTmp = self.blocTextObj.findBloc(self.text,self.reHeader,self.reBody)
        blocs = self.getFullAreas(blTmp)
        headers = []
        startHeaders = []
        finHeaders = []
        docObj = xmlDoc()
        docObj.createDoc(self.configName, self.configVersion)
        rootNode = docObj.getNodeBody()
        # Если пустой текст то создаем пустой документ
        if not blocs:
            return docObj

        for h in blocs[0]:
            reH = re.compile("]\s*$")
            #listfinH = h.split("]")
            listfinH = reH.split(h)
            finH = listfinH[0]
            if "[" in finH:
                startHeaders.append(finH + "]")
            else:
                startHeaders.append(finH)
            if len(listfinH) == 2:
                finHeaders.append(listfinH[1])
            else:
                finHeaders.append("")
            head=finH.replace("][",".").replace("[","").replace("]","").strip()
            headers.append(head)
        bodys = blocs[1]

        z = 0
        for h in headers:
            if not bodys[z]:
                z += 1
                continue
            areaAction = False
            if h:
                if h[0] == "!":
                    docObj.createCaption(h[1:], [startHeaders[z],""])
                    areaAction = "drop"
                elif h[0] == "-":
                    docObj.createCaption(h[1:], [startHeaders[z],""])
                    areaAction = "replace"
                else:
                    docObj.createCaption(h, [startHeaders[z],""])
            else:
                docObj.createCaption(h, [startHeaders[z],""])

            if "\n" in blocs[0][z]:
                if self.reComment.search(finHeaders[z]):
                        docObj.createField('comment', [finHeaders[z]])
                elif not finHeaders[z].strip() and\
                     finHeaders[z].replace("\n",""):
                        docObj.createField('br',
                                            [finHeaders[z].replace("\n","")])
                else:
                    docObj.createField('br')
            fields = self._splitToFields(bodys[z])
            for f in fields:
                if f.name != False and f.value!=False and f.br!=False:
                    # Обработка условий для samba
                    if f.name[0] == "!" or f.name[0] == "-" or\
                        f.name[0] == "+":
                        qns = self.removeSymbolTerm(f.br)
                        xmlField = docObj.createField("var",
                                                  [qns],
                                                  f.name[1:], [f.value])
                        if f.name[0] == "!":
                            # Удаляемое в дальнейшем поле
                            docObj.setActionField(xmlField, "drop")
                    else:
                        docObj.createField("var",[f.br.replace("\n","")],
                                           f.name, [f.value])
                    docObj.createField('br')
                elif f.comment != False:
                    docObj.createField('comment', [f.comment])
                elif f.br != False:
                    docObj.createField('br', [f.br.replace("\n","")])
            if h.strip():
                area = docObj.createArea()
                if areaAction:
                    docObj.setActionArea(area, areaAction)
                rootNode.appendChild(area)
            else:
                fieldsNodes = docObj.tmpFields.getFields()
                for fieldNode in fieldsNodes:
                    rootNode.appendChild(fieldNode)
                docObj.clearTmpFields()
            z += 1
        #print docObj.doc.toprettyxml()
        return docObj

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


class xmlDocPlasma:
    """Класс для замены метода joinArea в xmlDoc для plasma"""
        # заменяемый метод для xmlDoc
    def joinArea(self, baseNode, xmlNewArea):
        """Объединяет область c областью Body (xmlNewArea c baseNode)"""
        def appendArea(baseNode, xmlNewArea):
            fieldsRemove = xpath.Evaluate(\
            "descendant::field[child::action='drop']", xmlNewArea)
            for rmNode in fieldsRemove:
                parentNode = rmNode.parentNode
                parentNode.removeChild(rmNode)
            captionAreasRemove = xpath.Evaluate(\
                    "descendant::area/child::caption[child::action='drop']",
                    xmlNewArea)
            for rmNodeCapt in captionAreasRemove:
                rmNode = rmNodeCapt.parentNode
                parentNode = rmNode.parentNode
                parentNode.removeChild(rmNode)
            self.setActionArea(xmlNewArea, "append")
            # Добавляем разделитель областей во вложенные области
            areaNodes = xpath.Evaluate('descendant::area',xmlNewArea)
            for areaNode in areaNodes:
                self.setActionArea(areaNode,"append")
                parentNode = areaNode.parentNode
                parentNode.insertBefore(self.sepAreas.cloneNode(True),
                                        areaNode)
            baseNode.appendChild(xmlNewArea)
            # Добавляем разделитель областей
            baseNode.insertBefore(self.sepAreas.cloneNode(True), xmlNewArea)

        nodesNames = xpath.Evaluate('child::area/caption/name',baseNode)
        nodesNewArea = xpath.Evaluate('child::caption/name',xmlNewArea)
        if not nodesNames:
            # Добавляем область
            if nodesNewArea:
                newAreaAction = self.getActionArea(xmlNewArea)
                if not (newAreaAction == "drop"):
                    appendArea(baseNode, xmlNewArea)
            return True
        if not nodesNames or not nodesNewArea:
            return False
        nameArea = ""
        if nodesNewArea[0].firstChild:
            nameArea = nodesNewArea[0].firstChild.nodeValue.strip()
        flagFindArea = False
        baseNodes = []
        for oName in nodesNames:
            newAreaAction = self.getActionArea(xmlNewArea)
            oArea = oName.parentNode.parentNode
            oNameTxt = ""
            if oName.firstChild:
                oNameTxt = oName.firstChild.nodeValue
            if nameArea == oNameTxt:
                flagFindArea = True
                # При использовании удаления
                if newAreaAction == "drop":
                    prevNode = oName.parentNode.parentNode.previousSibling
                    removePrevNodes = []
                    while (prevNode) and self.getTypeField(prevNode) == "br":
                        removePrevNodes.append(prevNode)
                        prevNode = prevNode.previousSibling
                    for removeNode in removePrevNodes:
                        baseNode.removeChild(removeNode)
                    baseNode.removeChild(oName.parentNode.parentNode)
                    continue
                elif newAreaAction == "replace":
                    oldAreaNode = oName.parentNode.parentNode
                    newAreaCaption = xpath.Evaluate('child::caption',
                                                    xmlNewArea)[0]
                    oldAreaCaption = xpath.Evaluate('child::caption',
                                                    oldAreaNode)[0]
                    if newAreaCaption and oldAreaCaption:
                        xmlNewArea.replaceChild(oldAreaCaption,newAreaCaption)
                        self.setActionArea(xmlNewArea,"replace")
                    baseNode.replaceChild(xmlNewArea,
                                          oldAreaNode)
                    continue
                baseNodes.append(oName.parentNode.parentNode)

                # Заменяем QUOTE
                oldAreaNode = oName.parentNode.parentNode
                oldAreaQuote = xpath.Evaluate('child::caption/quote',
                                                oldAreaNode)[0]
                if oldAreaQuote and\
                    not oldAreaQuote.firstChild:
                    newAreaQuote = xpath.Evaluate('child::caption/quote',
                                                xmlNewArea)[0]
                    oldAreaCaption = xpath.Evaluate('child::caption',
                                                oldAreaNode)[0]
                    if newAreaQuote and oldAreaCaption:
                        oldAreaCaption.replaceChild(newAreaQuote, oldAreaQuote)

                newFields = xpath.Evaluate('child::field',xmlNewArea)

                joinNewFields = xpath.Evaluate(\
                    "child::field[child::action='join']"
                                       ,xmlNewArea)
                self.addNewFielsOldArea(newFields, joinNewFields, oArea)


        if not flagFindArea:
            # Добавляем область
            if not (newAreaAction == "drop"):
                appendArea(baseNode, xmlNewArea)
        else:
            tmpXmlNewAreas = xpath.Evaluate('child::area',xmlNewArea)
            for na in tmpXmlNewAreas:
                for bn in baseNodes:
                    self.joinArea(bn, na)
        return True

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

    """
    _comment = "#"
    configName = "plasma"
    configVersion = "0.1"
    reHeader = re.compile("^[\t ]*\[[^\[\]]+\].*\n?",re.M)
    reBody = re.compile(".+",re.M|re.S)
    reComment = re.compile("^\s*%s.*"%(_comment))
    reSeparator = re.compile("=")
    sepFields = "\n"
    reSepFields = re.compile(sepFields)

    def __init__(self,text):
        samba.__init__(self,text)

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

        возвращает список объектов областей (переменная areas)
        """
        class area:
            def __init__(self):
                self.header = False
                self.start = False
                self.fields = []
                self.end = False


        def findPathArea(listPath, areaF):
            """Ищет путь в области

            areaF - объект area
            listPath - cписок названий областей
            """
            ret = False
            if not listPath:
                return ret
            flagList = False
            if type(areaF) == types.ListType:
                fields = areaF
                flagList = True
            else:
                fields = areaF.fields
                if areaF.header == listPath[0]:
                    ret = areaF
                else:
                    return ret
            for i in fields:
                if str(i.__class__.__name__) == "area":
                    add = False
                    if not flagList:
                        add = listPath.pop(0)
                    if not listPath:
                        break
                    ret = False
                    if i.header == listPath[0]:
                        ret = findPathArea(listPath, i)
                        break
                    else:
                        if add:
                            listPath.insert(0,add)
            if ret == areaF and len(listPath)>1:
                ret = False
            return ret


        blTmp = self.blocTextObj.findBloc(self.text,self.reHeader,self.reBody)
        blocs = self.getFullAreas(blTmp)
        reH = re.compile("\[([^\[\]]+)\]")
        # Список имен блоков
        namesBlockList = []
        # Временные поля
        fieldsTmp = []
        # Добавляем заголовки
        z = 0
        for h in blocs[0]:
            if not h:
                if blocs[1][z] == "":
                    fieldsTmp.append("")
                    #fieldsTmp.append("\n")
                else:
                    fieldsTmp.append(blocs[1][z])
                #print '"' + blocs[1][z] + '"'
                z += 1
                continue
            #print '"' + blocs[1][z] + '"'
            z += 1
            slpNamesBlock = reH.split(h)
            # Отступ слева для заголовка
            indentionLeft = slpNamesBlock[0]
            namesBlock = filter(lambda x: x.strip(), slpNamesBlock)
            #namesBlock = map(lambda x: self.removeSymbolTerm(x), namesBlock)
            findArea = findPathArea(copy.copy(namesBlock), areas)
            namesBlockList.append(namesBlock)
            if findArea:
                if len(namesBlock) > 1:
                    namesBlockView = map(lambda x: self.removeSymbolTerm(x),
                                        namesBlock)
                else:
                    namesBlockView = namesBlock
                findArea.start = indentionLeft + "[" + \
                 "][".join(namesBlockView) + "]"
            else:
                i = 0
                lenNamesBlock = len(namesBlock)
                namesBlockTmp = []
                for nameB in namesBlock:
                    namesBlockTmp.append(nameB)
                    findArea = findPathArea(copy.copy(namesBlockTmp), areas)
                    i += 1
                    if not findArea:
                        areaNew = area()
                        areaNew.header = nameB
                        if lenNamesBlock == i:
                            if len(namesBlock) > 1:
                                namesBlockView = map(\
                                            lambda x: self.removeSymbolTerm(x),
                                            namesBlock)
                            else:
                                namesBlockView = namesBlock
                            areaNew.start = indentionLeft + "[" + \
                                            "][".join(namesBlockView) + "]"
                        else:
                            areaNew.start = ""
                        areaNew.end = ""
                        if i == 1:
                            if lenNamesBlock == i:
                                areas += fieldsTmp
                            areas.append(areaNew)
                            findAreaPrev = areas[-1]
                        else:
                            if lenNamesBlock == i:
                                findAreaPrev.fields += fieldsTmp
                            findAreaPrev.fields.append(areaNew)
                            findAreaPrev = findAreaPrev.fields[-1]
                    else:
                        findAreaPrev = findArea
                fieldsTmp = []
        i = 0
        delt = 0
        # Добавляем тела
        for body in  blocs[1]:
            #print "#" + body + "#"
            #print
            if not blocs[0][i]:
                i += 1
                delt +=1
                continue
            ## В случае последнего комментария не добавляем перевод строки
            #if self.reComment.search(body.splitlines()[-1]):
            body = "\n" + body

            namesBlock = namesBlockList[i-delt]
            findArea = findPathArea(copy.copy(namesBlock), areas)
            if findArea:
                #if findArea.fields:
                    #if type(findArea.fields[0]) == types.StringType:
                        #findArea.fields.pop(0)
                findArea.fields.insert(0, body)
            i += 1
        
        #eee = 1
        #def prAreas(ar, eee):
            #for a in ar:
                #if type(a) == types.StringType:
                    #print 'field', a
                #else:
                    #print "--------------------"
                    #print "HEADER =", a.header
                    #print "START =", a.start
                    #print "FIELDS =", a.fields
                    #print "LEVEL", eee
                #if type(a) != types.StringType:
                    #if a.fields:
                        #eee += 1
                        #prAreas(a.fields, eee)
            
        #prAreas(areas, eee)
        return areas

    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:
                    areaXML = self.createCaptionTerm(i.header, i.start,
                                                     i.end.replace("\n",""),
                                                     docObj)
                for f in i.fields:
                    if str(f.__class__.__name__) == "area":
                        if f.header:
                            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 != 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 != False:
                                fieldXML = docObj.createField("comment",
                                                              [field.comment],
                                                              "", [],
                                                              False, False)
                                areaXML.appendChild(fieldXML)
                            elif field.br != False:
                                brText = field.br.replace("\n","")
                                if brText:
                                    fieldXML = docObj.createField('br',
                                                                  [brText],
                                                                  "", [],
                                                                  False, False)
                                else:
                                    fieldXML = docObj.createField('br',
                                                                  [],
                                                                  "", [],
                                                                  False, False)
                                if areaXML:
                                    areaXML.appendChild(fieldXML)

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

            else:
                if not i:
                    continue
                fields = self.splitToFields(i)
                for field in fields:
                    if field.name != 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 != False:
                        fieldXML = docObj.createField("comment",
                                                      [field.comment],
                                                      "", [],
                                                      False, False)
                        rootNode.appendChild(fieldXML)
                    elif field.br != 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 createTxtConfig(self, strHeader, dictVar):
        """Cоздает область с заголовком

        создает текст конфигурационного файла в формате samba из
        заголовка (строка) и словаря переменных
        """
        if not strHeader:
            return ""
        if type(strHeader) in (tuple, list):
            outTxt = "".join(map(lambda x: "["+x+"]",strHeader))
            if not outTxt:
                return ""
            outTxt += "\n"
        else:
            outTxt = "[" + strHeader + "]\n"
        for key in dictVar.keys():
            outTxt += "%s=%s\n" %(key,dictVar[key])
        return outTxt

    def _textToXML(self):
        """Преобразуем текст в XML"""
        areas = []
        if self.text.strip():
            self.splitToAllArea(self.text, areas)
        #docObj = xmlDoc()
        # Создаем новый класс xmlDoc с измененным методом joinArea
        newClass = type("newXmlDocPlalma",(xmlDocPlasma,xmlDoc,object),{})
        # Создаем экземпляр нового класса
        docObj = newClass()
        # Создание объекта документ c пустым разделителем между полями
        docObj.createDoc(self.configName, self.configVersion)
        if not areas:
            return docObj
        self.createXML(areas, docObj.getNodeBody(), docObj)
        return docObj


    def postXML(self):
        """Последующая постобработка XML"""
        # Для добавления перевода строки между областями если его нет
        #print self.docObj.body.toprettyxml()
        def getQuotesArea(xmlArea):
            quotes = []
            xmlQuotes = xpath.Evaluate('child::caption/quote',xmlArea)
            for node in xmlQuotes:
                if node.firstChild:
                    quotes.append(node.firstChild.nodeValue)
            if len(quotes) == 0:
                quotes.append("")
                quotes.append("")
            elif len(quotes) == 1:
                quotes.append("")
            return quotes

        xmlAreas = xpath.Evaluate("descendant::area", self.docObj.body)
        #print "-------------------------------------------------------"
        #print xmlAreas
        #if xmlAreas:
            #prXmlArea = xmlAreas[0]
        for xmlArea in xmlAreas:
            # Перед пустой областью и после нее удаляем переводы строк
            if getQuotesArea(xmlArea) == ["",""]:
                #areaTXT = xpath.Evaluate("child::caption/name", xmlArea)[0]
                #print "CL_AREA", areaTXT.firstChild
                if xmlArea.previousSibling and\
                    self.docObj.getTypeField(xmlArea.previousSibling) == "br":
                    parentNode = xmlArea.previousSibling.parentNode
                    if xmlArea.previousSibling.previousSibling and\
    self.docObj.getTypeField(xmlArea.previousSibling.previousSibling) == "br":
                        parentNode.removeChild(\
                                    xmlArea.previousSibling.previousSibling)
                    parentNode.removeChild(xmlArea.previousSibling)
                if xmlArea.nextSibling and\
                    self.docObj.getTypeField(xmlArea.nextSibling) == "br":
                    parentNode = xmlArea.nextSibling.parentNode
                    if xmlArea.nextSibling.nextSibling and\
             self.docObj.getTypeField(xmlArea.nextSibling.nextSibling) == "br":
                        parentNode.removeChild(xmlArea.nextSibling.nextSibling)
                    parentNode.removeChild(xmlArea.nextSibling)
                continue

            # Собираем поля в кучку
            xmlChildAreas = xpath.Evaluate("child::area", xmlArea)
            if xmlChildAreas:
                childNodes = self.docObj.getFieldsArea(xmlArea)
                firstChildArea = xmlChildAreas[0]
                if firstChildArea.previousSibling and\
                self.docObj.getTypeField(firstChildArea.previousSibling)=="br":
                    if firstChildArea.previousSibling.previousSibling:
                        if self.docObj.getTypeField(\
                        firstChildArea.previousSibling.previousSibling)=="br":
                            firstChildArea = firstChildArea.previousSibling
                flagFoundArea = False
                it = 0
                lenChild = len(childNodes)
                for node in childNodes:
                    it += 1
                    if node.tagName == "area":
                        flagFoundArea = True
                        continue
                    if flagFoundArea and node.tagName == "field":
                        if self.docObj.getTypeField(node) == "var":
                            xmlArea.insertBefore(node, firstChildArea)
                            if it < lenChild:
                                if self.docObj.getTypeField(childNodes[it])==\
                                                                           "br":
                                    xmlArea.insertBefore(childNodes[it],
                                                        firstChildArea)
                    # Добавление перевода строк в если его нет между полями
                    if self.docObj.getTypeField(node) == "var" and\
                        node.previousSibling and\
                        not (self.docObj.getTypeField(node.previousSibling) in\
                             ("br","comment")):
                        xmlArea.insertBefore(self.docObj.createField("br",
                                                            [],"",[],
                                                            False,False),
                                                            node)

            # Добавляем BR если его нет первым полем
            xmlFields = xpath.Evaluate("child::field", xmlArea) 
            if not (xmlFields and\
                (self.docObj.getTypeField(xmlFields[0]) == "br" or\
                    self.docObj.getTypeField(xmlFields[0]) == "comment")):
                if xmlFields:
                    xmlArea.insertBefore(self.docObj.createField("br",
                                                            [],"",[],
                                                            False,False),
                                                            xmlFields[0])
            # Если последним полем BR, удаляем его
            if xmlFields and self.docObj.getTypeField(xmlFields[-1]) == "br":
                    #print "DEL_BR", xmlFields[-1].nextSibling
                       #and\
                    if not xmlFields[-1].nextSibling:
                        xmlArea.removeChild(xmlFields[-1])

            # Если предыдущим полем  не (BR или комментарий) - добавляем BR
            if xmlArea.previousSibling and\
            not (self.docObj.getTypeField(xmlArea.previousSibling) == "br" or\
            self.docObj.getTypeField(xmlArea.previousSibling) == "comment"):
                parentNode = xmlArea.parentNode
                parentNode.insertBefore(self.docObj.createField("br",
                                                    [],"",[],
                                                    False,False),
                                                    xmlArea)
            # Если есть предыдущее поле, и поле предыдущеее предыдущему
            # не равно BR или комментарий то добавляем BR
            if xmlArea.previousSibling:
                prPrSibling = xmlArea.previousSibling.previousSibling
                if prPrSibling and\
                not (self.docObj.getTypeField(prPrSibling) == "br" or\
                    self.docObj.getTypeField(prPrSibling) == "comment"):
                    parentNode = xmlArea.parentNode
                    parentNode.insertBefore(self.docObj.createField("br",
                                                        [],"",[],
                                                        False,False),
                                                        xmlArea)
            # Если после есть BR а за ним ничего нет, удаляем BR
            if xmlArea.nextSibling and\
                self.docObj.getTypeField(xmlArea.nextSibling) == "br":
                    if not xmlArea.nextSibling.nextSibling:
                        parentNode = xmlArea.nextSibling.parentNode
                        parentNode.removeChild(xmlArea.nextSibling)


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

class xml_xfce(_error):
    """Класс для объединения xfce-xml файлов"""
    # root нода
    rootNode = False
    # body нода
    bodyNode = False
    # Документ
    doc = False
    # Текст профиля
    text = ""
    # Комментарий
    _comment = ("<!--","-->")

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

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

    def setNameBodyNode(self, name):
        """Устанавливает название для корневой ноды документа"""
        if not self.bodyNode:
            return False
        self.bodyNode.setAttribute("name", name)
        return True

    def textToXML(self):
        """Создание из текста XML документа
        Храним xml в своем формате
        """
        if not self.text.strip():
            self.text = '''<?xml version="1.0" encoding="UTF-8"?>
<channel version="1.0">
</channel>'''
        try:
            self.doc = xml.dom.minidom.parseString(self.text)
        except:
            self.setError(_("Can not text profile is XML"))
            return False
        self.rootNode = self.doc.documentElement
        self.bodyNode = self.rootNode
        return self.doc

    def join(self, xml_xfceObj):
        """Объединяем конфигурации"""
        if isinstance(xml_xfceObj, xml_xfce):
            try:
                self.joinDoc(xml_xfceObj.doc)
            except:
                self.setError(_("Can not join profile"))
            return False
        return True

    def _removeDropNodesAndAttrAction(self, xmlNode):
        """Удаляет ноды с аттрибутом action='drop'

        Также удаляет аттрибут action у всех нод
        """
        flagError = False
        childNodes = xmlNode.childNodes
        if xmlNode.nodeType ==xmlNode.ELEMENT_NODE:
            if xmlNode.hasAttribute("action"):
                nAction = xmlNode.getAttribute("action")
                if not nAction in ("join","replace","drop"):
                    textError = _('''In the text, XML profile, look \
for a reserved attribute 'action' with the incorrect value.\n\
Valid values attribute 'action': \
(action="join", action="replace", action="drop")''')
                    self.setError(textError)
                    return False
                xmlNode.removeAttribute("action")
                if nAction == "drop":
                    parentNode = xmlNode.parentNode
                    if parentNode:
                        parentNode.removeChild(xmlNode)
            if childNodes:
                for node in childNodes:
                    if not self._removeDropNodesAndAttrAction(node):
                        flagError = True
                        break
        if flagError:
            return False
        return True

    def postXML(self):
        """Последующая постобработка XML"""
        # Удаляем теги action и удаляемые ноды
        self._removeDropNodesAndAttrAction(self.bodyNode)

    def _join(self, xmlNewNode, xmlOldNode, flagRootNode=True):
        """Объединение корневой ноды профиля и корневой ноды файла"""
        xmlNode = xmlNewNode
        childNodes = xmlNode.childNodes
        nextOldNode = xmlOldNode
        flagError = False
        if xmlNode.nodeType ==xmlNode.ELEMENT_NODE:
            n = xmlNode
            path = u''
            nName = u''
            nType = u''
            nValue = u''
            nAction = u''
            attrName = ''
            attrType = ''
            path = n.tagName
            if n.hasAttribute("name"):
                nName = n.getAttribute("name")
                attrName = u"attribute::name='%s'"%nName
            if n.hasAttribute("type"):
                nType = n.getAttribute("type")
                attrType = u"attribute::type='%s'"%nType
            if n.hasAttribute("value"):
                nValue = n.getAttribute("value")
            if n.hasAttribute("action"):
                nAction = n.getAttribute("action")
                if not nAction in ("join","replace","drop"):
                    textError = _('''In the text, XML profile, look \
for a reserved attribute 'action' with the incorrect value.\n\
Valid values attribute 'action': \
(action="join", action="replace", action="drop")''')
                    self.setError(textError)
                    return False
            if xmlOldNode.parentNode:
                strAttr = [attrName, attrType]
                findAttr = filter(lambda x: x, strAttr)
                findAttrStr = ''
                if findAttr:
                    strAttr = u' and '.join(findAttr)
                    findAttrStr = "[%s]"%strAttr
                findPath = u"child::%s%s"%(path,findAttrStr)
                # Рабочая нода
                if flagRootNode:
                    workNode = xmlOldNode.parentNode
                else:
                    workNode = xmlOldNode
                oldNodes = xpath.Evaluate(findPath, workNode)
                #print findPath
                #print workNode
                #print "----------------------------"
                # Новая нода список
                flagArray = False
                if nType == "array":
                    flagArray = True
                flagDrop = False
                flagJoin = True
                flagReplace = False
                if nAction == "replace":
                    flagJoin = False
                    flagReplace = True
                elif nAction == "drop":
                    flagJoin = False
                    flagDrop = True
                    if flagRootNode:
                        textError = _('Incorrect action="drop" in root node')
                        self.setError(textError)
                        return False
                if oldNodes:
                    if len(oldNodes)>1:
                        textError = _("The uncertainty in this profile are \
the same nodes at one level")
                        self.setError(textError)
                        return False
                    nextOldNode = oldNodes[0]
                    # Замещаем ноду в случае массива
                    if flagArray and not flagDrop:
                        replaceXmlNode = xmlNode.cloneNode(True)
                        if nAction:
                            replaceXmlNode.removeAttribute("action")
                        workNode.replaceChild(replaceXmlNode,
                                                nextOldNode)
                        flagJoin = False
                        flagReplace = False
                        childNodes = False
                    # Объединение нод
                    if flagJoin:
                        if nextOldNode.hasAttribute("value"):
                            oValue = nextOldNode.getAttribute("value")
                            if nValue != oValue:
                                nextOldNode.setAttribute("value",nValue)
                    # Замещение ноды
                    elif flagReplace:
                        replaceXmlNode = xmlNode.cloneNode(True)
                        if not\
                            self._removeDropNodesAndAttrAction(replaceXmlNode):
                                return False
                        workNode.replaceChild(replaceXmlNode,
                                                nextOldNode)
                        childNodes = False
                    # Удаление ноды
                    elif flagDrop:
                        workNode.removeChild(nextOldNode)
                        childNodes = False
                else:
                    # Добавление ноды
                    childNodes = False
                    if not flagDrop:
                        appendXmlNode = xmlNode.cloneNode(True)
                        if not\
                            self._removeDropNodesAndAttrAction(appendXmlNode):
                                return False
                        workNode.appendChild(appendXmlNode)
            if childNodes:
                for node in childNodes:
                    if not self._join(node, nextOldNode, False):
                        flagError = True
                        break
        if flagError:
            return False
        return True

    def joinDoc(self, doc):
        """Объединение документа профиля и документа файла"""
        if not self.doc:
            self.setError(_("Can not text file is XML"))
            return False
        if not doc:
            self.setError(_("Can not text profile is XML"))
            return False
        # Импортируем корневую ноду нового документа в текущий документ
        #newImportBodyNode = self.doc.importNode(doc.documentElement, True)
        # Объединение корневой ноды профиля и корневой ноды файла
        if not self._join(doc.documentElement, self.bodyNode):
            return False
        return True

    def getConfig(self):
        """Получение текстового файла из XML документа"""
        data = self.doc.toprettyxml(encoding='UTF-8').split("\n")
        data = filter(lambda x: x.strip(), data)
        return "\n".join(data).replace("\t","  ").decode("UTF-8")

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

    """
    configName = "squid"
    configVersion = "0.1"
    # разделитель названия и значения переменной
    reSeparator = re.compile(" ")

    def __init__(self, text):
        procmail.__init__(self, text)
        # Создаем поля-массивы
        self.docObj.postParserList()
        # Создаем поля разделенные массивы
        self.docObj.postParserListSeplist(self.docObj.body)

    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)
            flagVariable = True 
            if not textLine.strip():
                field.br = textLine
                fields.append(field)
                field = fieldData()
                flagVariable = False
            elif findComment:
                if textLine[:findComment.start()].strip():
                    field.comment = textLine[findComment.start():]
                    textLine = textLine[:findComment.start()]
                else:
                    field.comment = textLine
                    flagVariable = False
                fields.append(field)
                field = fieldData()
            if flagVariable:
                pars = textLine.strip()
                nameValue = self.reSeparator.split(pars)
                if len(nameValue) > 2:
                    valueList = nameValue[1:]
                    nameValue =[nameValue[0]," ".join(valueList)]
                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 join(self, squidObj):
        """Объединяем конфигурации"""
        if isinstance(squidObj, squid):
            #print squidObj.getConfig()
            self.docObj.joinDoc(squidObj.doc)

class xml_xfcepanel(xml_xfce):
    """Класс для объединения xfce-panel файлов"""
    def __init__(self, text):
        xml_xfce.__init__(self, text)
        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)
        except:
            self.setError(_("Can not text profile is XML"))
            return False
        self.rootNode = self.doc.documentElement
        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 = xmlNode.childNodes
        nextOldNode = xmlOldNode
        flagError = False
        if xmlNode.nodeType ==xmlNode.ELEMENT_NODE:
            n = xmlNode
            path = u''
            nName = u''
            flagArray = False
            nValue = u''
            nAction = u''
            attrName = ''
            attrType = ''
            path = n.tagName
            if path == "items":
                flagArray = True
            if not flagArray:
                if n.hasAttribute("name"):
                    nName = n.getAttribute("name")
                    attrName = u"attribute::name='%s'"%nName
                if n.hasAttribute("value"):
                    nValue = n.getAttribute("value")
            if n.hasAttribute("action"):
                nAction = n.getAttribute("action")
                if not nAction in ("join","replace","drop"):
                    textError = _('''In the text, XML profile, look \
for a reserved attribute 'action' with the incorrect value.\n\
Valid values attribute 'action': \
(action="join", action="replace", action="drop")''')
                    self.setError(textError)
                    return False
            if xmlOldNode.parentNode:
                findAttrStr = ""
                if attrName:
                    findAttrStr = "[%s]"%attrName
                findPath = u"child::%s%s"%(path,findAttrStr)
                # Рабочая нода
                if flagRootNode:
                    workNode = xmlOldNode.parentNode
                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 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 = _("The uncertainty in this profile are \
the same nodes at one 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 = xmlNode.cloneNode(True)
                        if nAction:
                            replaceXmlNode.removeAttribute("action")
                        workNode.replaceChild(replaceXmlNode,
                                                nextOldNode)
                        flagJoin = False
                        flagReplace = False
                        childNodes = False
                    # Объединение нод
                    if flagJoin:
                        if nextOldNode.hasAttribute("value"):
                            oValue = nextOldNode.getAttribute("value")
                            if nValue != oValue:
                                nextOldNode.setAttribute("value",nValue)
                    # Замещение ноды
                    elif flagReplace:
                        replaceXmlNode = xmlNode.cloneNode(True)
                        if not\
                            self._removeDropNodesAndAttrAction(replaceXmlNode):
                                return False
                        workNode.replaceChild(replaceXmlNode,
                                                nextOldNode)
                        childNodes = False
                    # Удаление ноды
                    elif flagDrop:
                        workNode.removeChild(nextOldNode)
                        childNodes = False
                else:
                    flagAppend = True
                    flagDrop = False
                if flagAppend and not flagDrop:
                    # Добавление ноды
                    childNodes = False
                    if not flagDrop:
                        appendXmlNode = xmlNode.cloneNode(True)
                        if not\
                            self._removeDropNodesAndAttrAction(appendXmlNode):
                                return False
                        workNode.appendChild(appendXmlNode)
            if childNodes:
                for node in childNodes:
                    levelNumber +=1
                    if not self._join(node, nextOldNode, False, levelNumber):
                        flagError = True
                        break
                    levelNumber -= 1
        if flagError:
            return False
        return True

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


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

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

    def __init__(self,text):
        bind.__init__(self,text)

    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 = textLine.replace(self.sepFields,"").strip()
                    field.value = ""
                    field.br = textLine
                    fields.append(field)
                    field = fieldData()

                if len(nameValue) > 2:
                    nameCheck = nameValue[0]
                    if nameValue[0][:1] in ["+","-","!"]:
                        nameCheck = nameValue[0][1:]
                    if nameCheck == "option" or nameCheck  == "hardware" or\
                        nameCheck == "set":
                        valueList = nameValue[2:]
                        nameValue =[nameValue[0]+nameValue[1],
                                    " ".join(valueList).replace(\
                                    self.sepFields,"")]
                    else:
                        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 join(self, dhcpObj):
        """Объединяем конфигурации"""
        if isinstance(dhcpObj, dhcp):
            self.docObj.joinDoc(dhcpObj.doc)


class xml_gconf(xml_xfce):
    """Класс для объединения gconf-xml файлов"""
    # root нода
    rootNode = False
    # body нода
    bodyNode = False
    # Документ
    doc = False
    # Текст профиля
    text = ""
    # Текущее время в секундах 
    currentTime = ""
    # Комментарий
    _comment = ("<!--","-->")
    # поддерживаемые аттрибуты тега entry. Пример <entry type="int"/>
    supportEntryTypes = ("int", "bool", "float", "string", "list", "pair")

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

    def getCurrentTime(self):
        """Получение текущего времени в секундах"""
        return str(int(time.time()))

    def textToXML(self):
        """Создание из текста XML документа
        Храним xml в своем формате
        """
        if not self.text.strip():
            self.text = '''<?xml version="1.0"?><gconf></gconf>'''
        try:
            self.doc = xml.dom.minidom.parseString(self.text)
        except:
            self.setError(_("Can not text profile is XML"))
            return False
        self.rootNode = self.doc.documentElement
        self.bodyNode = self.rootNode
        return self.doc

    def cmpListsNodesEntry(self, listXmlA, listXmlB):
        """Сравнение содержимого двух списков XML нод"""
        getTextsNodes = lambda y: map(lambda x:\
            x.toxml().replace(" ","").replace("\t","").replace("\n",""),
                    map(lambda x: x.hasAttribute("mtime") and\
                        x.removeAttribute("mtime") or x,
                        map(lambda x: x.cloneNode(True),
                            filter(lambda x: x.nodeType==x.ELEMENT_NODE, y))))
        if set(getTextsNodes(listXmlA))==set(getTextsNodes(listXmlB)):
            return True
        return False

    def _join(self, xmlNewNode, xmlOldNode, flagRootNode=True, levelNumber=0):
        """Объединение корневой ноды профиля и корневой ноды файла"""
        if levelNumber>1:
            return True
        xmlNode = xmlNewNode
        childNodes = xmlNode.childNodes
        nextOldNode = xmlOldNode
        flagError = False
        if xmlNode.nodeType == xmlNode.ELEMENT_NODE:
            n = xmlNode
            tagName = n.tagName
            nAction = u''
            nName = u''
            nType = u''
            nValue = u''
            nSchema = u''
            attrName = ''
            if flagRootNode:
                if not tagName == "gconf":
                    self.setError(_("The text is not a valid gconf-XML format \
(not found '<gconf>...</gconf>')"))
                    return False
                flagType = False
                flagValue = False
                flagSchema = False
            else:
                if not tagName == "entry":
                    self.setError(_("The text is not a valid gconf-XML format \
(found '<gconf><%s>..</%s></gconf>'")%(tagName,tagName))
                    return False
                if not n.hasAttribute("name"):
                    self.setError(_('Not found arrtibute "name" in tag entry'))
                    return False
                flagType = n.hasAttribute("type")
                flagValue = False
                flagSchema = n.hasAttribute("schema")
                if flagSchema:
                    nSchema = n.getAttribute("schema")
                if not flagType and not flagSchema:
                    self.setError(_('Not found arrtibute "type" in tag entry'))
                    return False
                nName = n.getAttribute("name")
                attrName = u"attribute::name='%s'"%nName
                if flagType:
                    flagValue = n.hasAttribute("value")
                    nType = n.getAttribute("type")
                    # Проверка правильности аттрибута type
                    if not nType in self.supportEntryTypes:
                        self.setError(\
                        _('Incorrect arrtibute "type" - <entry type="%s"/>')\
                          %nType)
                        return False
                    if flagValue:
                        nValue = n.getAttribute("value")
            if n.hasAttribute("action"):
                nAction = n.getAttribute("action")
                if not nAction in ("join","replace","drop"):
                    textError = _('''In the text, XML profile, look \
for a reserved attribute 'action' with the incorrect value.\n\
Valid values attribute 'action': \
(action="join", action="replace", action="drop")''')
                    self.setError(textError)
                    return False
            if xmlOldNode.parentNode:
                findAttrStr = ""
                if attrName:
                    findAttrStr = "[%s]"%attrName
                findPath = u"child::%s%s"%(tagName,findAttrStr)
                # Рабочая нода
                if flagRootNode:
                    workNode = xmlOldNode.parentNode
                else:
                    workNode = xmlOldNode
                oldNodes = xpath.Evaluate(findPath, workNode)
                # По умолчанию - объединение
                flagJoin = True
                flagReplace = False
                flagDrop = False
                # Замещаем ноду
                if nType=="string" or nAction=="replace":
                    flagJoin = False
                    flagReplace = True
                # Замещаем ноду в случае массива
                elif nType == "list" or nType == "pair":
                    flagJoin = False
                    flagReplace = True
                # Удаляем ноду
                elif nAction == "drop":
                    flagJoin = False
                    flagDrop = True
                    if flagRootNode:
                        textError = _('Incorrect action="drop" in root node')
                        self.setError(textError)
                        return False
                if oldNodes:
                    if len(oldNodes)>1:
                        textError = _("The uncertainty in this profile are \
the same nodes at one level")
                        self.setError(textError)
                        return False
                    nextOldNode = oldNodes[0]
                    # Объединение нод
                    if flagJoin:
                        if flagType and flagValue:
                            flagChange = False
                            foundValue = nextOldNode.hasAttribute("value")
                            if foundValue:
                                oValue = nextOldNode.getAttribute("value")
                                if nValue != oValue:
                                    flagChange = True
                            else:
                                flagChange = True
                            if flagChange:
                                nextOldNode.setAttribute("mtime",
                                                         self.currentTime)
                                nextOldNode.setAttribute("value",nValue)
                        elif flagSchema:
                            flagChange = False
                            foundValue = nextOldNode.hasAttribute("schema")
                            if foundValue:
                                oSchema = nextOldNode.getAttribute("schema")
                                if nSchema != oSchema:
                                    flagChange = True
                            else:
                                flagChange = True
                            if flagChange:
                                nextOldNode.setAttribute("mtime",
                                                         self.currentTime)
                                nextOldNode.setAttribute("schema",nSchema)
                    # Замещение ноды
                    elif flagReplace:
                        replaceXmlNode = xmlNode.cloneNode(True)
                        # Сравнение содержимого нод
                        if not self.cmpListsNodesEntry([replaceXmlNode],
                                                       [nextOldNode]):
                            replaceXmlNode.setAttribute("mtime",
                                                        self.currentTime)
                            if not\
                                self._removeDropNodesAndAttrAction(\
                                                                replaceXmlNode):
                                return False
                            workNode.replaceChild(replaceXmlNode,
                                                nextOldNode)
                        childNodes = False
                    # Удаление ноды
                    elif flagDrop:
                        workNode.removeChild(nextOldNode)
                        childNodes = False
                else:
                    # Добавление ноды
                    childNodes = False
                    if not flagDrop:
                        appendXmlNode = xmlNode.cloneNode(True)
                        appendXmlNode.setAttribute("mtime", self.currentTime)
                        if not\
                            self._removeDropNodesAndAttrAction(appendXmlNode):
                                return False
                        workNode.appendChild(appendXmlNode)
            if childNodes:
                for node in childNodes:
                    levelNumber +=1
                    if not self._join(node, nextOldNode, False, levelNumber):
                        flagError = True
                        break
                    levelNumber -= 1
        if flagError:
            return False
        return True

    def join(self, xml_gconfObj):
        """Объединяем конфигурации"""
        # Получаем текущее время
        self.currentTime = self.getCurrentTime()
        if isinstance(xml_gconfObj, xml_gconf):
            try:
                self.joinDoc(xml_gconfObj.doc)
            except:
                self.setError(_("Can not join profile"))
                return False
        return True

    def getConfig(self):
        """Получение текстового файла из XML документа"""
        data = self.doc.toprettyxml().split("\n")
        data = map(lambda x: x.replace("\t","  "),
                   filter(lambda x: x.strip(), data))
        dataOut = []
        z = 0
        lenData = len(data)
        lenM2 = lenData - 2
        for i in xrange(lenData):
            if z>0:
                z -= 1
                continue
            if i < lenM2 and data[i].endswith(">") and not "<" in data[i+1]:
                dataOut.append(data[i] + data[i+1].strip() + data[i+2].strip())
                z = 2
                continue
            dataOut.append(data[i])
        return "\n".join(dataOut)
