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

# Copyright 2011-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.

from calculate.lib.datavars import Variable, ReadonlyVariable, VariableError
import os
import sys

from calculate.lib.cl_lang import setLocalTranslate
from calculate.lib.utils.files import pathJoin, listDirectory, readFile
from calculate.core.server.loaded_methods import LoadedMethods
from calculate.core.server.func import uniq

_ = lambda x: x
setLocalTranslate('cl_core3', sys.modules[__name__])


class VariableClListCertId(ReadonlyVariable):
    def get(self):
        cert_dir = self.Get('cl_core_client_certs_path')
        return map(lambda x: x[:-4],
                   filter(lambda x: x.endswith('.crt'),
                          listDirectory(cert_dir)))


class VariableClCertId(Variable):
    """
    Certificate Identification
    """
    type = "choice"
    opt = ["-c"]
    metavalue = "CERT_ID"

    def init(self):
        self.help = _("Certificate identifier")
        self.label = _("Certificate identifier")

    def choice(self):
        return self.Get('cl_list_cert_id')

    def check(self, cert_id):
        #        if cert_id != 'all':
        try:
            int(cert_id)
        except ValueError:
            raise VariableError(_("The certificate ID must be int"))

        list_certs_id = self.Get('cl_list_cert_id')
        if cert_id not in list_certs_id:
            raise VariableError(_("The certificate with ID %s not exists")
                                % cert_id)


class VariableClCertPerms(Variable):
    """
    Certificate Permissions
    """
    type = "choice-list"
    opt = ["--cert-perm"]
    metavalue = "perm[,perm2[..]]"

    def init(self):
        self.help = _("Certificate permissions")
        self.label = _("Certificate permissions")

    def choice(self):
        right_list = []
        for key in LoadedMethods.rightsMethods.keys():
            right_list += LoadedMethods.rightsMethods[key]

        uniq_right_list = uniq(right_list)
        uniq_right_list.sort()
        return uniq_right_list

    def get(self):
        cert_id = self.Get('cl_cert_id')
        groups_list = self.Get('cl_cert_groups')

        group_rights = self.Get('cl_core_group_rights_path')
        rights = self.Get('cl_core_rights')
        # if group = all and not redefined group all
        results = []
        if 'all' in groups_list:
            find_flag = False
            fd = open(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:
                right_list = []
                for key in LoadedMethods.rightsMethods.keys():
                    right_list += LoadedMethods.rightsMethods[key]

                uniq_right_list = uniq(right_list)
                uniq_right_list.sort()
                return uniq_right_list

        else:
            if not os.path.exists(group_rights):
                return ["No Methods"]
            with open(group_rights) as fd:
                t = fd.read()
                for line in t.splitlines():
                    if not line:
                        continue
                    words = line.split(' ', 1)
                    # 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())

            results = uniq(results)

            add_list_rights = []
            del_list_rights = []

            t = readFile(rights)
            for line in t.splitlines():
                words = line.split()
                meth = words[0]
                for word in words:
                    try:
                        word = int(word)
                    except ValueError:
                        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 not results:
                results.append("No Methods")

        return results

    def uncompatible(self):
        return _('You cannot change the certificate permissions')


class VariableClCertGroups(Variable):
    """
    Certificate Groups
    """
    type = "choice-list"
    #    opt = ["--cert-group"]
    #    metavalue = "perm[,perm2[..]]"

    def init(self):
        self.help = _("Certificate groups")
        self.label = _("Certificate groups")

    def choice(self):
        group_rights = self.Get('cl_core_group_rights_path')

        with open(group_rights, 'r') as f:
            t = f.read()
            result = []
            for line in t.splitlines():
                words = line.split()
                if words and len(words):
                    if not words[0].startswith('#'):
                        result.append(words[0])
            if 'all' not in result:
                result.append('all')
        return result

    def get(self):
        try:
            import OpenSSL

            try:
                cert_file = self.Get('cl_cert_crt_path')

                with open(cert_file, 'r') as f:
                    cert = f.read()
                certobj = OpenSSL.crypto.load_certificate(
                    OpenSSL.SSL.FILETYPE_PEM, cert)
                com = certobj.get_extension(
                    certobj.get_extension_count() - 1).get_data()
                groups = com.rpartition(':')[2]
                groups_list = groups.split(',')
                return groups_list
            except OpenSSL.crypto.Error:
                return []
        except (IOError, ImportError):
            return []

    def uncompatible(self):
        return _('You cannot change the certificate permissions')


class VariableClCertCrtPath(Variable):
    """
    Путь до сертификата (при указании иденификатора сертификата)
    """

    def get(self):
        return pathJoin(self.Get('cl_core_client_certs_path'),
                        "%s.crt" % self.Get('cl_cert_id'))
