"""
Contains components that manage services, their sequences and interdependence.
"""

import importlib
import logging
import os
import time
from collections import namedtuple

import app.services
from app.core.toposort import toposort
from app.core.config_loader import get_config

logger = logging.getLogger(__name__)
Module = namedtuple('Module', ["name", "deps", "meta"])


def list_modules(module):
    res = []
    for name in os.listdir(module.__path__[0]):
        try:
            module = importlib.import_module("app.services." + name)
            module_meta = module.__meta__
        except ImportError:
            logger.warning("Not a module: services/%s", name)
            continue
        except AttributeError:
            logger.warning("No __meta__ in services/%s.", name)
            continue
        deps = module_meta["deps"]
        res.append(Module(name=name, deps=deps, meta=module_meta))
    return res


def topo_sort_modules(modules):
    module_map = {x.name: x for x in modules}
    dep_map = {x.name: x.deps for x in modules}
    res = []
    for item in toposort(dep_map):
        res.append(module_map[item])
    return res


class ServiceManager(object):
    """
    Scans for all service modules within the given module.
    """
    def __init__(self, registry):
        unsorted_services = list_modules(app.services)
        self.service_modules = topo_sort_modules(unsorted_services)
        self.services = []

    def run(self):
        """ Sequentially starts all the services."""
        for module in self.service_modules:
            config = get_config(module.meta.get("config", []))
            service = module.meta["class"](config)

            service.service_start()
            self.services.append(service)
            print("Started:", service)

        while True:
            print("waiting..")
            time.sleep(60)

    def stop(self):
        for service in self.services[::-1]:
            print("Stopping", service)
            service.service_stop()

@@ -131,19 +131,24 @@
 import t
-ime
+hreading
 %0Afrom co
@@ -1450,16 +1450,56 @@
 ces = %5B%5D
+%0A        self.active = threading.Event()
 %0A%0A    de
@@ -1775,36 +1775,109 @@
     
-self.services.append(service
+if not service.wait_for_start(config.get(%22start_timeout%22, 10)):%0A                service.service_stop(
 )%0A  
@@ -1890,55 +1890,92 @@
     
+ 
-print(%22Started:%22, service)%0A%0A        while Tr
+   logger.info(%22Failed to start service: %25s%22, module.name)%0A                contin
 ue
-:
 %0A   
@@ -1987,74 +1987,172 @@
     
-print(%22waiting..%22)%0A            time.sleep(60)%0A%0A    def stop(self):
+self.services.append(service)%0A            logger.info(%22Started service: %25s%22, module.name)%0A%0A        self.active.wait()%0A%0A    def stop(self):%0A        self.active.set()
 %0A   

Kill services if they don't start within the configured timeout.