# Standard library imports
import inspect
import collections
import pkg_resources


_INSTALLERS = collections.OrderedDict()
_ENTRY_POINTS = collections.OrderedDict()


class plugin(object):
    _BASE_ENTRY_POINT_NAME = "uplink.plugins."

    def __init__(self, name, _entry_points=_ENTRY_POINTS):
        self._name = self._BASE_ENTRY_POINT_NAME + name
        self._entry_points = _entry_points

    def __call__(self, func):
        self._entry_points[self._name] = func
        return func


class installer(object):
    def __init__(self, base_cls, _installers=_INSTALLERS):
        self._base_cls = base_cls
        self._installers = _installers

    def __call__(self, func):
        self._installers[self._base_cls] = func
        return func


def load_entry_points(
    _entry_points=_ENTRY_POINTS,
    _iter_entry_points=pkg_resources.iter_entry_points,
):
    for name in _entry_points:
        plugins = {
            entry_point.name: entry_point.load()
            for entry_point in _iter_entry_points(name)
        }
        func = _entry_points[name]
        for value in plugins.values():
            func(value)


def install(installable, _installers=_INSTALLERS):
    cls = installable if inspect.isclass(installable) else type(installable)
    for base_cls in _installers:
        if issubclass(cls, base_cls):
            _installers[base_cls](installable)
            break
    else:
        raise TypeError("Failed to install: '%s'" % str(installable))

    return installable