"""
Plugin hooks for EDMC - Ian Norton
"""
import os
import imp
import sys

if __debug__:
    from traceback import print_exc

from config import config

"""
Dictionary of loaded plugin modules.
"""
PLUGINS = dict()


def find_plugins():
    """
    Look for plugin entry points.
    :return:
    """
    found = dict()
    disabled = list()
    plug_folders = os.listdir(config.plugin_dir)
    for name in plug_folders:
        if name.endswith(".disabled"):
            name, discard = name.rsplit(".", 1)
            disabled.append(name)
            continue
        loadfile = os.path.join(config.plugin_dir, name, "load.py")
        if os.path.isfile(loadfile):
            found[name] = loadfile
    return found, disabled


def load_plugins():
    """
    Load all found plugins
    :return:
    """
    found, disabled = find_plugins()
    imp.acquire_lock()
    for plugname in disabled:
        sys.stdout.write("plugin {} disabled\n".format(plugname))

    for plugname, loadfile in found.iteritems():
        try:
            sys.stdout.write("loading plugin {}\n".format(plugname))

            # Add plugin's folder to Python's load path in case plugin has dependencies.
            sys.path.append(os.path.dirname(loadfile))

            with open(loadfile, "rb") as plugfile:
                plugmod = imp.load_module(plugname, plugfile, loadfile.encode(sys.getfilesystemencoding()),
                                          (".py", "r", imp.PY_SOURCE))
                if hasattr(plugmod, "plugin_start"):
                    newname = plugmod.plugin_start()
                    PLUGINS[newname and unicode(newname) or plugname] = plugmod

        except Exception as plugerr:
            if __debug__:
                print_exc()
            else:
                sys.stderr.write('%s: %s\n' % (plugname, plugerr))	# appears in %TMP%/EDMarketConnector.log in packaged Windows app

    imp.release_lock()


def _get_plugin_func(plugname, funcname):
    """
    Get a function from a plugin, else return None if it isn't implemented.
    :param plugname:
    :param funcname:
    :return:
    """
    return getattr(PLUGINS[plugname], funcname, None)


def get_plugin_app(plugname, parent):
    """
    If the plugin provides mainwindow content create and return it.
    :param plugname: name of the plugin
    :param parent: the parent frame for this entry.
    :return:
    """
    plugin_app = _get_plugin_func(plugname, "plugin_app")
    if plugin_app:
        return plugin_app(parent)
    return None


def get_plugin_prefs(plugname, parent):
    """
    If the plugin provides a prefs frame, create and return it.
    :param plugname: name of the plugin
    :param parent: the parent frame for this preference tab.
    :return:
    """
    plugin_prefs = _get_plugin_func(plugname, "plugin_prefs")
    if plugin_prefs:
        return plugin_prefs(parent)
    return None


def notify_prefs_changed():
    """
    Notify each plugin that the settings dialog has been closed.
    :return:
    """
    for plugname in PLUGINS:
        prefs_changed = _get_plugin_func(plugname, "prefs_changed")
        if prefs_changed:
            try:
                prefs_changed()
            except Exception as plugerr:
                if __debug__:
                    print_exc()
                else:
                    sys.stderr.write('%s: %s\n' % (plugname, plugerr))


def notify_journal_entry(cmdr, system, station, entry, state):
    """
    Send a journal entry to each plugin.
    :param cmdr: The Cmdr name, or None if not yet known
    :param system: The current system, or None if not yet known
    :param station: The current station, or None if not docked or not yet known
    :param entry: The journal entry as a dictionary
    :param state: A dictionary containing info about the Cmdr, current ship and cargo
    :return:
    """
    for plugname in PLUGINS:
        journal_entry = _get_plugin_func(plugname, "journal_entry")
        if journal_entry:
            try:
                # Pass a copy of the journal entry in case the callee modifies it
                if journal_entry.func_code.co_argcount == 4:
                    journal_entry(cmdr, system, station, dict(entry))
                else:
                    journal_entry(cmdr, system, station, dict(entry), dict(state))
            except Exception as plugerr:
                if __debug__:
                    print_exc()
                else:
                    sys.stderr.write('%s: %s\n' % (plugname, plugerr))


def notify_interaction(cmdr, entry):
    """
    Send an interaction entry to each plugin.
    :param cmdr: The piloting Cmdr name
    :param entry: The interaction entry as a dictionary
    :return:
    """
    for plugname in PLUGINS:
        interaction = _get_plugin_func(plugname, "interaction")
        if interaction:
            try:
                # Pass a copy of the interaction entry in case the callee modifies it
                interaction(cmdr, dict(entry))
            except Exception as plugerr:
                if __debug__:
                    print_exc()
                else:
                    sys.stderr.write('%s: %s\n' % (plugname, plugerr))


def notify_system_changed(timestamp, system, coordinates):
    """
    Send notification data to each plugin when we arrive at a new system.
    :param timestamp:
    :param system:
    :return:
    deprecated:: 2.2
    Use :func:`journal_entry` with the 'FSDJump' event.
    """
    for plugname in PLUGINS:
        system_changed = _get_plugin_func(plugname, "system_changed")
        if system_changed:
            try:
                if system_changed.func_code.co_argcount == 2:
                    system_changed(timestamp, system)
                else:
                    system_changed(timestamp, system, coordinates)
            except Exception as plugerr:
                if __debug__:
                    print_exc()
                else:
                    sys.stderr.write('%s: %s\n' % (plugname, plugerr))


def notify_newdata(data):
    """
    Send the latest EDMC data from the FD servers to each plugin
    :param data:
    :return:
    """
    for plugname in PLUGINS:
        cmdr_data = _get_plugin_func(plugname, "cmdr_data")
        if cmdr_data:
            try:
                cmdr_data(data)
            except Exception as plugerr:
                if __debug__:
                    print_exc()
                else:
                    sys.stderr.write('%s: %s\n' % (plugname, plugerr))