#       Licensed to the Apache Software Foundation (ASF) under one
#       or more contributor license agreements.  See the NOTICE file
#       distributed with this work for additional information
#       regarding copyright ownership.  The ASF licenses this file
#       to you 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 os
import sys
import logging
import shlex
from multiprocessing import Process

import pylons
from paste.script import command
from paste.deploy import appconfig
from paste.registry import Registry

import activitystream
import ming
from allura.config.environment import load_environment
from allura.lib.decorators import task
from allura.lib.helpers import iter_entry_points

log = None

@task
def run_command(command, args):
    """Run paster command asynchronously"""
    mod, cls = command.rsplit('.', 1)
    mod = __import__(mod, fromlist=[str(cls)])
    command = getattr(mod, cls)
    command = command(command.__name__)
    arg_list = shlex.split(args or '')
    try:
        command.parser.parse_args(arg_list)
    except SystemExit:
        raise Exception("Error parsing args: '%s'" % args)
    return command.run(arg_list)

class EmptyClass(object): pass

class Command(command.Command):
    min_args = 1
    max_args = 1
    usage = '[<ini file>]'
    group_name = 'Allura'

    class __metaclass__(type):
        @property
        def __doc__(cls):
            return cls.parser.format_help()

    @classmethod
    def post(cls, *args, **kw):
        cmd = '%s.%s' % (cls.__module__, cls.__name__)
        return run_command.post(cmd, *args, **kw)

    @ming.utils.LazyProperty
    def registry(self):
        return Registry()

    @ming.utils.LazyProperty
    def globals(self):
        import allura.lib.app_globals
        return allura.lib.app_globals.Globals()

    @ming.utils.LazyProperty
    def config(self):
        import tg
        return tg.config

    def basic_setup(self):
        global log, M
        if self.args[0]:
            # Probably being called from the command line - load the config file
            self.config = conf = appconfig('config:%s' % self.args[0],relative_to=os.getcwd())
            # ... logging does not understand section#subsection syntax
            logging_config = self.args[0].split('#')[0]
            logging.config.fileConfig(logging_config, disable_existing_loggers=False)
            log = logging.getLogger('allura.command')
            log.info('Initialize command with config %r', self.args[0])
            load_environment(conf.global_conf, conf.local_conf)
            self.setup_globals()
            from allura import model
            M=model
            ming.configure(**conf)
            activitystream.configure(**conf)
            pylons.tmpl_context.user = M.User.anonymous()
        else:
            # Probably being called from another script (websetup, perhaps?)
            log = logging.getLogger('allura.command')
            conf = pylons.config
        self.tools = pylons.app_globals.entry_points['tool'].values()
        for ep in iter_entry_points('allura.command_init'):
            log.info('Running command_init for %s', ep.name)
            ep.load()(conf)
        log.info('Loaded tools')

    def setup_globals(self):
        import allura.lib.app_globals
        self.registry.prepare()
        self.registry.register(pylons.tmpl_context, EmptyClass())
        self.registry.register(pylons.app_globals, self.globals)
        self.registry.register(allura.credentials, allura.lib.security.Credentials())
        pylons.tmpl_context.queued_messages = None

    def teardown_globals(self):
        self.registry.cleanup()
