import sublime
from os.path import normpath, join
import imp
from collections import namedtuple
import sys
import traceback
import warnings


class BracketRegion (namedtuple('BracketRegion', ['begin', 'end'], verbose=False)):
    """
    Bracket Regions for plugins
    """

    def move(self, begin, end):
        """
        Move bracket region to different points
        """

        return self._replace(begin=begin, end=end)

    def size(self):
        """
        Get the size of the region
        """

        return abs(self.begin - self.end)

    def toregion(self):
        """
        Convert to sublime region
        """

        return sublime.Region(self.begin, self.end)


def is_bracket_region(obj):
    """
    Check if object is a BracketRegion
    """

    return isinstance(obj, BracketRegion)


class ImportModule(object):
    @classmethod
    def import_module(cls, module_name, loaded=None):
        # Pull in built-in and custom plugin directory
        if module_name.startswith("bh_modules."):
            path_name = join(sublime.packages_path(), "BracketHighlighter", normpath(module_name.replace('.', '/')))
        else:
            path_name = join(sublime.packages_path(), normpath(module_name.replace('.', '/')))
        path_name += ".py"
        if loaded is not None and module_name in loaded:
            module = sys.modules[module_name]
        else:
            with warnings.catch_warnings(record=True) as w:
                # Ignore warnings about plugin folder not being a python package
                warnings.simplefilter("always")
                module = imp.new_module(module_name)
                sys.modules[module_name] = module
                source = None
                with open(path_name) as f:
                    source = f.read().replace('\r', '')
                cls.__execute_module(source, module_name)
                w = filter(lambda i: issubclass(i.category, UserWarning), w)
        return module

    @classmethod
    def __execute_module(cls, source, module_name):
        exec(compile(source, module_name, 'exec'), sys.modules[module_name].__dict__)

    @classmethod
    def import_from(cls, module_name, attribute):
        return getattr(cls.import_module(module_name), attribute)


class BracketPlugin(object):
    """
    Class for preparing and running plugins
    """

    def __init__(self, plugin, loaded):
        """
        Load plugin module
        """

        self.enabled = False
        self.args = plugin['args'] if ("args" in plugin) else {}
        self.plugin = None
        if 'command' in plugin:
            plib = plugin['command']
            try:
                module = ImportModule.import_module(plib, loaded)
                self.plugin = getattr(module, 'plugin')()
                loaded.add(plib)
                self.enabled = True
            except Exception:
                print 'BracketHighlighter: Load Plugin Error: %s\n%s' % (plugin['command'], traceback.format_exc())

    def is_enabled(self):
        """
        Check if plugin is enabled
        """

        return self.enabled

    def run_command(self, view, name, left, right, selection):
        """
        Load arguments into plugin and run
        """

        plugin = self.plugin()
        setattr(plugin, "left", left)
        setattr(plugin, "right", right)
        setattr(plugin, "view", view)
        setattr(plugin, "selection", selection)
        edit = view.begin_edit()
        self.args["edit"] = edit
        self.args["name"] = name
        try:
            plugin.run(**self.args)
            left, right, selection = plugin.left, plugin.right, plugin.selection
        except Exception:
            print "BracketHighlighter: Plugin Run Error:\n%s" % str(traceback.format_exc())
        view.end_edit(edit)
        return left, right, selection


class BracketPluginCommand(object):
    """
    Bracket Plugin base class
    """

    def run(self, bracket, content, selection):
        """
        Runs the plugin class
        """

        pass
