from __future__ import absolute_import, unicode_literals

from uuid import uuid4

from django.contrib.postgres.fields import JSONField
from django.utils.translation import ugettext as _
from django.db import models


class ProviderTemplate(models.Model):
    id = models.UUIDField(primary_key=True, default=uuid4, editable=False)
    name = models.CharField(max_length=256)
    instance_name = models.CharField(max_length=256)
    credentials = JSONField(default=dict, blank=True)
    data = JSONField(default=dict, blank=True)
    active = models.BooleanField(default=True)

    class Meta:
        abstract = True


class ProviderException(Exception):
    pass


class ProviderNotFound(ProviderException):
    pass


class ModuleNotFound(ProviderException):
    pass


class ModuleCredentialsNotFound(ProviderException):
    pass


class ModuleCredentialsInvalid(ProviderException):
    pass


class ModuleConfigInvalid(ProviderException):
    pass


class ModuleInvalid(ProviderException):
    pass


class ModuleLoader(object):

    def __call__(self, *args, **kwargs):
        raise NotImplementedError

    def __init__(self, module_lookup, *args, **kwargs):
        if not isinstance(module_lookup, dict):
            raise TypeError(_("Module lookup must be a dict"))
        self.module_lookup = module_lookup

    def load_module(self, provider_instance):
        if not isinstance(provider_instance, ProviderTemplate):
            raise TypeError(_("Must provide valid provider instance"))

        try:
            mod = self.module_lookup[provider_instance.name]
        except:
            raise ModuleNotFound

        if not hasattr(mod, "instantiate"):
            raise ModuleInvalid

        return mod

    def instantiate(self, provider_instance, *args, **kwargs):
        mod = self.load_module(provider_instance)
        return mod.instantiate(*args, **kwargs)


# usage: subclass ModuleLoader and override __init__ and __call__.
# Then set module-level function instantiate = ModuleLoader(*args, **kwargs)
# In each module, there should also be an instantiate function that constructs
# a new instance of the service
@@ -1138,16 +1138,21 @@
 e_lookup
+=None
 , *args,
@@ -1155,32 +1155,74 @@
 rgs, **kwargs):%0A
+        if module_lookup is not None:%0A    
         if not i
@@ -1257,32 +1257,36 @@
 t):%0A            
+    
 raise TypeError(
@@ -1320,16 +1320,42 @@
 dict%22))%0A
+            else:%0A        
         
@@ -1390,16 +1390,126 @@
 lookup%0A%0A
+        if not getattr(self, %22module_lookup%22):%0A            raise ValueError(_(%22Must specify module lookup%22))%0A%0A
     def 

allow module_lookup to be specified in subclass definition