# Copyright 2010 Canonical Ltd.  This software is licensed under the
# GNU Lesser General Public License version 3 (see the file LICENSE).

import os
import sys
from optparse import make_option, OptionParser

from django.conf import settings, global_settings
from django.core.management.base import BaseCommand, CommandError

from configglue.pyschema import schemaconfigglue


class Command(BaseCommand):
    option_list = BaseCommand.option_list + (
        make_option('--global', action='store_true',
            dest='include_global',
            help='include global settings in lookup'),
        make_option('--show', action='store_true', dest='show_current',
            help='show current settings'),
        make_option('--locate', action='store_true', dest='locate',
            help='show location of setting definitions'),
        make_option('--validate', action='store_true', dest='validate',
            help='validate current settings'),
        )
    help = ('Show settings attributes (value, location), or ' 
            'validate current settings')
    args = '[setting ...]'

    def handle(self, *args, **options):
        show_current = options.get('show_current')
        include_global = options.get('include_global')
        locate = options.get('locate')
        validate = options.get('validate')

        if not args and not (show_current or validate):
            self.print_help(sys.argv[0], sys.argv[1])
            return

        if validate:
            output = self.validate_settings()
        else:
            setting_list = map(str.upper, args)
            if locate:
                output = self.locate(setting_list)
            else:
                output = self.get(setting_list)

                if show_current:
                    output += self.show(include_global)

        return output

    def show(self, include_global=False):
        def is_setting(name):
            return not name.startswith('__') and name.isupper()

        global_settings_ = set(k for k in dir(global_settings) if
            is_setting(k))
        all_settings = set(k for k in dir(settings) if is_setting(k))
        lines = []
        if include_global:
            local_settings = all_settings
        else:
            local_settings = all_settings - global_settings_
        for name in local_settings:
            lines.append("%s = %r" % (name, getattr(settings, name)))

        return '\n'.join(lines)

    def get(self, keys):
        __marker = object()
        output = ''
        for key in keys:
            value = getattr(settings, key, __marker)
            if value is __marker:
                output = "setting %s not found" % key
            else:
                output = "%s = %r" % (key, value)
        return output

    def locate(self, keys):
        location = None

        try:
            parser = settings.__CONFIGGLUE_PARSER__
        except AttributeError:
            # this is a normal settings file, not generated by configglue
            module = __import__(settings.SETTINGS_MODULE, globals(),
                                locals(), [''])
            location = module.__file__

        output = []
        if location is None:
            # looking in configglue settings
            for key in keys:
                cases = [key, key.lower(), key.upper()]
                for case in cases:
                    location = parser.locate(option=case)
                    if location is not None:
                        msg = "setting %s last defined in %r"
                        output.append(msg % (key.upper(),
                            os.path.realpath(location)))
                        break
                else:
                    output.append("setting %s not found" % key.upper())
        else:
            # looking in django settings
            for key in map(str.upper, keys):
                if key in settings.get_all_members():
                    msg = "setting %s last defined in %r"
                    output.append(msg % (key, os.path.realpath(location)))
                else:
                    output.append("setting %s not found" % key)

        return '\n'.join(output)

    def validate_settings(self):
        is_valid = True
        msg = 'Settings appear to be fine.'

        try:
            parser = settings.__CONFIGGLUE_PARSER__
        except AttributeError:
            # this is a normal settings file, not generated by configglue
            msg = 'The settings module was not generated by configglue. '
            msg += 'Can only validate configglue generated settings.'
            return msg

        is_valid, errors = parser.is_valid(report=True)
        if not is_valid:
            msg = "Settings did not validate against schema.\n\n%s\n"
            errors = '\n'.join(errors)
            raise CommandError(msg % errors)

        return msg

    def create_parser(self, prog_name, subcommand):
        """
        Add all our SchemaConfigParser's options so they can be shown
        in help messages and such.
        """
        parser = OptionParser(prog=prog_name,
                              usage=self.usage(subcommand),
                              version=self.get_version(),
                              option_list=self.option_list)
        configglue_parser = settings.__CONFIGGLUE_PARSER__
        op, options, args = schemaconfigglue(configglue_parser, op=parser)
        return op


