import importlib
from logging import getLogger
import os
import sys


logger = getLogger(__name__)


class LoaderInterface(object):
    """Interface for any loader class"""

    def load(self, names):
        """
        Locates and loads plugin modules using built in strategy

        Arguments:
            :param    names: names (paths, module names) to be loaded
            :type     names: Iterable[str]
        """
        raise NotImplementedError()


class LoaderAggregate(LoaderInterface):
    """Plugin loader that aggregates other plugin loaders"""

    def __init__(self, loaders):
        """Object initialization

        Arguments:
            :param    loaders: loaders to be aggregated
            :type     loaders: Iterable[LoaderInterface]
        """
        self._loaders = list(loaders)

    def load(self, names):
        """
        Loads plugins using given loaders

        Arguments:
            :param    names: names (paths, module names) to be loaded
            :type     names: Iterable[str]
        """
        for loader in self._loaders:
            loader.load(names)


class LoaderFile(LoaderInterface):
    """Loads plugins in given file or directory.
    Loads module from given file or directory"""

    def __init__(self):
        """
        Object initialization
        """
        self._module_name_cache = []

    def load(self, names):
        """
        Loads a set of plugins at the given path.

        Arguments:
            :param    names: file paths to load plugin from
            :type     names: Iterable[str]
        """
        for path in names:
            filename = os.path.basename(path)
            dirname = os.path.dirname(path)
            self._load_module_from_file(dirname, filename)

    def _load_module_from_file(self, path, filename):
        """Loads module from given file and path

        Arguments:
            :param    path: path where file is placed
            :type     path: string
            :param    filename: name of file to load
            :type     filename: string
        """
        logger.debug("loading module from file; path=[%s]; filename=[%s]",
                     path, filename)
        (path, name) = self._prepare_module_name(path, filename)
        if not self._valid_module_information(path, name):
            return

        self._import_module(path, name)

    def _prepare_module_name(self, plugin_dir, item):
        """
        Prepares name of module to load

        Arguments:
            :param    plugin_dir: directory where module is placed
            :type     plugin_dir: string
            :param    item: name of module file (might be file of directory)
            :type     item: string
        :returns: string -- name of module to load