# coding=utf-8
from logging import getLogger
from tempfile import mkdtemp
from zipfile import ZipFile

from path import path

from engineer.conf import settings
from engineer.exceptions import ThemeDirectoryNotFoundException
from engineer.plugins import ThemeProvider
from engineer.themes import Theme


__author__ = 'Tyler Butler <tyler@tylerbutler.com>'

logger = getLogger('engineer.finders')


#noinspection PyShadowingBuiltins
class BaseFinder(object):
    @classmethod
    def get_from_directory(cls, directory):
        if not path(directory).exists():
            raise ThemeDirectoryNotFoundException(directory)
        themes = []
        for file in directory.walkfiles('metadata.yaml'):
            themes.append(Theme.from_yaml(file))

        for zipped_file in directory.walkfiles('*.zip'):
            temp = path(mkdtemp())
            with ZipFile(zipped_file, 'r') as theme:
                theme.extractall(path=temp)
            logger.debug("Zipped theme %s unzipped to %s." % (zipped_file, temp))
            themes.extend(cls.get_from_directory(temp))
        return themes

    @classmethod
    def get_themes(cls):
        return NotImplementedError()


class DefaultFinder(BaseFinder):
    """Locates and loads built-in Engineer themes."""

    @classmethod
    def get_themes(cls):
        themes_path = settings.ENGINEER.THEMES_DIR
        return cls.get_from_directory(themes_path)


class SiteFinder(BaseFinder):
    """
    Loads themes from the ``/themes`` directory inside a site folder.

    .. versionadded:: 0.2.3
    """

    @classmethod
    def get_themes(cls):
        themes_path = settings.SETTINGS_DIR / 'themes'
        if themes_path.exists():
            return cls.get_from_directory(themes_path)
        else:
            return []


#noinspection PyShadowingBuiltins
class ThemeDirsFinder(BaseFinder):
    """
    Loads themes from the directories specified in :attr:`~engineer.conf.EngineerConfiguration.THEME_DIRS`.

    .. versionadded:: 0.2.3
    """

    @classmethod
    def get_themes(cls):
        themes = []
        for dir in settings.THEME_DIRS:
            try:
                themes.extend(cls.get_from_directory(dir))
            except ThemeDirectoryNotFoundException as e:
                logger.warning(e.message)
                continue
        return themes


class PluginFinder(BaseFinder):
    """
    Loads themes from any installed :ref:`theme plugins`.

    .. versionadded:: 0.2.4
    """

    @classmethod
    def get_themes(cls):
        themes = []
        for p in ThemeProvider.plugins:
            for t in p.paths:
                try:
                    themes.extend(cls.get_from_directory(t))
                except ThemeDirectoryNotFoundException as e:
                    logger.warning(e.message)
                    continue
        return themes
