#!/usr/bin/python
# Authors:
#     Endi S. Dewata <edewata@redhat.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; version 2 of the License.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
# Copyright (C) 2014 Red Hat, Inc.
# All rights reserved.
#

from __future__ import absolute_import
from __future__ import print_function
import shlex
import subprocess
import sys
import traceback

import pki.cli
import pki.cli.pkcs12


PYTHON_COMMANDS = ['pkcs12-import']


class PKICLI(pki.cli.CLI):

    def __init__(self):
        super(PKICLI, self).__init__(
            'pki', 'PKI command-line interface')

        self.database = None
        self.password = None
        self.password_file = None
        self.token = None

        self.add_module(pki.cli.pkcs12.PKCS12CLI())

    def get_full_module_name(self, module_name):
        return module_name

    def print_help(self):
        print('Usage: pki [OPTIONS]')
        print()
        print('      --client-type <type>     PKI client type (default: java)')
        print('   -d <path>                   Client security database location ' +
              '(default: ~/.dogtag/nssdb)')
        print('   -c <password>               Client security database password ' +
              '(mutually exclusive to the -C option)')
        print('   -C <path>                   Client-side password file ' +
              '(mutually exclusive to the -c option)')
        print('      --token <name>           Security token name')
        print()
        print('  -v, --verbose                Run in verbose mode.')
        print('      --debug                  Show debug messages.')
        print('      --help                   Show help message.')
        print()

        super(PKICLI, self).print_help()

    def execute_java(self, args, stdout=sys.stdout):

        # read Java home
        value = subprocess.check_output(
            '. /usr/share/pki/etc/pki.conf && . /etc/pki/pki.conf && echo $JAVA_HOME',
            shell=True)
        java_home = value.decode(sys.getfilesystemencoding()).strip()

        # read RESTEasy library path
        value = subprocess.check_output(
            '. /usr/share/pki/etc/pki.conf && . /etc/pki/pki.conf && echo $RESTEASY_LIB',
            shell=True)
        resteasy_lib = value.decode(sys.getfilesystemencoding()).strip()

        # read logging configuration path
        value = subprocess.check_output(
            '. /usr/share/pki/etc/pki.conf && . /etc/pki/pki.conf && echo $LOGGING_CONFIG',
            shell=True)
        logging_config = value.decode(sys.getfilesystemencoding()).strip()

        # construct classpath
        classpath = [
            '/usr/share/java/commons-cli.jar',
            '/usr/share/java/commons-codec.jar',
            '/usr/share/java/commons-httpclient.jar',
            '/usr/share/java/commons-io.jar',
            '/usr/share/java/commons-lang.jar',
            '/usr/share/java/commons-logging.jar',
            '/usr/share/java/httpcomponents/httpclient.jar',
            '/usr/share/java/httpcomponents/httpcore.jar',
            '/usr/share/java/jackson/jackson-core-asl.jar',
            '/usr/share/java/jackson/jackson-jaxrs.jar',
            '/usr/share/java/jackson/jackson-mapper-asl.jar',
            '/usr/share/java/jackson/jackson-mrbean.jar',
            '/usr/share/java/jackson/jackson-smile.jar',
            '/usr/share/java/jackson/jackson-xc.jar',
            '/usr/share/java/jaxb-api.jar',
            '/usr/share/java/ldapjdk.jar',
            '/usr/share/java/servlet.jar',
            resteasy_lib + '/jaxrs-api.jar',
            resteasy_lib + '/resteasy-atom-provider.jar',
            resteasy_lib + '/resteasy-client.jar',
            resteasy_lib + '/resteasy-jaxb-provider.jar',
            resteasy_lib + '/resteasy-jaxrs.jar',
            resteasy_lib + '/resteasy-jaxrs-jandex.jar',
            resteasy_lib + '/resteasy-jackson-provider.jar',
            '/usr/share/java/pki/pki-nsutil.jar',
            '/usr/share/java/pki/pki-cmsutil.jar',
            '/usr/share/java/pki/pki-certsrv.jar',
            '/usr/share/java/pki/pki-tools.jar',
            '/usr/lib64/java/jss4.jar',
            '/usr/lib/java/jss4.jar'
        ]

        cmd = [
            java_home + '/bin/java',
            '-cp',
            ':'.join(classpath),
            '-Djava.util.logging.config.file=' + logging_config,
            'com.netscape.cmstools.cli.MainCLI'
        ]

        # restore options for Java commands

        if self.database:
            cmd.extend(['-d', self.database])

        if self.password:
            cmd.extend(['-c', self.password])

        if self.password_file:
            cmd.extend(['-C', self.password_file])

        if self.token and self.token != 'internal':
            cmd.extend(['--token', self.token])

        if self.verbose:
            cmd.extend(['--verbose'])

        cmd.extend(args)

        if self.verbose:
            print('Java command: %s' % ' '.join(cmd))

        subprocess.check_call(cmd, stdout=stdout)

    def execute(self, argv):

        # append global options
        value = subprocess.check_output(
            '. /usr/share/pki/etc/pki.conf && . /etc/pki/pki.conf && echo $PKI_CLI_OPTIONS',
            shell=True)
        value = value.decode(sys.getfilesystemencoding()).strip()
        args = shlex.split(value)
        args.extend(argv[1:])

        client_type = 'java'

        pki_options = []
        command = None
        cmd_args = []

        # read pki options before the command
        # remove options for Python module

        i = 0
        while i < len(args):
            # if arg is a command, stop
            if args[i][0] != '-':
                command = args[i]
                break

            # get database path
            if args[i] == '-d':
                self.database = args[i + 1]
                pki_options.append(args[i])
                pki_options.append(args[i + 1])
                i = i + 2

            # get database password
            elif args[i] == '-c':
                self.password = args[i + 1]
                pki_options.append(args[i])
                pki_options.append(args[i + 1])
                i = i + 2

            # get database password file path
            elif args[i] == '-C':
                self.password_file = args[i + 1]
                pki_options.append(args[i])
                pki_options.append(args[i + 1])
                i = i + 2

            # get token name
            elif args[i] == '--token':
                self.token = args[i + 1]
                pki_options.append(args[i])
                pki_options.append(args[i + 1])
                i = i + 2

            # check verbose option
            elif args[i] == '-v' or args[i] == '--verbose':
                self.set_verbose(True)
                pki_options.append(args[i])
                i = i + 1

            # check debug option
            elif args[i] == '--debug':
                self.set_verbose(True)
                self.set_debug(True)
                pki_options.append(args[i])
                i = i + 1

            # get client type
            elif args[i] == '--client-type':
                client_type = args[i + 1]
                pki_options.append(args[i])
                pki_options.append(args[i + 1])
                i = i + 2

            else:  # otherwise, save the arg for the next module
                cmd_args.append(args[i])
                i = i + 1

        # save the rest of the args
        while i < len(args):
            cmd_args.append(args[i])
            i = i + 1

        if self.verbose:
            print('PKI options: %s' % ' '.join(pki_options))
            print('PKI command: %s %s' % (command, ' '.join(cmd_args)))

        if client_type == 'python' or command in PYTHON_COMMANDS:
            (module, module_args) = self.parse_args(cmd_args)
            module.execute(module_args)

        elif client_type == 'java':
            self.execute_java(cmd_args)

        else:
            raise Exception('Unsupported client type: ' + client_type)


if __name__ == '__main__':

    cli = PKICLI()

    try:
        cli.execute(sys.argv)

    except subprocess.CalledProcessError as e:
        if cli.verbose:
            print('ERROR: %s' % e)
        elif cli.debug:
            traceback.print_exc()
        exit(e.returncode)
