import sys
from pluginmgr import PluginManager

from vodka.instance import (
    instances,
    instantiate,
    ready,
    get_instance
)

from vodka.app import (
    load_all,
    applications,
    get_application
)

import vodka.data
import vodka.data.data_types
import vodka.config
import vodka.log

plugin = PluginManager("vodka.plugins")


def init(config, rawConfig):

    # reference the complete config in vodka.config.raw
    if type(rawConfig) in [dict, vodka.config.Config]:
        vodka.config.raw.update(**rawConfig)
    else:
        vodka.config.raw.update(**rawConfig.data)

    # reference the vodka instance config in vodka.config.instance
    if type(config) in [dict, vodka.config.Config]:
        cfg = config
        vodka.config.instance.update(**cfg)
    else:
        cfg = vodka.config.Config(read=config)
        vodka.config.instance.update(**cfg.data)

    # set up loggers
    vodka.log.set_loggers(cfg.get("logging", {}))

    # import applications
    load_all(cfg)

    # instantiate data types
    vodka.log.debug("instantiating data types")
    vodka.data.data_types.instantiate_from_config(cfg.get("data", []))

    # instantiate plugins
    vodka.log.debug("instantiating plugins")
    plugin.instantiate(cfg["plugins"])
    
    # instantiate vodka applications
    vodka.log.debug("instantiating applications")
    instantiate(cfg)


    vodka.log.debug("making sure configuration is sane ...")

    num_crit, num_warn = vodka.config.InstanceHandler.validate(cfg)

    if num_crit > 0:
        vodka.log.error(
            "There have been %d critical errors detected in the configuration, please fix them and try again" % num_crit)
        sys.exit()

    vodka.log.debug("starting plugins")

    gevent_workers = []
    thread_workers = []

    for pcfg in cfg["plugins"]:
        p_name = pcfg.get("name", pcfg.get("type"))
        p = plugin.get_instance(p_name)
        
        p.setup()

        if pcfg.get("start_manual", False):
            continue
        vodka.log.debug("starting %s .." % p_name)
        async = pcfg.get("async", "thread")

        if hasattr(p, "worker"):
            worker = p.worker
        else:
            worker = p

        if async == "gevent":
            gevent_workers.append(worker)
        elif async == "thread":
            thread_workers.append(worker)

    ready()

    return {
        "gevent_workers": gevent_workers,
        "thread_workers": thread_workers
    }


def start(gevent_workers=None, thread_workers=None):
   if thread_workers:
        import threading
        for w in thread_workers:
            if hasattr(w, "start"):
                t = threading.Thread(target=w.start)
            else:
                t = threading.Thread(target=w)
            # FIXME: need plugin shutdown instead
            t.daemon = True
            t.start()

   if gevent_workers:
        import gevent
        _workers = []
        for worker in gevent_workers:
            if isinstance(worker, gevent.Greenlet):
                _workers.append(worker)
            else:
                if hasattr(worker, "run"):
                    _workers.append(gevent.Greenlet(worker.run))
                else:
                    _workers.append(gevent.Greenlet(worker))

        gevent.joinall(_workers)
 

def run(config, rawConfig=None):
    if not rawConfig:
        rawConfig=config
    start(**init(config, rawConfig))

@@ -988,24 +988,376 @@
 oad_all(cfg)
+%0A    %0A    # validating configuration%0A    vodka.log.debug(%22making sure configuration is sane ...%22)%0A    num_crit, num_warn = vodka.config.InstanceHandler.validate(cfg)%0A    if num_crit %3E 0:%0A        vodka.log.error(%0A            %22There have been %25d critical errors detected in the configuration, please fix them and try again%22 %25 num_crit)%0A        sys.exit()
 %0A%0A    # inst
@@ -1724,327 +1724,8 @@
 )%0A%0A%0A
-    vodka.log.debug(%22making sure configuration is sane ...%22)%0A%0A    num_crit, num_warn = vodka.config.InstanceHandler.validate(cfg)%0A%0A    if num_crit %3E 0:%0A        vodka.log.error(%0A            %22There have been %25d critical errors detected in the configuration, please fix them and try again%22 %25 num_crit)%0A        sys.exit()%0A%0A
     

move config validation before plugin initialization so we can catch plugin config errors