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

# Copyright 2010-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 sys, os
from shutil import copy2
import importlib
import re

from soaplib.serializers.primitive import String, Boolean, Integer
from soaplib.serializers.clazz import Array, ClassSerializer
from soaplib.service import rpc
from calculate.core.server.api_types import ReturnedMessage
from calculate.core.server.api_types import ViewInfo, ViewParams
from calculate.core.server.decorators import Dec
from calculate.core.server.func import catchExcept
core_method = Dec.core_method

from calculate.core.datavars import DataVarsCore
from calculate.lib.datavars import Variable,DataVarsError,VariableError
from calculate.lib.cl_log import log
from calculate.lib import datavars
from calculate.lib.utils.files import (scanDirectory, pathJoin)
from calculate.lib.utils.common import getPasswdUsers
import pwd
from calculate.lib.utils.files import getModeFile
import calculate.lib.cl_template as cl_template

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

__ = getLazyLocalTranslate(_)

setvarsCatchExcept = catchExcept(VariableError,DataVarsError)

class SetVariablesInfo(ClassSerializer):
    """Parameters for method set variables"""
    cl_variable_data = Array(Array(String))
    cl_variable_filter = String
    cl_variable_show = String

    Default = Array(String)
    CheckOnly = Boolean

VARIABLE,MODE,LOCATION,VALUE = 0,1,2,3

class SetVariables:
    def writeVariables(self,dv):
        """
        Write variable to env files, or delete from env files
        """
        data = filter(lambda x:x[LOCATION] or \
                    not x[LOCATION] and \
                    dv.isFromIni(x[VARIABLE].rpartition('.')[2]),
               dv.Get('cl_variable_data'))
        if data:
            head = [_("Variable"),_("Mode"), _("Location"),
                    _("Value")]
            self.printTable(_("List of variables"), head, data)
            for varname,mode,location,value in data:
                if location:
                    value = dv.unserialize(dv.getInfo(varname).type,str(value))
                section,op,varname = varname.rpartition('.')
                if not location:
                    for location in dv.Get('main.cl_env_location'):
                        if not dv.Delete(varname,location,header=section):
                            self.printWARNING(
                                _("Failed to delete variable {var} from {location}").format(
                                  var=varname,location=location))
                else:
                    dv.Write(varname,value,location=location,header=section)
        else:
            self.printSUCCESS("Nothing to set")
        return True

    def showVariables(self,dv):
        """
        Show variables by cl_variable_filter
        """
        removeQuotes = lambda x: x if x != "''" else ""
        reIndex = re.compile("((?:\w+\.)?(\w+))(?:\[(\d+)\])")
        showVal = dv.Get('cl_variable_show')
        if showVal:
            index = reIndex.search(showVal)
            if index:
                varname = index.group(1)
                index = int(index.group(3))
            else:
                varname = showVal
            prevVal = str(dv.Select('cl_variable_value',
                          where='cl_variable_fullname',
                          eq=varname,limit=1))
            if not index is None:
                typeVar = dv.getInfo(varname).type
                val = dv.unserialize(typeVar,prevVal)
                if index < len(val):
                    self.printDefault(removeQuotes(val[index]))
                else:
                    self.printDefault("")
            else:
                self.printDefault(removeQuotes(prevVal))
            return True
        filterVal = dv.Get('cl_variable_filter')
        filterFunc = \
            {'all':None,
             'userset' :lambda x:x[LOCATION],
             'writable':lambda x:x[MODE].startswith("w"),
             'system'  :lambda x:x[LOCATION] == "system",
             'local'   :lambda x:x[LOCATION] == "local",
             'remote'  :lambda x:x[LOCATION] == "remote"}.get(filterVal,
                        lambda x:filterVal in x[VARIABLE])
        body = filter(filterFunc,
               dv.Get('cl_variable_data'))
        dv.close()
        if body:
            head = [_("Variable"),_("Mode"),
                    _("Location"),_("Value")]
            self.printTable(_("List of variables"), head, body)
            return True
        else:
            self.printWARNING(_("No such variables"))
        return True

class CoreWsdl:
    """
    cl-core-variables
    """
    @rpc(Integer, SetVariablesInfo, _returns = Array(ReturnedMessage))
    @core_method(category=__('Utilities'),title=__('Setup variables'),
        image='applications-system',
        gui=True,command='cl-core-variables',
        rights=['configure'])
    def variables(self, sid, info):
        return self.callMethod(sid,info,method_name="variables",
                               logicClass=SetVariables,
                               method="writeVariables")

    def variables_vars(self,dv=None):
        if not dv:
            dv = DataVarsCore()
            dv.importCore()
            dv.flIniFile()
        dv.addGroup(None,
            normal=('cl_variable_data',),
            next_label=_("Save"))
        return dv

    @rpc(Integer, ViewParams,_returns = ViewInfo)
    def variables_view (self, sid, params):
        dv = self.get_cache(sid,"variables","vars")
        if not dv:
            dv = self.variables_vars()
        else:
            dv.processRefresh()
        view = ViewInfo(dv,viewparams=params)
        self.set_cache(sid, 'variables', "vars",dv,smart=False)
        return view

    """
    cl-core-variables-show
    """
    @rpc(Integer, SetVariablesInfo, _returns = Array(ReturnedMessage))
    @core_method(category=__('Utilities'),title=__('View variables'),
        image='applications-system',
        gui=False,command='cl-core-variables-show',
        rights=['configure'])
    def variables_show(self, sid, info):
        return self.callMethod(sid,info,method_name="variables_show",
                               logicClass=SetVariables,
                               method="showVariables")

    def variables_show_vars(self,dv=None):
        if not dv:
            dv = DataVarsCore()
            dv.importCore()
            dv.flIniFile()
        dv.addGroup(None,
            normal=('cl_variable_filter','cl_variable_show'),
            next_label=_("Show"))
        return dv

    @rpc(Integer, ViewParams,_returns = ViewInfo)
    @setvarsCatchExcept
    def variables_show_view (self, sid, params):
        dv = self.get_cache(sid,"variables_show","vars")
        if not dv:
            dv = self.variables_show_vars()
        else:
            dv.processRefresh()
        view = ViewInfo(dv,viewparams=params)
        self.set_cache(sid, 'variables_show', "vars",dv,smart=False)
        return view
