import fnmatch
import os

from django.core.management.base import BaseCommand, CommandError

from compressor.conf import settings
from compressor.cache import cache, get_mtime, get_mtime_cachekey


class Command(BaseCommand):
    help = "Add or remove all mtime values from the cache"

    def add_arguments(self, parser):
        parser.add_argument(
            '-i', '--ignore', action='append', default=[],
            dest='ignore_patterns', metavar='PATTERN',
            help="Ignore files or directories matching this glob-style "
                 "pattern. Use multiple times to ignore more."),
        parser.add_argument(
            '--no-default-ignore', action='store_false',
            dest='use_default_ignore_patterns', default=True,
            help="Don't ignore the common private glob-style patterns 'CVS', "
                 "'.*' and '*~'."),
        parser.add_argument(
            '--follow-links', dest='follow_links', action='store_true',
            help="Follow symlinks when traversing the COMPRESS_ROOT "
                 "(which defaults to STATIC_ROOT). Be aware that using this "
                 "can lead to infinite recursion if a link points to a parent "
                 "directory of itself."),
        parser.add_argument(
            '-c', '--clean', dest='clean', action='store_true',
            help="Remove all items"),
        parser.add_argument(
            '-a', '--add', dest='add', action='store_true',
            help="Add all items"),

    def is_ignored(self, path):
        """
        Return True or False depending on whether the ``path`` should be
        ignored (if it matches any pattern in ``ignore_patterns``).
        """
        for pattern in self.ignore_patterns:
            if fnmatch.fnmatchcase(path, pattern):
                return True
        return False

    def handle(self, **options):
        ignore_patterns = options['ignore_patterns']
        if options['use_default_ignore_patterns']:
            ignore_patterns += ['CVS', '.*', '*~']
            options['ignore_patterns'] = ignore_patterns
        self.ignore_patterns = ignore_patterns

        if ((options['add'] and options['clean'])
                or (not options['add'] and not options['clean'])):
            raise CommandError('Please specify either "--add" or "--clean"')

        if not settings.COMPRESS_MTIME_DELAY:
            raise CommandError(
                'mtime caching is currently disabled. Please '
                'set the COMPRESS_MTIME_DELAY setting to a number of seconds.')

        files_to_add = set()
        keys_to_delete = set()

        for root, dirs, files in os.walk(settings.COMPRESS_ROOT,
                                         followlinks=options['follow_links']):
            for dir_ in dirs:
                if self.is_ignored(dir_):
                    dirs.remove(dir_)
            for filename in files:
                common = "".join(root.split(settings.COMPRESS_ROOT))
                if common.startswith(os.sep):
                    common = common[len(os.sep):]
                if self.is_ignored(os.path.join(common, filename)):
                    continue
                filename = os.path.join(root, filename)
                keys_to_delete.add(get_mtime_cachekey(filename))
                if options['add']:
                    files_to_add.add(filename)

        if keys_to_delete:
            cache.delete_many(list(keys_to_delete))
            self.stdout.write("Deleted mtimes of %d files from the cache."
                              % len(keys_to_delete))

        if files_to_add:
            for filename in files_to_add:
                get_mtime(filename)
            self.stdout.write("Added mtimes of %d files to cache."
                              % len(files_to_add))
