# Path: marvinbot/plugins.py
# def load_plugins(config, adapter=None, webapp=None):
#     modules_to_load = config.get("plugins")
#     plugin_configs = config.get("plugin_configuration", {})
# 
#     if modules_to_load:
#         for module in modules_to_load:
#             if module:
#                 # Pass along module specific configuration, if available
#                 try:
#                     plugin = load_module(module, plugin_configs.get(module, {}), adapter, webapp)
#                     plugin_loaded.send(plugin)
#                 except Exception as e:
#                     # Report the error, continue loading the other plugins
#                     log.warn("Plugin [{}] not loaded due to an error".format(module))
#                     log.exception(e)
# 
# Path: marvinbot/signals.py

# 
# Path: marvinbot/polling.py
# class TelegramPollingThread(PollingThread):
#     def __init__(self, adapter, workers=UPDATER_DEFAULTS.get('polling_workers')):
#         self.adapter = adapter
#         updater_config = UPDATER_DEFAULTS
#         updater_config.update(self.adapter.config.get('updater', {}))
# 
#         # If specified on the constructor, override the config
#         updater_config['polling_workers'] = workers or updater_config['polling_workers']
#         super(TelegramPollingThread, self).__init__(self.fetch_updates, self.on_update,
#                                                     checker=lambda x: bool(x),
#                                                     ignored_exceptions=[NetworkError, Unauthorized],
#                                                     send_last_result=True, send_last_update_time=True,
#                                                     poll_interval=updater_config.get('polling_interval'),
#                                                     poll_timeout=updater_config.get('polling_expiry'),
#                                                     thread_name='telegram-polling-thread',
#                                                     workers=updater_config.get('polling_workers'))
# 
#     def fetch_updates(self, last_result=None, last_update_time=None):
#         # Fetch a list of Telegram updates for the bot, passing in the last_update_id
#         # as stored in last_result
#         yield from self.adapter.fetch_updates(last_result)
# 
#     def on_update(self, updates):
#         last_update = None
#         for update in updates:
#             # Execute the actual processing asynchronously
#             self.execute(self.adapter.process_update, update)
#             last_update = update
#         if last_update:
#             # This is needed so we can avoid pulling the same update twice
#             # Telegram's API returns the latest update after this ID
#             return last_update.update_id + 1
# 
# Path: marvinbot/scheduler.py
# def configure_scheduler(config, adapter):
#     scheduler_config = {}
#     scheduler_config.update(DEFAULT_CONFIG)
#     scheduler_config.update(config.get('scheduler', {}))
# 
#     adapter.scheduler = BackgroundScheduler(scheduler_config)
#     return adapter.scheduler


from marvinbot.plugins import load_plugins
from marvinbot.signals import bot_shutdown, bot_started
from marvinbot.polling import TelegramPollingThread
from marvinbot.scheduler import configure_scheduler
import logging

log = logging.getLogger(__name__)


def shutdown_bot(adapter):
    log.info('Shutting down...')
    if adapter.scheduler_available:
        adapter.scheduler.shutdown()
    adapter.updater.stop()
    bot_shutdown.send(adapter)


def run_bot(adapter):
    # The program will exit as soon as all non-daemon threads stop
    log.info("Starting bot in standalone mode")
    adapter.updater.daemon = False
    adapter.updater.start()
    configure_scheduler(adapter.config, adapter)
    load_plugins(adapter.config, adapter)

# Path: marvinbot/plugins.py
# def load_plugins(config, adapter=None, webapp=None):
#     modules_to_load = config.get("plugins")
#     plugin_configs = config.get("plugin_configuration", {})
# 
#     if modules_to_load:
#         for module in modules_to_load:
#             if module:
#                 # Pass along module specific configuration, if available
#                 try:
#                     plugin = load_module(module, plugin_configs.get(module, {}), adapter, webapp)
#                     plugin_loaded.send(plugin)
#                 except Exception as e:
#                     # Report the error, continue loading the other plugins
#                     log.warn("Plugin [{}] not loaded due to an error".format(module))
#                     log.exception(e)
# 
# Path: marvinbot/signals.py

# 
# Path: marvinbot/polling.py
# class TelegramPollingThread(PollingThread):
#     def __init__(self, adapter, workers=UPDATER_DEFAULTS.get('polling_workers')):
#         self.adapter = adapter
#         updater_config = UPDATER_DEFAULTS
#         updater_config.update(self.adapter.config.get('updater', {}))
# 
#         # If specified on the constructor, override the config
#         updater_config['polling_workers'] = workers or updater_config['polling_workers']
#         super(TelegramPollingThread, self).__init__(self.fetch_updates, self.on_update,
#                                                     checker=lambda x: bool(x),
#                                                     ignored_exceptions=[NetworkError, Unauthorized],
#                                                     send_last_result=True, send_last_update_time=True,
#                                                     poll_interval=updater_config.get('polling_interval'),
#                                                     poll_timeout=updater_config.get('polling_expiry'),
#                                                     thread_name='telegram-polling-thread',
#                                                     workers=updater_config.get('polling_workers'))
# 
#     def fetch_updates(self, last_result=None, last_update_time=None):
#         # Fetch a list of Telegram updates for the bot, passing in the last_update_id
#         # as stored in last_result
#         yield from self.adapter.fetch_updates(last_result)
# 
#     def on_update(self, updates):
#         last_update = None
#         for update in updates:
#             # Execute the actual processing asynchronously
#             self.execute(self.adapter.process_update, update)
#             last_update = update
#         if last_update:
#             # This is needed so we can avoid pulling the same update twice
#             # Telegram's API returns the latest update after this ID
#             return last_update.update_id + 1
# 
# Path: marvinbot/scheduler.py
# def configure_scheduler(config, adapter):
#     scheduler_config = {}
#     scheduler_config.update(DEFAULT_CONFIG)
#     scheduler_config.update(config.get('scheduler', {}))
# 
#     adapter.scheduler = BackgroundScheduler(scheduler_config)
#     return adapter.scheduler


# Path: marvinbot/runner.py
from marvinbot.plugins import load_plugins
from marvinbot.signals import bot_shutdown, bot_started
from marvinbot.polling import TelegramPollingThread
from marvinbot.scheduler import configure_scheduler
import logging


log = logging.getLogger(__name__)


def shutdown_bot(adapter):
    log.info('Shutting down...')
    if adapter.scheduler_available:
        adapter.scheduler.shutdown()
    adapter.updater.stop()
    bot_shutdown.send(adapter)


def run_bot(adapter):
    # The program will exit as soon as all non-daemon threads stop
    log.info("Starting bot in standalone mode")
    adapter.updater.daemon = False
    adapter.updater.start()
    configure_scheduler(adapter.config, adapter)
    load_plugins(adapter.config, adapter)

    if adapter.scheduler_available: