#!/usr/bin/env python

# Copyright (C) 2011, Aleksey Lim
#
# 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, either version 3 of the License, or
# (at your option) any later version.
#
# 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, see <http://www.gnu.org/licenses/>.

import os
import sys
import pwd
import grp
import logging
import textwrap
from optparse import OptionParser
from os.path import basename
from gettext import gettext as _

from sugar_server import env, util, process, printf
from sugar_server.util import enforce


def cmd_start():
    enforce_user()
    enforce('keyring' in env.services.value or \
            'registry' in env.services.value,
            _('registry service is required but disabled'))
    return process.start(env.foreground.value, True)


def cmd_restart():
    cmd_stop()
    # TODO More reliable method
    import time
    time.sleep(3)
    cmd_start()


def cmd_reload():
    process.hup()


def cmd_stop():
    return process.stop()


def cmd_status():
    if process.started():
        printf.info('sugar-server started')
        return 0
    else:
        printf.info('sugar-server stopped')
        return 1


def cmd_config():
    if args:
        opt = args.pop(0)
        enforce(opt in util.Option.items, _('Unknown option "%s"'), opt)
        exit(0 if bool(util.Option.items[opt].value) else 1)
    else:
        print '\n'.join(util.Option.export())


def cmd_services():
    for i in env.SERVICES_ALL:
        line = i
        if i not in env.services.value:
            line += ' (%s)' % _('disabled')
        printf.info(line)


def cmd_import_root():
    enforce_user()

    enforce(args, _('ROOT argument needs to be passed'))
    src_root = args.pop(0)

    printf.info(_('Start import'))
    logging.debug('Import data root=%s', src_root)

    env.service('registry').import_root(src_root)
    for i in set(env.SERVICES_ALL) - set(['registry']):
        env.service(i).import_root(src_root)


def cmd_import_xs():
    enforce_user()

    enforce(args, _('DB argument needs to be passed'))
    src_db = args.pop(0)
    enforce(args, _('ROOT argument needs to be passed'))
    src_root = args.pop(0)

    printf.info(_('Start import from XS installation'))
    logging.debug('Import XS data db=%s root=%s', src_db, src_root)

    env.service('registry').import_xs(src_db)
    for i in set(env.SERVICES_ALL) - set(['registry']):
        env.service(i).import_xs(src_root)


def enforce_user():
    if 'keyring' in env.services.value:
        enforce(len(env.services.value) == 1,
                _('Service keyring should be launched alone'))
        user = env.keyring_user.value
    else:
        user = env.user.value

    group = grp.getgrnam(env.user.value)
    user_pw = pwd.getpwnam(user)

    if user_pw.pw_uid != os.geteuid():
        enforce(os.geteuid() == 0,
                _('Program should be launched by %s user'), user_pw.pw_name)
        logging.info(_('Switch to %s user'), user_pw.pw_name)
        os.setgid(group.gr_gid)
        os.setuid(user_pw.pw_uid)


def service_help(service_name):
    if service_name not in util.Command.sections:
        return

    print 'Commands from %s service:' % service_name
    for name, cmd in sorted(util.Command.sections[service_name].items()):
        cmdline = '%s %s' % (name, cmd.cmd_format)
        sys.stdout.write(cmdline)
        for n, line in enumerate(textwrap.wrap(cmd.description, 56)):
            if n == 0:
                if len(cmdline) >= 24:
                    print
                    sys.stdout.write(' ' * 24)
                else:
                    sys.stdout.write(' ' * (24 - len(cmdline)))
            else:
                sys.stdout.write(' ' * 24)
            print line
    print


HELP = """
Commands:
  setup                 initiate root directories tree
  status                check for launched daemon
  start                 start in daemon mode
  restart               restart daemon
  reload                reopen log files in daemon mode
  stop                  stop daemon
  import_root ROOT      import data from another sugar-server installation
  import_xs DB ROOT     import data from OLPC XS installation
  services              list of supported services
  <service> [COMMAND]   call service specific commands, no arguments for info
  config                output current configuration
"""

FOOTER = """\
See http://wiki.sugarlabs.org/go/Sugar_Server_Kit/sugar-server for details."""

parser = OptionParser(
        usage='%prog [OPTIONS] [COMMAND]',
        description=_('Core services for Sugar users.'),
        add_help_option=False)
parser.print_version = \
        lambda: sys.stdout.write('%s\n' % env.VERSION)
parser.add_option('-q', '--quiet',
        help='supress any auxiliary output',
        default=False, action='store_true')
parser.add_option('-h', '--help',
        help=_('show this help message and exit'),
        action='store_true')
parser.add_option('-V', '--version',
        help=_('show version number and exit'),
        action='version')

options, args = env.init(parser)
printf.VERBOSE = not options.quiet

if not args and not options.help:
    prog = basename(sys.argv[0])
    print 'Usage: %s [OPTIONS] [COMMAND]' % prog
    print '       %s -h|--help' % prog
    print
    print parser.description
    print HELP
    print FOOTER
    exit(0)

if options.help:
    parser.print_help()
    print HELP
    for service in env.services.value:
        service_help(service)
    print FOOTER
    exit(0)

command = args.pop(0)
try:
    if 'cmd_' + command in globals():
        exit(globals()['cmd_' + command]() or 0)
    elif command not in env.SERVICES_ALL:
        raise RuntimeError(_('Unknown command "%s"') % command)
    else:
        enforce(command in env.services.value,
                _('Service %s is disabled'), command)
        if args:
            service = env.service(command)
            sub_cmd = args.pop(0)
            enforce(sub_cmd in util.Command.sections[command],
                    _('Unknown command %s for service %s'), sub_cmd, command)
            enforce_user()
            service.setup()
            util.Command.call(service.mod, sub_cmd, args)
        else:
            prog = basename(sys.argv[0])
            print 'Usage: %s %s [OPTIONS] [COMMAND]' % (prog, command)
            print '       %s -h|--help' % prog
            print
            print parser.description
            print
            service_help(command)
            print FOOTER
except Exception:
    printf.exception(_('Abort sugar-server due to error'))
    exit(1)
finally:
    process.shutdown()
    printf.flush_hints()
