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

# Copyright 2012-2013 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 pickle, random
import threading
import sys, os, re
from os import path
import glob
import traceback
from traceback import print_exc
from calculate.install.distr import Distributive
from calculate.lib.cl_log import log
from calculate.lib.utils.colortext import convert_console_to_xml
from api_types import ReturnProgress,ViewParams,Integer,ViewInfo
from loaded_methods import LoadedMethods
from calculate.lib.cl_lang import setLocalTranslate,getLazyLocalTranslate
setLocalTranslate('cl_core3',sys.modules[__name__])
__ = getLazyLocalTranslate(_)

from calculate.lib.utils.files import (process,readFile,processProgress,
                                       makeDirectory)
from calculate.lib.datavars import DataVarsError, CriticalError
from calculate.lib.cl_template import TemplatesError
from calculate.lib.utils.content import getCfgFiles
from itertools import *

from soaplib.serializers.primitive import String, Integer, Any, Boolean
from soaplib.serializers.clazz import Array
from soaplib.service import rpc, DefinitionBase
from calculate.core.server.api_types import ReturnedMessage,CommonInfo
from calculate.core.server.api_types import ChoiceValue, Table, Option, Field, \
                                           GroupField, ViewInfo, ViewParams
from calculate.lib.cl_template import Template
from calculate.lib.datavars import DataVars
from loaded_methods import LoadedMethods
from calculate.core.depricated import safetyWrapper

class CommonMethods:
    def dispatchConf(self,filesApply=None, prefix="/"):
        """
        Common dispatch conf. Using if ._cfg files created.
        """
        def normalizeConfig(text):
            """
            Нормализовать конфигурационный файл для сравнения:
            * удалить calculate заголовок
            * добавить перевод строки в конец если файл без перевода строки
            """
            if text.endswith('\n'):
                return Template.removeComment(text)
            else:
                return "%s\n"%Template.removeComment(text)

        ORIG,DATA=0,1
        MTIME,CFGFNAME=0,1
        FIRST=0
        cfgFiles = getCfgFiles(prefix=prefix).items()
        info = filter(lambda x:filesApply is None or \
                              x[DATA][FIRST][CFGFNAME] in filesApply,
               cfgFiles)
        maxInfo = len(info)
        for ind,data in enumerate(info):
            out = []
            orig,data = data
            data = data[FIRST]

            origdata = readFile(orig)
            newdata = readFile(data[CFGFNAME])
            pattern = "%s/._cfg????_%s"%(os.path.dirname(orig),
                                         os.path.basename(orig))
            for fn in glob.glob(pattern):
                try:
                    if fn == data[CFGFNAME]:
                        continue
                    os.unlink(fn)
                except:
                    pass
            if (self.clVars.Get('cl_autoupdate_set') == 'on' or 
                origdata == newdata):
                answ = "use new"
            else:
                origContent = normalizeConfig(readFile(orig))
                newContent = normalizeConfig(readFile(data[CFGFNAME]))
                if origContent == newContent:
                    answ = "use new"
                else:
                    for i,s in enumerate(list(process("diff","-Nu",
                               orig,data[CFGFNAME]))):
                        s = convert_console_to_xml(s)
                        if s.startswith('+') and i>1:
                            out.append('<font color="green">%s</font>'%s)
                        elif s.startswith('-') and i>1:
                            out.append('<font color="red">%s</font>'%s)
                        else:
                            out.append(s)
                    self.printPre("<br/>".join(out))
                    self.printSUCCESS(_("({one} of {_all}) -- {fname}").format(
                        one=ind+1,_all=maxInfo,fname=orig))
                    answ = self.askChoice(_("Choose a configuration action:"),
                                      answers=(("zap new", _("Zap new")),
                                               ("use new", _("Use new")),
                                               ("next", _("Next"))))
            if answ == "next":
                continue
            elif answ == "use new":
                try:
                    open(orig, 'w').write(readFile(data[CFGFNAME]))
                    os.unlink(data[CFGFNAME])
                    if not filesApply is None:
                        try:
                            i = filesApply.index(data[CFGFNAME])
                            filesApply[i] = orig
                        except Exception as e:
                            print str(e)
                except Exception as e:
                    print str(e)
                    self.printERROR(
                        _("Failed to copy {ffrom} to {fto}").format(
                         ffrom=data[CFGFNAME],fto=orig))
                    continue
            elif answ == "zap new":
                try:
                    os.unlink(data[CFGFNAME])
                    if not filesApply is None:
                        try:
                            filesApply.remove(data[CFGFNAME])
                        except Exception as e:
                            print str(e)
                except Exception as e:
                    self.printERROR(
                        _("Failed to remove %s")%data[CFGFNAME])
        return True

    def setVariable(self,varname,varvalue,force=False):
        """
        Установить значение переменной
        """
        self.clVars.Set(varname,varvalue,force=force)
        return True

    def invalidateVariables(self, *variables):
        for varname in (x.rpartition('.')[2] for x in variables):
            self.clVars.Invalidate(varname, force=True)
        return True


    def applyTemplates(self,target=None,useClt=None,cltFilter=False,root=None,
                        useDispatch=True):
        """
        Применить шаблоны.
        
        Args:
        target: дистрибутив, куда необходимо выполнить шаблоны (/ по умолчанию)
        useClt: использовать clt шаблоны
        cltFilter: применять фильтр на clt шаблоны
        root: каталог, куда будут наложны шаблоны (cl_root_path)
        """
        from calculate.lib.cl_template import (Template, TemplatesError,
                                               ProgressTemplate)
        if target is None:
            chroot = '/'
        elif isinstance(target, Distributive):
            chroot = target.getDirectory()
        else:
            chroot = target
        if root is None:
            root = '/'
        elif isinstance(root, Distributive):
            root = root.getDirectory()
        cltFilter=True if cltFilter in (True,"on") else False
        self.clVars.Set("cl_chroot_path",chroot, True)
        self.clVars.Set("cl_root_path",root, True)
        # определение каталогов содержащих шаблоны
        dirs_list, files_list = ([],[])
        useClt = useClt in ("on",True)
        self.addProgress()
        nullProgress = lambda *args,**kw:None
        dispatch = self.dispatchConf if useDispatch else None
        clTempl = ProgressTemplate(nullProgress,self.clVars,
                cltObj=useClt,
                cltFilter=cltFilter,
                printSUCCESS=self.printSUCCESS,
                printWARNING=self.printWARNING,
                askConfirm=self.askConfirm,
                dispatchConf=dispatch,
                printERROR=self.printERROR)
        try:
            clTempl.applyTemplates()
            if clTempl.hasError():
                if clTempl.getError():
                    raise TemplatesError(clTempl.getError())
        finally:
            if clTempl:
                if clTempl.cltObj:
                    clTempl.cltObj.closeFiles()
                clTempl.closeFiles()
        return True


class CommonLink(object):
    """
    Объект-связка объектов тип Install,Client,Action с Common объектом
    """

    def set_link(self,com):
        """
        Установить связь с Common объектом
        """
        self.com = com
        # подключить все методы Common
        for fn in (x for x in dir(CoreWsdl.Common) if not x.startswith("_")):
            if hasattr(com,fn):
                setattr(self, fn, getattr(com, fn))


class ActionError(Exception):
    pass

class Tasks:
    """
    Класс для создания проверок необходимости запуска задачи в зависимости
    от результатра работы предыдущих задач
    """
    def __init__(self,check):
        self.check = check

    def __call__(self,result):
        return self.check(result)

    def __or__(self,y):
        return Tasks(lambda result:self(result) or y(result))

    def __ror__(self,y):
        return Tasks(lambda result:y(result) or self(result))

    def __and__(self,y):
        return Tasks(lambda result:self(result) and y(result))

    def __rand__(self,y):
        return Tasks(lambda result:y(result) and self(result))

    def __invert__(self):
        return Tasks(lambda result:not self(result))

    @classmethod
    def success_all(cls,*tasks):
        """
        Все указанные задачи выполнены и выполнены без ошибок
        """
        return Tasks(
            lambda result:all(x in result and result[x] for x in tasks))

    @classmethod
    def success_one_of(cls,*tasks):
        """
        Хотя бы одна из задач выполнена и хотя бы одна из выполненных без ошибок
        """
        return Tasks(
            lambda result:any(result[x] for x in tasks if x in result))

    @classmethod
    def success(cls,inessential=[]):
        """
        Все ранее запущенные задачи успешно завершены, результат задач
        inessential не важен
        """
        return Tasks(lambda result:all(result[x] for x in result
                                       if x not in inessential))

    @classmethod
    def failed(cls,inessential=[]):
        """
        Хотя бы одна из задач завершилась неудачно, результат задач
        inessential не важен
        """
        return Tasks(lambda result:any(not result[x] for x in result
                                       if x not in inessential))

    @classmethod
    def failed_all(cls,*tasks):
        """
        Выполнена хотя бы одна задача и все те, которые выполнены с ошибкой
        """
        return Tasks(
            lambda result:any(not result[x] for x in tasks if x in result))

    @classmethod
    def failed_one_of(cls,*tasks):
        """
        Хотя бы одна из указанных задач выполнена и выполнена с ошибкой
        """
        return Tasks(
            lambda result:any(x in result and not result[x] for x in tasks))

    @classmethod
    def has(cls,*tasks):
        """
        Был запуск всех перечисленных задач
        """
        return Tasks(lambda result:all(x in result for x in tasks))

    @classmethod
    def hasnot(cls,*tasks):
        """
        Не было запуска ни одной из перечисленных задач
        """
        return Tasks(lambda result:all(x not in result for x in tasks))

    @classmethod
    def result(cls,task,eq=None,ne=None):
        if eq:
            wrapper = lambda result: task in result and result[task]==eq
        elif ne:
            wrapper = lambda result: not task in result or result[task]!=ne
        else:
            wrapper = lambda result: task in result and result[task]
        return Tasks(wrapper)

    @classmethod
    def has_any(cls,*tasks):
        """
        Был запуск любой из задач
        """
        return Tasks(lambda result:any(x in result for x in tasks))

class Action:
    """
    Класс для реализации выполнения действия
    """
    #default = {'depend':Tasks.success(),
    #           # прятать вывод
    #           'hideout':False,
    #           # задача важна, в случае False результат не сохраняется в self.result
    #           'essential':True}

    # список выполняемых задач
    tasks = []
    # список исключений, которые выводятся в сокращенном формате (ожидаемые ошибки)
    # остальные выводятся с именем модуля и номером строки
    native_error = ()

    # сообщение об удачном завершении действия
    successMessage = None
    # сообщение при ошибке
    failedMessage = None
    # сообщение о прерывании
    interruptMessage = None

    # список задач для действия
    tasks = []
    # добавить стандартные сообщения в конце
    finishMessage = True

    def __init__(self):
        if self.finishMessage:
            tasks = []
            if self.failedMessage:
                tasks.append(
                 # вывести сообщение в случае ошибки
                 {'name':'failed',
                  'error': self.failedMessage,
                  'depend': (Tasks.failed() & Tasks.hasnot("interrupt"))})
            if self.successMessage:
                tasks.append(
                 # вывести сообщение в случае успеха
                 {'name':'success',
                  'message': self.successMessage,
                  'depend': (Tasks.success() & Tasks.hasnot("failed"))})
            if self.interruptMessage:
                tasks.append(
                 # вывести сообщение о том, что действие прервано
                 {'name':'intmessage',
                  'error':self.interruptMessage,
                  'depend': (Tasks.has("interrupt"))})
            self.tasks = self.tasks + tasks
        self.group_name = ""
        self.clVars = None

    @classmethod
    def program(cls,progName):
        """
        Проверить наличие программы
        """
        return lambda dv:bool(progPath(progName))

    @classmethod
    def packageInstalled(cls,pkg):
        """
        Проверить было ли обновление пакета
        """
        return lambda dv:False

    @classmethod
    def variables(cls,*varnames):
        """
        Передать переменные как аргументы, поддерживается True,False
        """
        return lambda dv:[dv.Get(x) if not x in (True,False) else x \
                          for x in varnames]

    reMethod = re.compile("^([A-Za-z]+)\.([A-Za-z0-9_]+)\(([^)]*)\)$")
    reMessageVars = re.compile("\{([^}]+)\}")

    def parseMethod(self,objs,dv,s,task):
        """
        Разобрать строку метода, на объект, метод, аргументы
        """
        result = self.reMethod.search(s)
        if not result:
            raise ActionError(_("Wrong method for task %s")%task)
        objname,methodname,args = result.groups()
        if not objname in objs:
            raise ActionError(_("Object %s not found")%objname)
        obj = objs[objname]
        if not hasattr(obj,methodname):
            raise ActionError(_("Method {method} for {obj} not found").
                        format(method=methodname,obj=objname))

        def _convertMethodArg(param):
            """
            Конвертировать аргумент для метода, взять по словарю,
            либо строка - имя переменной
            """
            param = param.strip()
            mapStd = {'True':True,
                      'False':False,
                      'None':None,
                      '""':"",
                      "''":""}
            if param in mapStd:
                return mapStd[param]
            if param.isdigit():
                return int(param)
            if param.startswith('"') and param.endswith('"'):
                return param.strip('"')
            if param == 'eachvar':
                return self.eachvar
            _type = dv.getInfo(param).type
            if _type == "int":
                return dv.GetInteger(param)
            if _type == "bool":
                return dv.GetBool(param)
            return dv.Get(param)

        if args:
            args = map(_convertMethodArg, args.split(','))
        else:
            args = ()
        return getattr(obj,methodname),args

    def formatMessage(self,dv,message):
        """
        Вставить значения переменных в текст сообщения
        """

        class TextTrasformer:
            def first_letter_upper(self, s):
                return "%s%s" % (s[0].upper(), s[1:])

        tt = TextTrasformer()

        def replace_value(match):
            var = match.group(1)
            if ":" in var:
                var, func = var.split(':')
            else:
                func = None
            if var == "eachvar":
                val = self.eachvar
            else:
                val = dv.Get(var)
            if type(val) == list:
                val = ",".join(val)
            if func:
                if hasattr(tt, func):
                    val = getattr(tt, func)(val)
                else:
                    val = getattr(val, func)()
            return "{0}".format(val)

        return self.reMessageVars.sub(replace_value, str(message))

    def runCondition(self,funcCondition):
        """
        Запустить метод проверки условия (если аргумент называется Get,
        то передавать в него не объект DataVars а метод Get,
        если у нет аргументов, то не передавать туда аргументы
        """
        args = []
        arg_count = funcCondition.func_code.co_argcount
        for param_name in funcCondition.func_code.co_varnames[:arg_count]:
            if param_name in ('Get','Select','ZipVars'):
                args.append(getattr(self.clVars, param_name))
            elif param_name == 'eachvar':
                args.append(self.eachvar)
            else:
                args.append(self.clVars)
        return funcCondition(*args)

    def getFormatMessage(self,action,*fields):
        """
        Получить сообщение для вывода среди нескольких с приоритетом и
        метод вывода
        """
        for field in (x for x in fields if x in action):
            if "error" in field:
                printFunc = self.printERROR
            elif "warning" in field:
                printFunc = self.printWARNING
            else:
                printFunc = self.printSUCCESS
            return printFunc,self.formatMessage(self.clVars,action[field])
        return None,None

    def get_tasks(self, result):
        """
        Герератор задач (поддержка линейной обработки задач в группах)
        """
        for task in self.tasks:
            if "group" in task:
                if all(self.get_condition_context(task, result).values()):
                    self.group_name = task["group"]
                    for action in task["tasks"]:
                        yield action
                    if not self.group_name:
                        self.endGroup()
                    else:
                        self.group_name = ""
            else:
                yield task

    def get_condition_context(self, action, result):
        """
        Получить результаты проверки по зависимосятм и условиям
        """
        group, op, name = action.get("name",
                                     "<unknown>").rpartition(':')
        # проверить по результатам
        # если указанно группа к имени с '!', то проверяется
        # только условие принадлежности задачи к группе
        if group and group.endswith('!'):
            group = group.strip('!')
            depend = [Tasks.success_all(group)]
        else:
            depend = action.get("depend", Tasks.success())
            depend = (depend
                      if type(depend) in (list, tuple) else [depend])
            if group:
                depend.append(Tasks.success_all(group))
        depend_result = all([x(result) for x in depend])
        # проверить по условиям
        if depend_result:
            condition_funcs = action.get("condition", lambda dv: True)
            condition_funcs = (condition_funcs
                               if type(condition_funcs) in (list, tuple)
                               else [condition_funcs])
            condition_result = all(
                [self.runCondition(x) for x in condition_funcs])
        else:
            condition_result = True
        return {'condition': condition_result, 'depend': depend_result}

    def run(self, objs, dv):
        """Запустить список действий"""
        class StubLogger:
            def info(self,s):
                pass
        result = {}

        self.group_name = ""
        self.clVars = dv
        if dv.Get('cl_env_debug_set') == 'off' or \
            dv.Get('cl_ebuild_phase'):
            logger = StubLogger()
        else:
            logger = log("core-action.log",
                         filename="/var/log/calculate/core-action.log",
                         formatter="%(asctime)s - %(levelname)s - %(message)s")
        for obj in objs.values():
            obj.set_link(self)
            obj.clVars = dv
            if hasattr(obj,"init"):
                obj.init()
        try:
            self.beginFrame()
            logger.info("Start {methodname}".format(
                methodname=self.method_name))
            for action in self.get_tasks(result):
                foreach = action.get("foreach", "")
                if foreach:
                    foreach = self.clVars.Get(foreach)
                else:
                    foreach = [""]
                self.eachvar = ""
                for eachvar in foreach:
                    self.eachvar = eachvar
                    group,op,name = action.get("name",
                                               "<unknown>").rpartition(':')
                    res = True
                    task = False
                    self.clVars.Set('cl_task_name', name, force=True)
                    try:
                        run_context = self.get_condition_context(action, result)
                        actinfo = "Run" if all(run_context.values()) else "Skip"
                        logger.info(
                            "{action} {name}: condition: {condition}, "
                            "depend: {depend}".format(
                                action=actinfo,
                                name=name,
                                condition=run_context['condition'],
                                depend=run_context['depend']))

                        elsePrint, elseMessage = (
                            self.getFormatMessage(action,"else_error",
                                              "else_warning","else_message"))
                        if (run_context['depend'] and
                                not run_context['condition'] and elseMessage):
                            if "else_error" in action:
                                if action.get("essential",True):
                                    result[name]=False
                            elsePrint(elseMessage)
                        if all(run_context.values()):
                            self.writeFile()
                            if self.group_name:
                                self.startGroup(str(self.group_name))
                                self.group_name = None
                            printFunc,message = self.getFormatMessage(
                                    action,"error","warning","message")
                            if "confirm" in action and message:
                                result[name] = \
                                    self.askConfirm(str(message),
                                                    action["confirm"])
                                continue
                            elif message:
                                # если действие с командой
                                if not "error" in action and \
                                    "method" in action or "command" in action:
                                    self.startTask(str(message))
                                    task = True
                                # действие содержит только сообщение
                                else:
                                    if "error" in action:
                                        res = False
                                    printFunc(message)
                            # запустить метод объекта
                            if "method" in action:
                                try:
                                    method, args = self.parseMethod(objs,dv,
                                                      action["method"], name)
                                    if "decoration" in action:
                                        decfunc, decargs = \
                                            self.parseMethod(objs, dv,
                                                     action["decoration"], name)
                                        method = decfunc(*decargs)(method)
                                    res = method(*args)
                                    if res is None:
                                        res = False
                                except CriticalError as e:
                                    self.printERROR(str(e))
                                    self.endFrame()
                                    return False
                                except self.native_error as e:
                                    if hasattr(e, "addon") and e.addon:
                                        self.printERROR(str(e.addon))
                                    self.printERROR(str(e))
                                    res = False
                                except Exception as e:
                                    error = shortTraceback(*sys.exc_info())
                                    self.printERROR(error)
                                    res = False
                            # запустить системную команду
                            if "command" in action:
                                hideout = action.get("hideout",False)
                                cmdParam = map(lambda x:x.strip('"\''),
                                           re.findall('["\'][^"\']+["\']|\S+',
                                           action["command"]))
                                cmd = processProgress(*cmdParam)
                                for line in cmd.progress():
                                    if not hideout:
                                        self.printSUCCESS(line)
                                if cmd.failed():
                                    lineCmd = cmd.pipe.stderr.read().split('\n')
                                    for line in filter(None, lineCmd):
                                        self.printERROR(line)
                                res = cmd.success()
                            if action.get("essential",True):
                                result[name]=res
                            failedPrint, failedMessage = (
                                self.getFormatMessage(action,"failed_error",
                                         "failed_warning","failed_message"))
                            if not res and failedPrint:
                                failedPrint(failedMessage)
                            if task and res in (True,False,"skip"):
                                self.endTask(res)
                            logger.info("{name}: Result is {result}".format(
                                name=name, result=res))
                            if res is True:
                                on_success = action.get('on_success',None)
                                if on_success:
                                    on_success()
                        #else:
                        #    print "[-] Skip ",name
                    except KeyboardInterrupt as e:
                        if action.get("essential",True):
                            result[name]=False
                        self.endTask(False)
                        self.printWARNING(_("Task interrupted"))
                        result["interrupt"] = False
                        logger.info("{name}: Interrupeted".format(name=name))
                    except self.native_error as e:
                        if hasattr(e,"addon") and e.addon:
                            self.printERROR(str(e.addon))
                        self.printERROR(str(e))
                        result[name]=False
                        logger.info("{name}: Native error".format(name=name))
                    except CriticalError as e:
                        self.printERROR(str(e))
                        self.endFrame()
                        return False
                    except BaseException as e:
                        result[name]=False
                        error = shortTraceback(*sys.exc_info())
                        self.printERROR("%s:%s"%(name,error))
                        logger.info("{name}: Unknown exception {exp}".format(
                            name=name, exp=e.__class__.__name__))
        finally:
            dv.close()
        self.endFrame()
        if any(x in ("failed","interrupt") for x in result):
            return False
        return True

def commonView(self,sid,params,arg):
    dv = self.get_cache(sid,arg,"vars")
    if not dv:
        dv = getattr(self,"%s_vars"%arg)()
    else:
        dv.processRefresh()
    view = ViewInfo(dv,viewparams=params)
    self.set_cache(sid, arg, "vars",dv,smart=False)
    return view

def catchExcept(*skipException):
    class wrapper:
        def __init__(self,f):
            self.f = f
            self.func_name = f.func_name
            self.func_code = f.func_code
            self.__doc__ = f.__doc__
            self.__name__ = f.__name__
        
        def __call__(self,*args,**kwargs):
            try:
                return self.f(*args,**kwargs)
            except BaseException as e:
                from calculate.core.server.api_types import ViewInfo,GroupField,Field
                view = ViewInfo(groups=[])
                group = GroupField(name=_("Error"),last=True)
                group.fields = []
                group.fields.append(Field(
                        name = "error",
                        label = str(e),
                        default = 'color:red;',
                        element = "error"))
                view.groups.append(group)
                if not any(isinstance(e,x) for x in skipException):
                    print shortTraceback(*sys.exc_info())
                    #for i in apply(traceback.format_exception, sys.exc_info()):
                    #    print i,

                return view
    return wrapper

def shortTraceback(e1,e2,e3):
    """
    Return short traceback
    """
    frame = e3
    for i in apply(traceback.format_exception, (e1,e2,e3)):
        print i,
    while(frame.tb_next):
        frame = frame.tb_next
    module,part = os.path.split(frame.tb_frame.f_code.co_filename)
    if part.endswith('.py'):
        part = part[:-3]
    fallbackmod = part
    modname = [part]
    while module != '/' and not module.endswith('site-packages'):
        module,part = os.path.split(module)
        modname.insert(0,part)
    if module.endswith('site-packages'):
        modname = ".".join(modname)
    else:
        modname = fallbackmod
    return "%s:%s(%s:%s)"%(e1.__name__,str(e2),modname,frame.tb_lineno)


class ActiveClientStatus:
    Success = 0
    Failed = 1
    WrongSID = 2

class CoreWsdl():
    # client signals about presence
    def active_clients(self, sid):
        # curThread = threading.currentThread()
        #        REMOTE_ADDR = curThread.REMOTE_ADDR
        self.get_lang(sid, "from active clients")
        if 0 < sid < self.max_sid:
            try:
                # open file its session
                sid_file = self.sids + "/%d.sid" % sid
                if not os.path.isfile(sid_file):
                    return ActiveClientStatus.Failed
                # check sid in sid.db
                if not (os.path.isfile(self.sids_file) and
                    self.find_sid_in_file(sid)):
                    try:
                        os.unlink(sid_file)
                    except (OSError,IOError):
                        pass
                    return ActiveClientStatus.Failed
                with self.sid_locker:
                    with open(sid_file) as fd:
                        # read information about session
                        sid_inf = pickle.load(fd)
                        # reset counters
                        sid_inf[1] = 0
                        sid_inf[2] = 0
                    fd.close()
                    if not os.path.isfile(sid_file):
                        return ActiveClientStatus.Failed
                    fd = open(sid_file, "w")
                    pickle.dump(sid_inf, fd)
                    fd.close()
                return ActiveClientStatus.Success
            except:
                return ActiveClientStatus.Failed
        else:
            return ActiveClientStatus.WrongSID

    def serv_get_methods(self, client_type):
        curThread = threading.currentThread()
        certificate = curThread.client_cert
        from cert_cmd import find_cert_id
        cert_id = find_cert_id (certificate, self.data_path, self.certbase)

        rights = self.serv_view_cert_right(cert_id, self.data_path,client_type)
        return_list = []
        if client_type == "console":
            for meth in self.return_conMethod():
                right_flag = True
                for right in LoadedMethods.rightsMethods[meth[1]]:
                    if not right in rights:
                        right_flag = False
                if right_flag:
                    return_list.append(meth)
            if not len(return_list):
                return [['0','0']]
            return return_list
        else:
            curThread = threading.currentThread()
            for meth in self.return_guiMethod():
                right_flag = True
                for right in LoadedMethods.rightsMethods[meth[1]]:
                    if not right in rights:
                        right_flag = False
                if right_flag:
                    return_list.append(meth)
            if not len(return_list):
                return [['0','0']]
            return return_list
            #return self.return_guiMethod()

    # return a list of methods for the console as list
    def return_conMethod(self):
        from loaded_methods import LoadedMethods
        results = []
        for item in LoadedMethods.conMethods:
            temp = []
            temp.append(item)
            for i in LoadedMethods.conMethods[item]:
                temp.append(i)
            results.append (temp)
        return results

    # return a list of methods for the GUI as list
    def return_guiMethod(self):
        from loaded_methods import LoadedMethods
        results = []
        for item in LoadedMethods.guiMethods:
            for i in range(0, len(LoadedMethods.guiMethods[item]),3):
                temp = []
                temp.append(item)
                for j in range (3):
                    temp.append(LoadedMethods.guiMethods[item][i+j])
                results.append (temp)
        return results

    # get available sessions
    def serv_get_sessions(self):
        result = []
        fd = open(self.sids_file, 'r')
        while 1:
            try:
                # read all on one record
                list_sid = pickle.load(fd)
            except:
                break
            # if session id found
            result.append (str(list_sid[0]))
        fd.close()
        return result

    # check client alive
    def client_alive(sid, SIDS_DIR):
        sid_path = SIDS_DIR + "/%d.sid"%sid
        if not os.path.isfile(sid_path):
            return 1
        with self.sid_locker:
            with open(sid_path) as fd:
                # read information about session
                sid_inf = pickle.load(fd)
                # flag absence client
            fd.close()
            if sid_inf[2] == 1:
                return 0
            else:
                return 1

    class Common(CommonMethods):
        """ class to interact with the processes """
        def __init__(self, process_dict, progress_dict, table_dict,
                     frame_list, pid):
            self.process_dict = process_dict
            self.progress_dict = progress_dict
            self.progress_dict['id'] = 0
            self.table_dict = table_dict
            self.frame_list = frame_list
            self.pid = pid
            self.Num = 100000

        def pauseProcess(self):
            from calculate.core.server.gen_pid import ProcessStatus
            self.method_status = ProcessStatus.Paused
            self.writeFile()

        def resumeProcess(self):
            from calculate.core.server.gen_pid import ProcessStatus
            self.method_status = ProcessStatus.Worked
            self.writeFile()

        def writeFile(self):
            """ write data in file """
            from baseClass import Basic
            from calculate.core.server.gen_pid import ProcessMode
            if not os.path.exists(Basic.pids):
                makeDirectory(Basic.pids)
            pid_file = path.join(Basic.pids, '%d.pid' % self.pid)
            try:
                with open(pid_file, 'w') as f:
                    d = {'name': self.process_dict['method_name'],
                         'mode': ProcessMode.CoreDaemon,
                         'os_pid': os.getpid(),
                         'status': self.process_dict['status']}
                    pickle.dump(d, f)
            except (IOError, OSError) as e:
                print str(e)
                print _("Failed to write the PID file %s!") % pid_file

        def setProgress(self, perc, short_message = None, long_message = None):
            try:
                id = self.progress_dict['id']
                self.progress_dict[id] = ReturnProgress(perc, short_message, \
                                                        long_message)
            except IOError as e:
                pass

        def setStatus(self, stat):
            self.process_dict['status'] = stat

        def setData(self, dat):
            self.data_list = dat

        def getStatus(self):
            try:
                return self.process_dict['status']
            except IOError as e:
                return -1

        def getProgress(self):
            try:
                id = self.progress_dict['id']
                if self.progress_dict.has_key(id):
                    return self.progress_dict[id].percent
            except IOError as e:
                pass
            return 0

        def getAnswer(self):
            import time
            while self.process_dict['answer'] == None:
                time.sleep (0.5)
            res = self.process_dict['answer']
            self.process_dict['answer'] = None
            self.frame_list.pop(len(self.frame_list) - 1)
            self.process_dict['counter'] -= 1            
            return res

        def addProgress(self,message=""):
            id = random.randint(1, self.Num)
            while id in self.progress_dict:
                id = random.randint(1, self.Num)
            self.progress_dict['id'] = id
            self.progress_dict[id] = ReturnProgress(0, '', '')
            self.addMessage(type = 'progress', id = id)

        def printTable (self, table_name, head, body, fields = None,\
                        onClick = None, addAction = None):
            id = random.randint(1, self.Num)
            while id in self.table_dict:
                id = random.randint(1, self.Num)

            from api_types import Table
            table = Table(head = head, body = map(lambda x:map(str,x),body), fields = fields, \
                          onClick = onClick, addAction = addAction, \
                          values = None)
            self.table_dict[id] = table
            self.addMessage(type = 'table', message = table_name, id = id)

        def addMessage(self, type='normal', message=None, id=None,
                       onlyShow='', default=None):
            from api_types import Message
            reClean = re.compile('\[(?:\d+;)?\d+m')
            messageObj = Message(type = type,
                message = None if message in (None,True,False) else \
                    reClean.sub('',filter(lambda x:x>= ' ',message)),
                result = message if message in (True,False) else None,
                id = id, onlyShow = onlyShow, default=default)
            try:
                self.frame_list.append(messageObj)
            except BaseException as e:
                print _(("%s:"%type)+str(message))
            #if len(self.frame_list)>500:
            #    self.frame_list.pop(0)

        def printSUCCESS(self, message='', onlyShow=None):
            self.addMessage(type='normal', message=message,
                            onlyShow=onlyShow)

        def printPre(self, message='', onlyShow=None):
            self.addMessage(type='pre', message=message,
                            onlyShow=onlyShow)

        def printDefault(self, message='', onlyShow=None):
            self.addMessage(type='plain', message=message,
                            onlyShow=onlyShow)

        def printWARNING(self, message, onlyShow=None):
            self.addMessage(type='warning', message=message,
                            onlyShow=onlyShow)

        def printERROR(self, message='', onlyShow=None):
            perc = self.getProgress()
            if perc == 0:
                self.setProgress(100)
            elif self.getProgress() > 0:
                self.setProgress(0 - self.getProgress())
            else:
                #self.setProgress(-100)
                self.setProgress(perc)
            self.addMessage(type='error', message=message,
                            onlyShow=onlyShow)

        def startTask(self, message, progress=False, num=1):
            if progress:
                self.addMessage(type='startTask', message=message, id=num)
                self.addProgress()
            else:
                self.addMessage(type='startTask', message=message, id=num)

        def setTaskNumber(self, number=None):
            self.addMessage(type='taskNumber', message=str(number))

        def endTask(self, result=None, progress_message=None):
            self.addMessage(type='endTask', message=result)
            self.setProgress(100, progress_message)

        def askConfirm(self, message, default="yes"):
            self.addMessage(type='confirm', message=message, default=default)
            ret = self.getAnswer()
            if ret == "":
                return default
            return ret

        def isInteractive(self):
            return True

        def askChoice(self,message,answers=[("yes","Yes"),("no","No")]):
            self.addMessage(type = 'choice',message="%s|%s"%(message,
                        ",".join(map(lambda x:"%s(%s)"%(x[0],x[1]),answers))))
            return self.getAnswer()

        def askQuestion(self, message):
            self.addMessage(type = 'question', message = message)
            return self.getAnswer()

        def askPassword(self, message, twice = False):
            pas_repeat = 2 if twice else 1
            self.addMessage(type = 'password', message = message, \
                            id = pas_repeat)
            return self.getAnswer()

        def beginFrame(self, message = None):
            self.addMessage(type = 'beginFrame', message = message)

        def endFrame(self):
            self.addMessage(type = 'endFrame')

        def startGroup(self, message):
            self.addMessage(type = 'startGroup', message = message)

        def endGroup(self):
            self.addMessage(type = 'endGroup')

        #def cache(self, param):
            #sid = self.process_dict['sid']
            #self.args[sid] = collections.OrderedDict()
    def startprocess (self, sid, target=None, method=None, method_name=None, \
                      auto_delete=False, args_proc = {}):
        """ start process """
        pid = self.gen_pid()
        self.add_sid_pid(sid, pid)

        import multiprocessing
        if self.manager is None:
            self.__class__.manager = multiprocessing.Manager()
        # Manager for sending glob_process_dict between watcher and process
        #manager = multiprocessing.Manager()
        self.glob_process_dict[pid] = self.manager.dict()
        self.glob_process_dict[pid]['sid'] = sid
        self.glob_process_dict[pid]['status'] = 0
        self.glob_process_dict[pid]['time'] = ""
        self.glob_process_dict[pid]['answer'] = None
        self.glob_process_dict[pid]['name'] = ""
        self.glob_process_dict[pid]['flag'] = 0
        self.glob_process_dict[pid]['counter'] = 0

        self.glob_frame_list[pid] = self.manager.list()
        self.glob_progress_dict[pid] = self.manager.dict()
        self.glob_table_dict[pid] = self.manager.dict()

        # create object Common and send parameters
        com = target(self.glob_process_dict[pid], \
                     self.glob_progress_dict[pid], \
                     self.glob_table_dict[pid], \
                     self.glob_frame_list[pid], pid)

        if len(com.__class__.__bases__)>1 and \
            hasattr (com.__class__.__bases__[1], '__init__'):
            com.__class__.__bases__[1].__init__(com)
        # start helper
        com.method_name = method_name
        p = multiprocessing.Process(target = self.target_helper,\
                args = (com, getattr(com,method)) +(method_name, )+ args_proc)

        self.process_pid[pid] = p
        p.start()
        if auto_delete:
            # start watcher (for kill process on signal)
            watcher = threading.Thread(target = self.watcher_pid_proc,\
                        args = (sid, pid))

            watcher.start()
        return str(pid)


    # wrap all method
    def target_helper(self, com, target_proc, method_name, *args_proc):
        if not os.path.exists(self.pids):
            os.system('mkdir %s' %self.pids)
#        PID_FILE  =  self.pids + '/%d.pid'%com.pid
        import datetime
        dat = datetime.datetime.now()

        com.process_dict['status'] = 1
        com.process_dict['time'] = dat
        #if method_name:
        com.process_dict['method_name'] = method_name
        com.process_dict['name'] = target_proc.__func__.__name__

        try:
            result = target_proc(*args_proc)
        except:
            result = False
            print_exc()
            fd = open(self.log_filename,'a')
            print_exc(file=fd)
            fd.close()
        try:
            if result == True:
                com.setStatus (0)
                com.writeFile()
            elif result == False:
                if com.getStatus() == 1:
                    com.setStatus (2)
                com.writeFile()
            else:
                if com.getStatus() == 1:
                    com.setStatus (2)
                else:
                    com.setStatus (0)
                com.writeFile()
            try:
                if com.getProgress() < 100 and com.getProgress() > 0:
                    com.setProgress(0 - com.getProgress())
                if len(com.frame_list):
                    last_message = com.frame_list[len(com.frame_list)-1]
                    if last_message.type != 'endFrame':
                        com.endFrame()
                else:
                    com.endFrame()
            except IOError as e:
                pass

        except Exception:
            print_exc()
            fd = open(self.log_filename,'a')
            print_exc(file=fd)
            fd.close()
            com.endFrame()

    def serv_view_cert_right (self, cert_id, data_path, client_type = None):
        """ rights for the selected certificate """
        try:
            cert_id = int(cert_id)
        except:
            return ["-2"]
        cert_file =  data_path+'/client_certs/%s.crt' %str(cert_id)
        if not os.path.exists(cert_file):
            return ["-1"]
        cert = open(cert_file, 'r').read()

        #try:
        import OpenSSL
        certobj = OpenSSL.crypto.load_certificate \
                                            (OpenSSL.SSL.FILETYPE_PEM, cert)
        com = certobj.get_extension(certobj.get_extension_count()-1).get_data()
        groups = com.split(':')[1]
        groups_list = groups.split(',')
        #except:
            #return ['-1']
        results = []
        find_flag = False
        # if group = all and not redefined group all
        if 'all' in groups_list:
            fd = open(self.group_rights, 'r')
            t = fd.read()
            # find all in group_rights file
            for line in t.splitlines():
                if not line:
                    continue
                if line.split()[0] == 'all':
                    find_flag = True
                    break
            if not find_flag:
                result = []
                if client_type == 'console':
                    for meth_list in self.return_conMethod():
                        for right in LoadedMethods.rightsMethods[meth_list[1]]:
                            result.append(right)
                else:
                    for meth_list in self.return_guiMethod():
                        for right in LoadedMethods.rightsMethods[meth_list[1]]:
                            result.append(right)
                result = uniq(result)
                results = result

        if not 'all' in groups_list or find_flag:
            if not os.path.exists (self.group_rights):
                open(self.group_rights, 'w')
            with open(self.group_rights) as fd:
                t = fd.read()
                for line in t.splitlines():
                    if not line:
                        continue
                    try:
                        words = line.split(' ',1)
                        if len(words) < 2:
                            continue
                        # first word in line equal name input method
                        if words[0] in groups_list:
                            methods = words[1].split(',')
                            for i in methods:
                                results.append(i.strip())
                    except IndexError:
                        print 'except IndexError in serv_view_cert_right'
                        continue
            results = uniq(results)

        add_list_rights = []
        del_list_rights = []

        with open(self.rights) as fr:
            t = fr.read()
            for line in t.splitlines():
                words = line.split()
                meth = words[0]
                for word in words:
                    try:
                        word = int(word)
                    except:
                        continue
                    # compare with certificat number
                    if cert_id == word:
                        # if has right
                        add_list_rights.append(meth)
                    if cert_id == -word:
                        del_list_rights.append(meth)

        results += add_list_rights
        results = uniq(results)

        for method in results:
            if method in del_list_rights:
                results.remove(method)  

        if results == []:
            results.append("No Methods")
        return results

    def get_lang(self, sid, method_name=""):
        """ get clients lang """
        lang = None
        SIDS_DIR = self.sids
        with self.sid_locker:
            sid_file = SIDS_DIR+"/%d.sid" %int(sid)
            if os.path.exists(sid_file):
                fd = open(sid_file, 'r')
                while True:
                    try:
                        list_sid = pickle.load(fd)
                    except BaseException as e:
                        break
                    # if session id found
                    if sid == list_sid[0]:
                        fd.close()
                        lang = list_sid[3]
                        break
                fd.close()
            try:
                if not lang.lower() in ['fr', 'ru', 'en']:
                    lang = "en"
            except:
                lang = "en"
            import locale
            try:
                lang = locale.locale_alias[lang.lower()]
            except:
                lang = locale.locale_alias['en']
            return lang

def create_symlink(data_path,old_data_path):
    meths = LoadedMethods.conMethods
    path_to_link = '/usr/sbin'
    path_to_user_link = '/usr/bin'
    old_symlinks_file = os.path.join(old_data_path, 'conf/symlinks')
    symlinks_file = os.path.join(data_path, 'conf/symlinks')
    if not os.path.exists(os.path.join(data_path, 'conf')):
        try:
            os.makedirs(os.path.join(data_path, 'conf'))
        except OSError:
            print _("cannot create directory %s") \
                                %(os.path.join(data_path, 'conf'))
    if os.path.exists(old_symlinks_file) and not os.path.exists(symlinks_file):
        open(symlinks_file,'w').write(open(old_symlinks_file).read())
        os.unlink(old_symlinks_file)
    fd = open(symlinks_file, 'a')
    for link in meths:
        if meths[link][1]:
            link_path = os.path.join(path_to_user_link, link)
        else:
            link_path = os.path.join(path_to_link, link)
        if os.path.islink(link_path):
            continue
        if os.path.isfile(link_path):
            red = '\033[31m * \033[0m'
            print red+link_path+_(' is a file, not a link!')
            continue
        try:
            os.symlink(os.path.join(path_to_link, 'cl-core'), link_path)
            fd.write(link_path + '\n')
        except OSError, e:
            print e.message
        print _('Symlink %s created') %link_path
    fd.close()

    from calculate.lib.utils.files import readLinesFile
    temp_text_file = ''
    for line in readLinesFile(symlinks_file):
        cmdname = os.path.basename(line)
        if not cmdname in meths.keys() or \
            line.startswith(path_to_link) and meths[cmdname][1] or \
            line.startswith(path_to_user_link) and not meths[cmdname][1]:
            if os.path.islink(line):
                os.unlink(line)
                print _('Symlink %s deleted') %line
        else:
            temp_text_file += line + '\n'
    fd = open(symlinks_file, 'w')
    fd.write(temp_text_file)
    fd.close()

def initialization(cl_wsdl):
    """ find modules for further added in server class """
    cl_apis = []
    for pack in cl_wsdl:
        if pack:
            module_name = '%s.wsdl_%s'% (pack.replace("-","."),
                                            pack.rpartition("-")[2])
            #try:
            import calculate.core.wsdl_core
            import importlib
            cl_wsdl_core = importlib.import_module(module_name)
            try:
                cl_apis.append (cl_wsdl_core.Wsdl)
            except ImportError:
                sys.stderr.write(_("Unable to import %s")%module_name)
    return cl_apis

#Creation of secret key of the client
def new_key_req(key, cert_path, serv_host_name, port):
    from create_cert import generateRSAKey, makePKey, makeRequest,\
                                    passphrase_callback
    rsa = generateRSAKey()
    rsa.save_key(key+'_pub',\
                        cipher=None, callback=passphrase_callback)

    pkey = makePKey(rsa)
    pkey.save_key(key,\
                        cipher=None, callback=passphrase_callback)

    req = makeRequest(rsa, pkey, serv_host_name, port)
    if not req:
        sys.exit()
    crtreq = req.as_pem()
    crtfile = open(cert_path + '/server.csr', 'w')
    crtfile.write(crtreq)
    crtfile.close()

# delete dublicate from list
def uniq(seq):
    seen = set()
    seen_add = seen.add
    return [ x for x in seq if x not in seen and not seen_add(x)]

class WsdlMeta(type):
    """
    Метакласс для создания методов по атрибуту methdos
    """
    datavars = {}
    def __new__(cls,name,bases,attrs):
        if "methods" in attrs:
            for method in attrs["methods"]:
                attrs[method['method_name']] = cls.callerConstructor(**method)
                attrs["%s_vars"%method['method_name']] = cls.datavarsConstructor(**method)
                attrs["%s_view"%method['method_name']] = cls.viewConstructor(**method)
        return type.__new__(cls, name,bases,attrs)

    @classmethod
    def closeDataVars(cls):
        for dv in WsdlMeta.datavars.values():
            dv.close()

    @classmethod
    def createInfoObj(cls,**kwargs):
        """
        Создание передаваемой структуры данных для WSDL
        """
        def typeConvert(s):
            if "bool" in s:
                return Boolean
            elif "table" in s:
                return Array(Array(String))
            elif "list" in s:
                return Array(String)
            else:
                return String
        d = {}
        if kwargs['datavars'] in WsdlMeta.datavars:
            dv = WsdlMeta.datavars[kwargs['datavars']]
        else:
            dv = DataVars()
            dv.importVariables()
            dv.importVariables('calculate.%s.variables'%kwargs['datavars'])
            dv.defaultModule = kwargs['datavars']
            WsdlMeta.datavars[kwargs['datavars']] = dv
        def group(*args,**kwargs):
            for v in chain(kwargs.get('normal',()),kwargs.get('expert',())):
                varname = v.rpartition(".")[2]
                d[varname] = typeConvert(dv.getInfo(v).type)
        for gr in kwargs['groups']:
            gr(group)
        #if "brief" in kwargs:
        if not "cl_page_count" in d:
            d["CheckOnly"] = Boolean
        return d

    @classmethod
    def callerConstructor(cls,**kwargs):
        """
        Конструктор для создания метода-вызова для действия
        """
        def wrapper(self, sid, info):
            # костыль для локализации install
            callbackRefresh = self.fixInstallLocalization \
                if kwargs['method_name'] == 'install' else lambda dv,sid:True
            return self.callAction(sid,info,logicClass=kwargs['logic'],
                                   actionClass=kwargs['action'],
                                   method_name=kwargs['method_name'],
                                   callbackRefresh=callbackRefresh)
        wrapper.func_name = kwargs['method_name']
        func = LoadedMethods.core_method(category=kwargs.get('category',None),
                           title=kwargs['title'],
                           image=kwargs.get('image',None),
                           gui=kwargs['gui'],
                           user=kwargs.get('user',False),
                           command=kwargs.get('command',None),
                           rights=kwargs['rights'])(wrapper)
        if "--start" in sys.argv:
            infoObj = cls.createInfoObj(**kwargs)
            infoClass = type("%sInfo"%kwargs["method_name"],(CommonInfo,),infoObj)
            return rpc(Integer,infoClass,_returns = Array(ReturnedMessage))(func)
        else:
            return func

    @classmethod
    def modifyDatavars(cls,dv,data):
        """
        Поменять значения в datavars согласно data
        """
        # установить заданные значения (!) принудительная установка
        for k,v in data.items():
            # если значение функция
            if callable(v):
                v = v(dv)
            dv.Set(k.strip('!'),v,force=k.endswith('!'))

    @classmethod
    def viewConstructor(cls,**kwargs):
        """
        Конструктор для создания метода-представления
        """
        def wrapper(self,sid,params):
            dv = self.get_cache(sid,kwargs["method_name"],"vars")
            langChanged = False
            if kwargs["groups"]:
                def group(*args,**kwargs):
                    if isinstance(kwargs.get('normal',()), (unicode, str)):
                        raise DataVarsError(_("Wrong normal varaiables list"))
                    if isinstance(kwargs.get('expert',()), (unicode, str)):
                        raise DataVarsError(_("Wrong expert varaiables list"))
                for gr in kwargs['groups']:
                    gr(group)
            if not dv:
                dv = getattr(self,"%s_vars"%kwargs["method_name"])()
                if hasattr(params,"clienttype"):
                    if params.clienttype == 'gui' and "guivars" in kwargs:
                        cls.modifyDatavars(dv,kwargs['guivars'])
                    if params.clienttype != 'gui' and "consolevars" in kwargs:
                        cls.modifyDatavars(dv,kwargs['consolevars'])
            else:
                # костыль для метода install, который меняет локализацию
                # интрефейса в зависимости от выбранного параметра lang
                if kwargs["method_name"] == 'install':
                    langChanged = self.fixInstallLocalization(sid,dv)
                    lang = dv.Get('install.os_install_locale_lang')
                    self.set_cache(sid,"install","lang",lang,smart=False)
                dv.processRefresh()
            self.set_cache(sid, kwargs["method_name"], "vars",dv,smart=False)
            if "brief" in kwargs and "name" in kwargs['brief']:
                brief_label = str(kwargs['brief']['name'])
            else:
                brief_label = None
            if kwargs["groups"]:
                view = ViewInfo(dv,viewparams=params,
                        has_brief="brief" in kwargs,
                        allsteps=langChanged,
                        brief_label=brief_label)
            else:
                view = ViewInfo()
            return view
        wrapper.func_name = "%s_view"%kwargs['method_name']
        return rpc(Integer, ViewParams, _returns = ViewInfo)(
               catchExcept(kwargs.get("native_error",()))(wrapper))
               
    @classmethod
    def datavarsConstructor(cls,**kwargs):
        """
        Конструктор для создания метода описания параметров
        """
        def wrapper(self,dv=None):
            if not dv:
                dv = DataVars()
                dv.importVariables()
                dv.importVariables('calculate.%s.variables'%kwargs['datavars'])
                dv.defaultModule = kwargs['datavars']
                dv.flIniFile()
                cls.modifyDatavars(dv,kwargs['setvars'])
            # созданием группы переменных из datavars согласно параметрам groups
            for groupfunc in kwargs['groups']:
                groupfunc(dv.addGroup)
            # указание brief если нужно
            if "brief" in kwargs:
                dv.addBrief(next_label=str(kwargs['brief'].get('next',_('Next'))),
                            image=kwargs['brief'].get('image',None))
            return dv
        return wrapper

class WsdlBase:
    """
    Базовый класс для автосоздания методов по описанию methods
    """
    __metaclass__ = WsdlMeta

def clearDataVars(func):
    def wrapper(*args,**kwargs):
        try:
            return func(*args,**kwargs)
        finally:
            WsdlMeta.closeDataVars()
    return wrapper
