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

# Copyright 2016 Mir Calculate. http://www.calculate-linux.org
#
#  Licensed under the Apache License, Version 2.0 (the "License");
#  you may not use this file except in compliance with the License.
#  You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
#  Unless required by applicable law or agreed to in writing, software
#  distributed under the License is distributed on an "AS IS" BASIS,
#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#  See the License for the specific language governing permissions and
#  limitations under the License.

import sys
from calculate.lib.datavars import (ReadonlyVariable, Variable,
                                    VariableInterface, VariableError)
from calculate.lib.utils.common import genpassword
from calculate.ldap.tools import SlapPasswd
from calculate.lib.utils.tools import repeater
from calculate.lib.cl_ldap import LDAPConnect, LDAPConnectError, ldap
from calculate.lib.configparser import (ConfigParserCaseSensLocked,
                                        Error as ConfigParserError)

_ = lambda x: x
from calculate.lib.cl_lang import (setLocalTranslate, getLazyLocalTranslate)

setLocalTranslate('cl_ldap3', sys.modules[__name__])
__ = getLazyLocalTranslate(_)


class ServerEnvHelper(VariableInterface):
    """
    Получение значений из env файла или fallback
    """
    fallback_variable = ""
    fallback_value = ""
    service = ""
    parameter = ""

    def get(self):
        cp_path = self.Get('server.cl_server_env_path')
        cp = ConfigParserCaseSensLocked(cp_path)
        try:
            with cp.lock_read() as cp:
                value = cp.get(self.service, self.parameter,
                               fallback=None)
            if value is None:
                if self.fallback_variable:
                    return self.Get(self.fallback_variable)
                else:
                    return self.fallback_value
            else:
                return value.encode('utf-8')
        except ConfigParserError:
            raise VariableError(_("Failed to remove server parameters"))


class LdapMaxHelper(VariableInterface):
    """
    Получение максимального значение из среди атрибутов
    """
    type = "int"
    base_dn = ""
    search_filter = ""
    attr = ""

    def get_max(self):
        ldap_connect = self.Get('ldap.cl_ldap_connect')
        if ldap_connect:
            base_dn = self._value_formatter.format(self.base_dn, self.Get)
            try:
                return max(int(x) for x in ldap_connect.ldap_simple_search(
                    base_dn, self.search_filter, self.attr) if x.isdigit())
            # max(empty_list)
            except ValueError:
                return None
        else:
            return None

    def get(self):
        return str(self.get_max() or "")


class LdapSearchHelper(VariableInterface):
    """
    Проверка свободен ли указанный идентификатор
    """
    base_dn = ""
    search_filter = "uid={value}"

    def value_get(self, value):
        def get_wrapper(val):
            if val == "value":
                return value
            else:
                return self.Get(val)

        return get_wrapper

    def check_name(self, value):
        ldap_connect = self.Get('ldap.cl_ldap_connect')
        if ldap_connect:
            base_dn = self._value_formatter.format(self.base_dn,
                                                   self.value_get(value))
            search_filter = self._value_formatter.format(self.search_filter,
                                                         self.value_get(value))
            return any(ldap_connect.ldap_search(
                base_dn, ldap.SCOPE_ONELEVEL, search_filter))
        else:
            return None


class HashHelper(VariableInterface):
    """
    Хэш пароля для LDAP
    """
    source = ""
    hash_var = "ldap.ld_encrypt"

    def get(self):
        value = self.Get(self.source)
        if value:
            return SlapPasswd(self.Get(self.hash_var)).get_hash(value)
        else:
            return "crypt{xxx}"


class RandomPasswordHelper(VariableInterface):
    """
    Генератор пароля
    """
    password_len = 9

    def get(self):
        return genpassword(self.password_len).strip()
