#-*- 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
import OpenSSL

from soaplib.serializers.primitive import String, 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 (Field, GroupField,
                ViewInfo, ViewParams)
from func import uniq
from calculate.lib.datavars import VariableError
from calculate.lib.cl_lang import getLazyLocalTranslate, setLocalTranslate
setLocalTranslate('cl_core3',sys.modules[__name__])

from calculate.core import datavars
import traceback
__ = getLazyLocalTranslate(_)

class CertificateInfo(ClassSerializer):
    """Parameters for method install"""
    cl_page_count = String
    cl_page_offset = String

class DetailCertificateInfo(ClassSerializer):
    """Parameters for method install"""
    cl_cert_id = String
    cl_cert_rights = Array(String)

class CreateCertificateInfo(ClassSerializer):
    """Parameters for method install"""
    cl_cert_user = String
    cl_cert_rights = Array(String)
    cl_cert_rights_del = Array(String)

def catchExcept():
    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,selfobj,*args,**kwargs):
            try:
                return self.f(selfobj,*args,**kwargs)
            except BaseException as e:
                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)
                print "!!!!EXCEPTION!!!!"
                for i in apply(traceback.format_exception, sys.exc_info()):
                    print i
                return view
    return wrapper

class CoreWsdl:
    #def create_req_table(self, )
    def show_certs_meth (self, dv) :
        try:
            page_count = int(dv.Get('cl_page_count'))
            page_offset = int(dv.Get('cl_page_offset'))
            #self.printSUCCESS('Current offset = %d' %page_offset)

            if not page_offset:
                page_offset = 0

            list_cert_id = dv.Get('cl_list_cert_id')

            if not len(list_cert_id):
                self.printSUCCESS('No certificates')
                return True

            dict_cert_id = {}
            list_cert_id.sort()
            for i in range(len(list_cert_id)):
                dict_cert_id[i] = list_cert_id[i]
            max_id = len(list_cert_id)

            if not page_count:
                page_count = len(list_cert_id)

            head = [_('Certificates'),_('Groups'),_('Permissions')]
            body = []
            fields = ['cl_cert_id','']

            num_id = len(list_cert_id)
            if page_offset > num_id - 1:
                i = num_id - 1
            else:
                i = page_offset
            while True:
                if len(body) == page_count or i >= max_id:
                    break

                dv.Set('cl_cert_id', dict_cert_id[i])
                group_rights = ', '.join(dv.Get('cl_cert_perms'))
                cert_groups = ', '.join(dv.Get('cl_cert_groups'))
                body.append([str(dict_cert_id[i]),cert_groups,group_rights])
                i+=1

            if body:
                self.printTable(_("List of certificates"), head,
                                body, fields = fields,
                                onClick = 'core_detail_cert')
                if not page_offset:
                    return True
                count_page = len(list_cert_id) / page_count + 1
                num_page = page_offset / page_count + 1
                self.printSUCCESS(_('page %d from ')%num_page+str(count_page))
                return True
        except Exception,e:
            for i in apply(traceback.format_exception, sys.exc_info()):
                print i
            print 'Except: ', e
        return True

    def check_cert_params (self, dv, info,allvars=False,ordered=None):
        errors = []
        keys = sorted(filter(lambda x:x.lower() == x,
               info._type_info.keys()))
        if ordered:
            keys = ordered + filter(lambda x:not x in ordered,
                             keys)
        for var in keys:
            # get value of variable from info
            val = getattr(info, var)
            # check value if value send of check allvariables
            if val != None or allvars:
                try:
                    # if value not send, then get from datavars
                    if val == None:
                        val = dv.Get(var)
                    else:
                        uncomperr = dv.Uncompatible(var)
                        if uncomperr:
                            raise VariableError(uncomperr)
                    if not dv.Uncompatible(var):
                        dv.Set(var, val)
                except VariableError, e:
                    mess = ''
                    messages = e.message if type(e.message) == list \
                                         else [e.message]
                    for error in messages:
                        mess += str(error) + '\n'
                        errors.append(ReturnedMessage(type = 'error', 
                                                field = var, message = mess))
        return errors

    from calculate.core.server.decorators import Dec

    def certCommon(self,sid,info,methodname):
        """
        Install common method
        """
        try:
            dv = self.get_cache(sid,methodname,"vars")
            if not dv:
                #reload(cl_install)
                dv = datavars.DataVarsCore()
                dv.importCore()
                dv.flIniFile()
            errors = self.check_cert_params(dv, info,
                       ordered=['cl_page_count',
                                'cl_page_offset'],
                     allvars=True)
            if errors:
                return errors 
            cert_meth = type("certCommon",(self.Common,
                                CoreWsdl, object), {})
            pid = self.startprocess(sid, target=cert_meth,
                                    method="show_certs_meth",
                                    method_name='core_show_certs',
                                    auto_delete = True,
                                    args_proc = (dv,))
            returnmess = ReturnedMessage(type = 'pid', message = pid, \
                                         expert = True)
            returnmess.type = "pid"
            returnmess.message = pid
            dv = self.clear_cache(sid,methodname)
            return [returnmess]
        finally:
            if dv:
                self.set_cache(sid,methodname,"vars",dv,smart=False)
        return []

    @rpc(Integer, CertificateInfo, _returns = Array(ReturnedMessage))
    @Dec.core_method(gui=True, title=__('Show certificates'),
                     category=__('Utilities'),\
                     image='certificate-server,application-certificate',
                     command='cl-core-view-cert',rights=["certificates"])
    def core_show_certs(self, sid, info):
        if not info:
            mess = 'Field must be int!'
            errors = []
            for field in ['cl_page_count', 'cl_page_offset']:
                errors.append(ReturnedMessage(type = 'error', field = field,
                                      message = mess, expert = True))
            return errors
        dv = datavars.DataVarsCore()
        dv.importCore()
        dv.flIniFile()
        dv.Set('cl_page_count', info.cl_page_count)
        dv.Set('cl_page_offset', info.cl_page_offset)
        self.set_cache(sid, 'core_show_certs', "vars", dv, smart=False)
        return self.certCommon(sid,info,'core_show_certs')

    @rpc(Integer, ViewParams,_returns = ViewInfo)
    @catchExcept()
    def core_show_certs_view (self, sid, params):
        dv = datavars.DataVarsCore()
        dv.importCore()
        dv.flIniFile()
        dv.addGroup(_("Certificates"),
            normal=('cl_page_count','cl_page_offset'),
            next_label=_("Next"))
        view = ViewInfo(dv,viewparams=params)
        self.set_cache(sid, 'core_show_certs', "vars", dv, smart=False)
        return view

##################### BEGIN DETAIL GROUP METHOD ##############################
    @rpc(Integer, DetailCertificateInfo, _returns = Array(ReturnedMessage))
    @Dec.core_method(gui=True, title=__('Certificate details'),
                     rights=["certificates"])
    def core_detail_cert ( self, sid, info):
        if not info:
            mess = 'Field must be in list!'
            errors = []
            errors.append(ReturnedMessage(type = 'error',
                                          field = 'cl_cert_id',
                                          message = mess))
            return errors

        dv = datavars.DataVarsCore()
        dv.importCore()
        dv.flIniFile()
        try:
            dv.Set('cl_cert_id', info.cl_cert_id)
        except VariableError, e:
            return [ReturnedMessage(type = 'error', field = 'cl_cert_id',
                                    message = e.message)]
        self.set_cache(sid, 'core_detail_cert', 'dv', dv, smart = False)
        return []

    @rpc(Integer, ViewParams, _returns = ViewInfo)
    @catchExcept()
    def core_detail_cert_view (self, sid, params):
        dv = self.get_cache(sid, 'core_detail_cert', 'dv')
        if not dv:
            dv = datavars.DataVarsCore()
            dv.importCore()
            dv.flIniFile()
            dv.Get('cl_cert_id')

        dv.addGroup(None,
            normal=('cl_cert_id', 'cl_cert_groups', 'cl_cert_perms'))

        view = ViewInfo(dv,viewparams=params)

        group = GroupField(name='',last=True)
        group.fields = []
        group.fields.append(Field(
            name = "but0",
            label = _("Back"),
            value = "core_show_certs",
            element = "button"))
#        group.fields.append(Field(
#            name = "but1",
#            label = _("Change"),
#            value = "core_change_cert",
#            element = "button"))
#        group.fields.append(Field(
#            name = "but2",
#            label = _("Delete"),
#            value = "core_del_group",
#            element = "button"))
        view.groups.append(group)
        self.set_cache(sid, 'core_show_certs', "vars", dv, smart=False)
        return view

############## END DETAIL GROUP METHOD #######################################

#    def changeCertPermCommon(self,sid,info,methodname):
#        try:
#            dv = self.get_cache(sid,methodname,"vars")
#            errors = self.check_group_params(dv, info,
#                       ordered=['cl_cert_id','cl_cert_perms'],
#                       allvars=True)
#            if errors:
#                return errors
#            cert_meth = type("changeCertPermCommon",(self.Common,
#                                CoreWsdl, object), {})
#            pid = self.startprocess(sid, target=cert_meth,
#                                method="change_cert_meth",
#                                method_name='core_change_cert',
#                                args_proc = (dv,))
#            returnmess = ReturnedMessage(type = 'pid', message = pid)
#            returnmess.type = "pid"
#            returnmess.message = pid
#            dv = self.clear_cache(sid,methodname)
#            return [returnmess]
#        finally:
#            if dv:
#                self.set_cache(sid,methodname,"vars",dv,smart=False)
#        return []
#
#    def change_cert_meth(self, dv):
#        try:
#            group_rights_file = dv.Get('cl_core_group_rights')
#
#            cl_group_name = str(dv.Get('cl_group_name'))
#            cl_group_rights = dv.Get('cl_group_rights')
#            #self.startTask('Request confirmation')
#            changed_flag = False
#            result = []
#
#            for line in readLinesFile(group_rights_file):
#                if line.startswith('#') or not line:
#                    result.append(line)
#                    continue
#                words = line.split(' ',1)
#                # first word in line equal name input method
#                if words[0] == cl_group_name:
#                    line = cl_group_name + ' ' + ','.join(cl_group_rights)
#                    changed_flag = True
#                result.append(line)
#
#            if cl_group_name == 'all' and not changed_flag:
#                result.append(cl_group_name + ' ' + ','.join(cl_group_rights))
#                changed_flag = True
#
#            fd = open (group_rights_file, 'w')
#            for lines in result:
#                fd.write(lines + '\n')
#            fd.close()
#
#            if changed_flag:
#                self.printSUCCESS ('<b>'+_('Group changed')+'</b>')
#            else:
#                self.printSUCCESS ('<b>'+ _('Group not changed')+'</b>')
#            self.printSUCCESS (_('Group name') + " = %s" %cl_group_name)
#            self.printSUCCESS (_('Group permissions') + " = %s" 
#                               %','.join(cl_group_rights))
#            return True
#        except (KeyboardInterrupt,):
#            self.printERROR('Process is interrupted!')
#            return False
#
#    @rpc(Integer, DetailCertificateInfo, _returns = Array(ReturnedMessage))
#    @Dec.core_method(gui=True, title=__('Change the certificate permissions'),
#                     command='cl-core-change-cert',rights=["certificates"])
#    @catchExcept()
#    def core_change_cert ( self, sid, info):
#        dv = self.get_cache(sid,'core_change_cert',"vars")
#        if not dv:
#            dv = datavars.DataVarsCore()
#            dv.importCore()
#            dv.flIniFile()
#        not_cert_msg = [ReturnedMessage(type='error', field='cl_cert_id',\
#                         message = _('use --group-name to select the '
#                         'certificate number'))]
#        if not info:
#            return not_cert_msg
#        if not info.cl_cert_id:
#            return not_cert_msg
#        try:
#            dv.Set('cl_cert_id', info.cl_group_name)
#        except VariableError, e:
#            return [ReturnedMessage(type = 'error', message = e.message, \
#                                    field = 'cl_group_name')]
#        if info.cl_group_rights == None:
#            return [ReturnedMessage(type='error', field='cl_group_rights',\
#                    message=_("use option --group-rights to toggle permissions"))]
#        try:
#            dv.Set('cl_group_rights', info.cl_group_rights)
#        except VariableError, e:
#            return [ReturnedMessage(type = 'error', message = e.message, \
#                                    field = 'cl_group_rights')]
#        self.set_cache(sid, 'core_change_cert', "vars", dv, smart=False)
#        return self.changeCertPermCommon(sid,info,'core_change_cert')
#
#    @rpc(Integer, ViewParams, _returns = ViewInfo)
#    @catchExcept()
#    def core_change_group_view (self, sid, params):
#        dv = self.get_cache(sid, 'core_change_cert', 'dv')
#        if not dv:
#            dv = datavars.DataVarsCore()
#            dv.importCore()
#            dv.flIniFile()
#            dv.Get('cl_group_name')
#
#        dv.addGroup(_("Toggle groups"),
#            normal=('cl_group_name', 'cl_group_rights'),
#            next_label=_("Done"))
#
#        view = ViewInfo(dv)
#
#        group = GroupField(name=_("Toggle groups"), nextlabel=_("Done"), \
#                           last=True)
#        group.fields = []
#        group.fields.append(Field(
#            name = "but2",
#            label = "Confirm",
#            value = "core_change_cert",
#            element = "button"))
#        view.groups.append(group)
#        self.set_cache(sid, 'core_change_cert', "vars", dv, smart=False)
#        return view

    def create_certs_meth (self, dv) :
        try:
            page_count = int(dv.Get('cl_page_count'))
            page_offset = int(dv.Get('cl_page_offset'))
            #self.printSUCCESS('Current offset = %d' %page_offset)

            if not page_offset:
                page_offset = 0

            list_cert_id = dv.Get('cl_list_cert_id')

            if not len(list_cert_id):
                self.printSUCCESS('No certificates')
                return True

            dict_cert_id = {}
            list_cert_id.sort()
            for i in range(len(list_cert_id)):
                dict_cert_id[i] = list_cert_id[i]
            max_id = len(list_cert_id)

            if not page_count:
                page_count = len(list_cert_id)

            head = [_('Certificates'),_('Groups'),_('Permissions')]
            body = []
            fields = ['cl_cert_id','']

            num_id = len(list_cert_id)
            if page_offset > num_id - 1:
                i = num_id - 1
            else:
                i = page_offset
            while True:
                if len(body) == page_count or i >= max_id:
                    break

                dv.Set('cl_cert_id', dict_cert_id[i])
                group_rights = ', '.join(dv.Get('cl_cert_perms'))
                cert_groups = ', '.join(dv.Get('cl_cert_groups'))
                body.append([str(dict_cert_id[i]),cert_groups,group_rights])
                i+=1

            if body:
                self.printTable(_("List of certificates"), head,
                                body, fields = fields,
                                onClick = 'core_detail_cert')
                if not page_offset:
                    return True
                count_page = len(list_cert_id) / page_count + 1
                num_page = page_offset / page_count + 1
                self.printSUCCESS(_('page %d from ')%num_page+str(count_page))
                return True
        except Exception,e:
            for i in apply(traceback.format_exception, sys.exc_info()):
                print i
            print 'Except: ', e
        return True

    def createCertCommon(self,sid,info,methodname):
        """
        Install common method
        """
        try:
            dv = self.get_cache(sid,methodname,"vars")
            if not dv:
                #reload(cl_install)
                dv = datavars.DataVarsCore()
                dv.importCore()
                dv.flIniFile()
            errors = self.check_cert_params(dv, info,
                                ordered=['cl_cert_user', 'cl_cert_rights',
                                'cl_cert_rights_del'],
                                allvars=True)
            if errors:
                return errors
            cert_meth = type("createCertCommon",(self.Common,
                                CoreWsdl, object), {})
            pid = self.startprocess(sid, target=cert_meth,
                                    method="create_certs_meth",
                                    method_name='core_create_certs',
                                    auto_delete = True,
                                    args_proc = (dv,))
            returnmess = ReturnedMessage(type = 'pid', message = pid, \
                                         expert = True)
            returnmess.type = "pid"
            returnmess.message = pid
            dv = self.clear_cache(sid,methodname)
            return [returnmess]
        finally:
            if dv:
                self.set_cache(sid,methodname,"vars",dv,smart=False)
        return []

#    @rpc(Integer, CreateCertificateInfo, _returns = Array(ReturnedMessage))
#    @Dec.core_method(gui=True, title=__('Creating a Certificate'),
#                     category=__('Utilities'),\
#                     image='view-certificate-add,certificate-server,'
#                     'application-certificate',
#                     command='cl-core-view-cert',rights=["certificates"])
#    def core_create_certs(self, sid, info):
#        if not info:
#            mess = 'Field must be int!'
#            errors = []
#            for field in ['cl_page_count', 'cl_page_offset']:
#                errors.append(ReturnedMessage(type = 'error', field = field,
#                                      message = mess, expert = True))
#            return errors
#        dv = datavars.DataVarsCore()
#        dv.importCore()
#        dv.flIniFile()
#        dv.Set('cl_page_count', info.cl_page_count)
#        dv.Set('cl_page_offset', info.cl_page_offset)
#        self.set_cache(sid, 'core_create_certs', "vars", dv, smart=False)
#        return self.certCommon(sid,info,'core_create_certs')
#
#    @rpc(Integer, ViewParams,_returns = ViewInfo)
#    @catchExcept()
#    def core_create_certs_view (self, sid, params):
#        dv = datavars.DataVarsCore()
#        dv.importCore()
#        dv.flIniFile()
#        dv.addGroup(_("Creating a Certificate"),
#            normal=('cl_page_count','cl_page_offset'),
#            next_label=_("Create"))
#        view = ViewInfo(dv)
#        self.set_cache(sid, 'core_create_certs', "vars", dv, smart=False)
#        return view
