#!/usr/bin/python
#-*- coding: utf-8 -*-

# Copyright 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 cert_cmd

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

_('User should be root')
_('Failed to import %s')
_('No module named %s')

def main(*args, **keywords):
    parser = cert_cmd.parse()
    args, unknown_args = parser.parse_known_args()

    if os.path.basename(sys.argv[0]) != 'cl-core':
        args.method = '_temp_'

    if not args.method:
        if unknown_args:
            args = parser.parse_args()

    if args.help and not args.method:
        parser.print_help()
        return 0

    if args.variable:
        cert_cmd.print_variable(args.variable,args.human_readable)
        return 0
    if args.write_variable:
        cert_cmd.write_variable(args.write_variable)
        return 0
    if args.append_variable:
        cert_cmd.append_variable(args.append_variable)
        return 0
    port = args.port

    from calculate.core.datavars import DataVarsCore
    ob = DataVarsCore()
    ob.importCore()

    # set var env
    if not ob.flIniFile():
        sys.exit(1)
#    cl_wsdl = ob.Get('cl_wsdl')
    cl_wsdl = ob.Get('cl_wsdl_available')
    data_path = ob.Get('cl_core_data')
    certbase = ob.Get('cl_core_database')
    serv_certbase = ob.Get('cl_core_serv_database')
    rights = ob.Get('cl_core_rights')
    group_rights = ob.Get('cl_core_group_rights')
    sids = ob.Get('cl_core_sids_path')
    pids = ob.Get('cl_core_pids_path')
    sids_pids = ob.Get('cl_core_sids_pids')
    sids_file = ob.Get('cl_core_sids_file')
    pids_file = ob.Get('cl_core_pids_file')
    max_sid = ob.Get('cl_core_max_sid')
    max_pid = ob.Get('cl_core_max_pid')
    cert_path = ob.Get('cl_core_cert_path')
    cert = ob.Get('cl_core_cert')
    key = ob.Get('cl_core_key')
    cl_ver = ob.Get('cl_ver')
    log_path_var = ob.Get('cl_log_path')

    if args.version:
        print cl_ver
        return 0

    import logging
    import logging.handlers

    log_path = args.log_path if args.log_path else log_path_var

    if not os.path.exists(log_path):
        os.makedirs(log_path)
    LOG_FILENAME = os.path.join(log_path, 'logging_cl_core.out')
    file_logger = logging.getLogger('MyLogger')
    file_logger.setLevel(logging.DEBUG)

    # Add the log message handler to the logger
    handler = logging.handlers.RotatingFileHandler(
                LOG_FILENAME, maxBytes=10000000, backupCount=3)

    file_logger.addHandler(handler)

    # debug
    if args.debug:
        logging.basicConfig(level=logging.DEBUG)
        logger = logging.getLogger('soaplib.wsgi')
        logger.setLevel(logging.DEBUG)

    #####################
    from urllib2 import URLError
    from traceback import print_exc
    try:
        if args.check:
            import bootstrap
            bootstrap.check(cert, key, cert_path, data_path, certbase, args)
            return 0
        if args.bootstrap_user_name:
            import bootstrap
            bootstrap.init(cert, key, cert_path, data_path, certbase, args, \
                           port, args.bootstrap_user_name)
            return 0
        if args.revoke_cert_id:
            cert_cmd.revoke_signed_cert(args.revoke_cert_id, data_path,
                                        cert_path)
            return 0
        if args.host or args.gen_root_cert or args.root_host or \
                                                           args.use_root_cert:
            cert_cmd.check_server_certificate(cert, key, cert_path, args, port)
            return 0
        if args.id_client_req:
            cert_cmd.sing_req_by_server(args.id_client_req,cert_path,data_path)
            return 0
        if args.Id:
            cert_cmd.view_cert(args, certbase, data_path, rights, group_rights)
            return 0
        if args.cert_id:
            cert_cmd.view_signed_cert(args, serv_certbase, data_path)
            return 0
        if args.req_id:
            cert_cmd.view_client_request(args, certbase, data_path)
            return 0
        # Sign request by root certificate
        if args.id_server_req:
            cert_cmd.sing_req_by_root(args, cert_path, data_path)
            return 0
        if args.id_del_req or args.id_del_client_req:
            cert_cmd.del_request(args.id_del_req, args.id_del_client_req,
                                 serv_certbase, certbase, data_path)
            return 0
    except URLError, e:
        fd = open(LOG_FILENAME,'a')
        file_logger.debug(print_exc(file=fd))
        fd.close()
        print e
    params_list = [args.start, args.create_symlink, args.method,
                   args.list_methods]
    if not filter(None, params_list):
        parser.print_help()
        return 0
    #####################
    # importing other modules
    from func import initialization
    other_mod = initialization(cl_wsdl)
    #try:
    pack = "calculate.core.server"
    import importlib
    func_metaclass = importlib.import_module('%s.func_metaclass' %pack)

    other_mod.append(func_metaclass.Func_MetaClass)

#    from calculate.core.server.cl_vers_api import VERS
#    other_mod.append(VERS)

    from calculate.core.server.baseClass import Basic
    other_mod.append(Basic)
    other_mod.append(object)
    # make server metaclass
    if args.method or args.list_methods:
        from replace_class import replaceClass, local_method
        CombinedServerClass = type ("CombinedServerClass",
                                    tuple([replaceClass]+other_mod), {})
        local_method(CombinedServerClass, args)
        return 0
    CombinedServerClass = type ("CombinedServerClass", tuple(other_mod), {})

    from server_class import ClApplication, OpenSSLAdapter
    App = ClApplication([CombinedServerClass],'tns', log = file_logger)
    tc = App.get_service(CombinedServerClass)

    if args.create_symlink:
        from func import create_symlink
        create_symlink(data_path)
        return 0

    # delete all sid and pid informations file
    cert_cmd.create_path(data_path, certbase, rights, group_rights)

    # set all path
    tc.set_paths (data_path, certbase, serv_certbase, rights, group_rights, \
                sids, pids, sids_pids, sids_file, pids_file, max_sid, \
                max_pid, cert_path, LOG_FILENAME, cert, key)

    max_num = 99999999
    from cherrypy.wsgiserver import CherryPyWSGIServer, WSGIPathInfoDispatcher
    dispatcher = WSGIPathInfoDispatcher( { '' : App } )
    server = CherryPyWSGIServer(('0.0.0.0', port), dispatcher,\
    numthreads = 10, max = max_num, request_queue_size = max_num)

    print _("listening to https://0.0.0.0:%d") % (port)
    print _("wsdl is located at: https://0.0.0.0:%d/?wsdl") %(port)

    ca_cert = cert_path + "/ca_root.crt"
    if not os.path.exists (ca_cert):
        ca_cert = None

    sslAdapter = OpenSSLAdapter(cert, key, ca_cert)

    sslAdapter.certbase = certbase

    server.ssl_adapter = sslAdapter
    server.certbase = certbase
    server.serv_certbase = serv_certbase
    server.rights = rights
    server.group_rights = group_rights
    server.sids = sids
    server.pids = pids
    server.sids_file = sids_file
    server.pids_file = pids_file
    server.data_path = data_path
    server.cert_path = cert_path

    server.ssl_certificate = cert
    server.ssl_private_key = key
    from OpenSSL.SSL import Error as SSLError
    import socket
    try:
        if args.pidfile:
            try:
                open(args.pidfile,"w").write(str(os.getpid()))
            except OSError:
                sys.stderr.write(_("failed to create PID file %s") \
                                                        %args.pidfile+"\n")
                sys.exit(1)
        # For cleaning of sessions at server reboot
        from clean import clean
        clean(sids_file, pids_file, sids_pids, sids, pids)
        print _("Server started")
        server.start()
    except KeyboardInterrupt, e:
        try:
            tc.killall()
        except KeyboardInterrupt:
            pass
        print '\n'+_("Server stopped")
        server.stop()
        sys.exit(0)
    except socket.error, e:
        if e.message == "No socket could be created":
            print _("No socket could be created")
            print _('Port %d already in use') %port
        else:
            fd = open(LOG_FILENAME,'a')
            file_logger.debug(print_exc(file=fd))
            fd.close()
            print e
    except SSLError, e:
        print '\n',_('Server certificate not found')#, e
        print _('use cl-core key --gen-cert-by HOST (--get-cert-from HOST) '
                'or --use-root-as-server)')
    except KeyboardInterrupt:
            pass
    except Exception, e:
        fd = open(LOG_FILENAME,'a')
        file_logger.debug(print_exc(file=fd))
        fd.close()

    server.stop()
    if args.pidfile:
        if os.path.exists(args.pidfile):
            os.unlink(args.pidfile)
    sys.exit(0)
