import asyncio
import logging
from collections import Mapping

from .base import AbstractEntity
from ..core.loader import load_entities
from ..utils import import_name


class Context(AbstractEntity, Mapping):
    async def init(self):
        self._entities = {}
        self._on_stop = []
        self.logger = logging.getLogger('aioworkers')

        await load_entities(
            self.config, context=self, loop=self.loop,
            entities=self._entities)

        inits = []
        for i in self._entities.values():
            inits.append(i.init())
            if hasattr(i, 'stop'):
                self._on_stop.append(i.stop())
        if inits:
            await self.wait_all(inits)

    async def wait_all(self, coros):
        if not coros:
            return
        d, p = await asyncio.wait(coros, loop=self.loop)
        assert not p
        for f in d:
            if f.exception():
                self.logger.exception('ERROR', exc_info=f.exception())

    async def stop(self):
        await self.wait_all(self._on_stop)

    def __getitem__(self, item):
        if item is None:
            return
        elif isinstance(item, str):
            try:
                return self._config[item]
            except:
                pass
            try:
                return import_name(item)
            except:
                pass
        elif isinstance(item, Mapping):
            if 'func' in item:
                func = import_name(item['func'])
                args = item.get('args', ())
                kwargs = item.get('kwargs', {})
                return func(*args, **kwargs)
        raise KeyError(item)

    def __getattr__(self, item):
        try:
            return self._config[item]
        except KeyError:
            raise AttributeError(item)

    def __iter__(self):
        pass

    def __len__(self):
        pass

@@ -211,27 +211,42 @@
     
-async 
 def 
+__
 init
+__
 (self
+, *args, **kwargs
 ):%0A 
@@ -281,25 +281,51 @@
        self.
-_
+on_start = %5B%5D%0A        self.
 on_stop = %5B%5D
@@ -379,16 +379,84 @@
 rkers')%0A
+        super().__init__(*args, **kwargs)%0A%0A    async def init(self):
 %0A       
@@ -718,25 +718,24 @@
        self.
-_
 on_stop.appe
@@ -751,30 +751,8 @@
 ())%0A
-        if inits:%0A    
     
@@ -1061,16 +1061,87 @@
 ion())%0A%0A
+    async def start(self):%0A        await self.wait_all(self.on_start)%0A%0A
     asyn
@@ -1191,17 +1191,16 @@
 ll(self.
-_
 on_stop)

context.start