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

# Copyright 2012-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 argparse
import sys
from calculate.core.server.api_types import ViewInfoAdapter
from calculate.core.server.local_call import Methods, has_force_arg
from function import _create_obj, get_view_params, print_brief, _print
from calculate.lib.cl_lang import setLocalTranslate

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

from calculate.core.server.methods_func import get_method_argparser, \
    collect_object, RawAndDefaultsHelpFormatter, \
    check_result_msg, get_param_pwd, display_error


def parse():
    parser = argparse.ArgumentParser(
        add_help=False, formatter_class=RawAndDefaultsHelpFormatter)
    #    parser = argparse.ArgumentParser(add_help=False)
    parser.add_argument(
        '-h', '--help', action='store_true', default=False,
        dest='help', help=_("show this help message and exit"))
    parser.add_argument(
        '--method', type=str, dest='method', help=_('call method'))
    parser.add_argument(
        '--port', type=int, dest='port',
        help=_('port number'))
    parser.add_argument(
        '--host', type=str, default='localhost', dest='host',
        help=_('destination host'))
    parser.add_argument(
        '--gen-cert-by', type=str, dest='by_host', metavar='HOST',
        help=_('send a certificate signature request to the server'))
    parser.add_argument(
        '--get-cert-from', type=str, dest='from_host', metavar='HOST',
        help=_('get the signed certificate from the server'))
    parser.add_argument(
        '--cert-path', type=str, dest='path_to_cert', metavar='PATH',
        help=_('path to the cert and key files'))
    parser.add_argument(
        '--attach', metavar='PID',
        dest='pid_res', help="%s (%s)" % (
            _("attach to process"),
            _("'list' for displaying possible values")))
    parser.add_argument(
        '--keep', action='store_true', default=False,
        dest='keep_result', help=_("keep the cache of the "
                                   "process results"))
    parser.add_argument(
        '--kill', type=int, metavar='PID',
        dest='pid_kill', help=_("kill the selected process"))
    parser.add_argument(
        '--session-clean', action='store_true', default=False,
        dest='session_clean', help=_('clear the session cache'))
    parser.add_argument(
        '--session-info', action='store_true', default=False,
        dest='session_info', help=_("view the session information"))
    parser.add_argument(
        '--session', type=int, metavar='SID',
        dest='session_num_info',
        help=_("view information about session = SID"))
    parser.add_argument(
        '--session-list', action='store_true', default=False,
        dest='session_list',
        help=_("view the active server sessions"))
    parser.add_argument(
        '--update-crl', action='store_true', default=False,
        dest='update_crl', help=_("update the revocation list"))
    parser.add_argument(
        '--stop-consoled', action='store_true', default=False,
        dest='stop_consoled', help=_("stop cl-consoled"))
    parser.add_argument(
        '--no-progress', action='store_true', default=False,
        dest='no_progress', help=_('do not display the progress bar'))
    parser.add_argument(
        '--stdin-passwords', action='store_true', default=False,
        dest='stdin_passwd',
        help=_("use passwords from standard input for users accounts"))
    return parser


def get_view(client, method, sid, view_params):
    try:
        view = client.service[0][method + '_view'](client.sid, view_params)
    except urllib2.URLError, e:
        _print(_('Failed to connect') + ':', e)
        raise Exception(1)
    return view


def call_method(client, args, unknown_args, wait_thread):
    method = args.method
    stdin_passwd = args.stdin_passwd

    # вычислить наличие флага --force
    try:
        dispatch_usenew = has_force_arg(unknown_args)
    except BaseException:
        wait_thread.stop()
        sys.stdout.write('\r')
        sys.stdout.flush()
        raise

    method_parser = None
    view = None

    while True:
        view_params = get_view_params(client, method + '_view', step=None,
                                      expert=True,
                                      dispatch_usenew=dispatch_usenew)

        view = get_view(client, method, client.sid, view_params)
        method_parser = get_method_argparser(view, args)

        _unknown_args = method_parser.fixBoolVariables(unknown_args)

        _args, _drop_args = method_parser.parse_known_args(_unknown_args)

        if dispatch_usenew == _args.no_questions:
            break
        else:
            client.service.clear_method_cache(client.sid, args.method)
            dispatch_usenew = _args.no_questions

    param_object = _create_obj(client, method)
    try:
        unknown_args = method_parser.fixBoolVariables(unknown_args)
        args, unknown_args = method_parser.parse_known_args(unknown_args)
        no_questions = args.no_questions
        client.no_questions = no_questions
    except SystemExit:
        raise Exception(1)
    for i in unknown_args:
        if i.startswith('-'):
            if i in parse().parse_known_args()[1]:
                wait_thread.stop()
                sys.stdout.write('\r')
                sys.stdout.flush()
                _print(_('Unknown parameter'), i)
                raise Exception(1)
    if view.groups is not None:
        param_object, steps = collect_object(client, param_object, view, args,
                                             wait_thread,
                                             stdin_passwd=stdin_passwd)
        if steps.label and hasattr(param_object, 'CheckOnly'):
            param_object['CheckOnly'] = True
            check_res = {}
            while True:
                method_result = client.service[0][method](client.sid,
                                                          param_object)
                if not method_result:
                    print _('Method not available')
                    return None
                if (method_result.ReturnedMessage[0].type and
                            method_result.ReturnedMessage[0].type != "pid"):
                    wait_thread.stop()

                    check_res = check_result_msg(method_result, view,
                                                 check_res, args)
                    if not check_res:
                        return None
                    else:
                        param_object = get_param_pwd(check_res, view,
                                                     param_object, client)
                else:
                    break

            view_params = get_view_params(client, method + '_view', step=None,
                                          expert=True, brief=True)
            view = get_view(client, method, client.sid, view_params)
            wait_thread.stop()
            sys.stdout.write('\r')
            sys.stdout.flush()
            print_brief(view, steps.label)
            if not no_questions:
                try:
                    ask = Methods().askConfirm(_("Run process?"))
                except KeyboardInterrupt:
                    ask = "no"
                if ask.lower() in ['n', 'no']:
                    Methods().printERROR(_('Manually interrupted'))
                    return None

            param_object['CheckOnly'] = False
    else:
        param_object = {}
    method_result = client.service[0][method](client.sid, param_object)
    if not method_result:
        print _('Method not available')
        return None
    if (method_result.ReturnedMessage[0].type and
                method_result.ReturnedMessage[0].type != "pid"):
        view = ViewInfoAdapter(view)
        for error in method_result.ReturnedMessage:
            display_error(error, args, view.groups)
        return None
    wait_thread.stop()
    return method_result
