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

# Copyright 2008-2012 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 os,sys


from cl_print import color_print

from calculate.lib.cl_lang import setLocalTranslate
setLocalTranslate('cl_lib3',sys.modules[__name__])

import cl_overriding
from datavars import DataVars

class APIError(Exception):
        """Класс ошибок"""

class libVars:

    clLibVars = False

    def createClLibVars(self, clLibVars=False):
        """Создает объект библиотечных переменных"""
        if not clLibVars:
            clLibVars = DataVars()
            # Заменяем значения переменных переменными из env файлов
            clLibVars.flIniFile()
            # Устанавливаем у объекта атрибут объект переменных
            self.clLibVars = clLibVars
        return True

class _services(color_print, libVars):

    def __init__(self):
        self.apiObjs = {}

    def getApiClass(self, apiFile):
        importPath, moduleName = os.path.split(apiFile)
        moduleName = moduleName.rpartition(".py")[0]
        if not importPath in sys.path:
            sys.path.insert(0, importPath)
        try:
            className = getattr(__import__(moduleName,
                                            globals(), locals(),
                                            ['serviceAPI']),
                                'serviceAPI')
        except (ImportError, AttributeError), e:
            self.printERROR(str(e).strip())
            self.printERROR(_("Failed to import module %s")% apiFile)
            cl_overriding.exit(1)
        return className

    def getPkgApi(self, pkgName):
        """get package api"""
        if not pkgName in self.apiObjs:
            self.createClLibVars(clLibVars=self.clLibVars)
            apiDict = self.clLibVars.Get('cl_api')
            if not apiDict or not type(apiDict) is dict:
                return None
            if not pkgName in apiDict:
                return None
            apiFile = apiDict[pkgName]
            className = self.getApiClass(apiFile)
            try:
                apiObject = className()
            except Exception, e:
                self.printERROR(str(e).strip())
                self.printERROR(_("Failed to create an API object"))
                self.printERROR(_("Module %s")% apiFile)
                cl_overriding.exit(1)
            self.apiObjs[pkgName] = apiObject
            return apiObject
        else:
            return self.apiObjs[pkgName]

    def getAllPkgApi(self):
        """get all packages api objects"""
        self.createClLibVars(clLibVars=self.clLibVars)
        apiDict = self.clLibVars.Get('cl_api')
        if not apiDict or not type(apiDict) is dict:
            return []
        apiFiles = apiDict.values()
        apiObjects = []
        for apiFile  in apiFiles:
            className = self.getApiClass(apiFile)
            try:
                apiObjects.append(className())
            except:
                self.printERROR(_("Failed to create an API object"))
                self.printERROR(_("Module %s")% apiFile)
                cl_overriding.exit(1)
        return apiObjects

    def runMethodToPkg(self, pkgName, methodName,  argv=[]):
        """Execute method from pkg"""
        pkgObj = self.getPkgApi(pkgName)
        if pkgObj is None:
            return ""
        if not hasattr(pkgObj, methodName) or\
            not callable(getattr(pkgObj, methodName)):
            self.printERROR(_("Method %(method)s not found in the API "
                              "object of service %(service)s")
                              %{'method':methodName,
                                'service':pkgObj.getServiceName()})
            cl_overriding.exit(1)
        if argv:
            res = getattr(pkgObj, methodName)(*argv)
        else:
            res = getattr(pkgObj, methodName)()
        return res

class attribute(object):
    def __init__(self, clVars):
        self._varsObj=clVars


    def __getattribute__(self, attr):
        if attr.startswith("__"):
            value = object.__getattribute__(self, attr)
        else:
            try:
                value = object.__getattribute__(self,'_varsObj').Get(attr)
            except Exception, e:
                #value = ""
                raise APIError(str(e).strip())
            object.__setattr__(self, attr, value)
        return value

    def __setattr__(self, attr, value):
        if attr.startswith("__") or attr=="_varsObj":
            object.__setattr__(self, attr, value)
        else:
            try:
               varObj = object.__getattribute__(self,'_varsObj')
               if varObj.Set(attr, value) is False:
                    raise AttributeError(attr)
            except:
                raise AttributeError(attr)

class _pkgAPI(object):

    def __init__(self, pkgName):
        self._pkgName = pkgName


    def __setvar__(self, pkgName):
        services = _services()
        varObj = services.runMethodToPkg(pkgName, 'get_vars')
        if varObj:
            self.var = attribute(varObj)

    def __setmethods__(self, pkgName):
        services = _services()
        pkgObj = services.getPkgApi(pkgName)
        for attr in dir(pkgObj):
            if not attr.startswith("_") and callable(getattr(pkgObj, attr)) and\
                getattr(pkgObj, attr).im_func.func_code.co_argcount == 1:
                setattr(self, attr, getattr(pkgObj, attr))

    def __getattribute__(self, attr):
        if attr.startswith("__") or attr in ('_pkgName'):
            value = object.__getattribute__(self, attr)
        elif attr == 'var':
            try:
                value = object.__getattribute__(self, attr)
            except AttributeError:
                pkgName  = object.__getattribute__(self, '_pkgName')
                self.__setvar__(pkgName)
                value = object.__getattribute__(self, attr)
        elif attr == 'api':
            try:
                value = object.__getattribute__(self, attr)
            except AttributeError:
                services = _services()
                pkgName  = object.__getattribute__(self, '_pkgName')
                value = services.getPkgApi(pkgName)
                setattr(self, attr, value)
        else:
            try:
                value = object.__getattribute__(self, attr)()
                flagFoundAttr = True
            except:
                flagFoundAttr = False
            if flagFoundAttr is False:
                pkgName  = object.__getattribute__(self, '_pkgName')
                self.__setmethods__(pkgName)
                try:
                    value = object.__getattribute__(self, attr)()
                except:
                    raise APIError(_("Method %s not found")%attr)
        return value

class _allPkg(object):

    def __init__(self, listPkgObj):
        def smpPrioritetReverse(objectA, objectB):
            '''Comparison of the run priorities of objects

            to sort in descending order
            '''
            prioritetA = objectA.get_prioritet()
            prioritetB = objectB.get_prioritet()
            if prioritetA == prioritetB:
                return 0
            elif prioritetA < prioritetB:
                return 1
            else:
                return -1

        def smpPrioritetNormal(objectA, objectB):
            '''Comparison of the run priorities of objects

            to sort in descending order
            '''
            prioritetA = objectA.get_prioritet()
            prioritetB = objectB.get_prioritet()
            if prioritetA == prioritetB:
                return 0
            elif prioritetA > prioritetB:
                return 1
            else:
                return -1

        self._listPkgObjNormal = listPkgObj[:]
        self._listPkgObjNormal.sort(smpPrioritetNormal)
        self._listPkgObjReverse = listPkgObj[:]
        self._listPkgObjReverse.sort(smpPrioritetReverse)

    def APIList(self):
        return self._listPkgObjNormal

    def APIListReverse(self):
        return self._listPkgObjReverse

    def __getattribute__(self, attr):
        if attr.startswith("__") or\
            attr in ('_listPkgObjNormal', '_listPkgObjReverse',
                     'APIList', 'APIListReverse'):
            value = object.__getattribute__(self, attr)
        else:
            if attr.startswith('stop') or attr.startswith('del'):
                listObi = object.__getattribute__(self, '_listPkgObjReverse')
            else:
                listObi = object.__getattribute__(self,'_listPkgObjNormal')
            listValues = []
            for pkgObj in listObi:
                try:
                    val = getattr(pkgObj, attr)
                except Exception, e:
                    continue 
                listValues.append(val)
            if filter(lambda x: set(listValues) == set(x),
                        ([True],[False],[True,False])):
                if False in listValues:
                    return False
                else:
                    return True
            listValues = filter(lambda x: x, listValues)
            listValues = map(lambda x: '1' if x is True else str(x), listValues)
            value = "\n".join(listValues)
            object.__setattr__(self, attr, value)
        return value

class packagesAPI(object):

    def __getattribute__(self, attr):
        if attr.startswith("__"):
            value = object.__getattribute__(self, attr)
        else:
            try:
                value = object.__getattribute__(self, attr)
                flagFoundAttr = True
            except AttributeError:
                flagFoundAttr = False
            if flagFoundAttr is False:
                objLibVars = libVars()
                objLibVars.createClLibVars()
                apiDict = objLibVars.clLibVars.Get('cl_api')
                listPkgObj = []
                for pkgName in apiDict.keys():
                    pkgAPIObj = _pkgAPI(pkgName)
                    setattr(self, pkgName.replace('-','_'), pkgAPIObj)
                    listPkgObj.append(pkgAPIObj)
                setattr(self, 'all', _allPkg(listPkgObj))
                value = object.__getattribute__(self, attr)
        return value
