import sublime
import sublime_plugin

from collections import defaultdict

from .lint import persist
from .lint import events


STATUS_COUNTER_KEY = "sublime_linter_status_counter"
STATUS_MSG_KEY = "sublime_linter_status_messages"

State = {
    'active_view': None,
    'current_pos': (-1, -1),
    'errors_per_line': defaultdict(list)
}


def plugin_loaded():
    State.update({
        'active_view': sublime.active_window().active_view()
    })


def plugin_unloaded():
    events.off(on_lint_result)
    for window in sublime.windows():
        for view in window.views():
            view.erase_status(STATUS_COUNTER_KEY)
            view.erase_status(STATUS_MSG_KEY)


@events.on(events.LINT_RESULT)
def on_lint_result(buffer_id, **kwargs):
    active_view = State['active_view']
    if active_view.buffer_id() == buffer_id:
        State.update({
            'errors_per_line': errors_per_line(persist.errors[buffer_id]),
        })

        draw(**State)


class UpdateState(sublime_plugin.EventListener):
    # Fires once per view with the actual view, not necessary the primary
    def on_activated_async(self, active_view):
        bid = active_view.buffer_id()

        State.update({
            'active_view': active_view,
            'errors_per_line': errors_per_line(persist.errors[bid]),
            'current_pos': get_current_pos(active_view)
        })
        draw(**State)

    # Triggers multiple times for each view into the same buffer.
    # But the argument is always the same view, the primary.
    # Activate view via mouse click fires this also, twice per view.
    def on_selection_modified_async(self, view):
        active_view = State['active_view']
        # It is possible that views (e.g. panels) update in the background.
        # So we check here and return early.
        if active_view.buffer_id() != view.buffer_id():
            return

        current_pos = get_current_pos(active_view)
        if current_pos != State['current_pos']:
            State.update({
                'current_pos': current_pos
            })
            draw(**State)


def draw(active_view, current_pos, errors_per_line, **kwargs):
    message = messages_under_cursor(errors_per_line, current_pos)
    if not message:
        active_view.erase_status(STATUS_MSG_KEY)
    elif message != active_view.get_status(STATUS_MSG_KEY):
        active_view.set_status(STATUS_MSG_KEY, message)


def messages_under_cursor(errors, current_pos):
    line, col = current_pos
    msgs = []
    message_template = persist.settings.get('statusbar.messages_template')

    if message_template != "":
        for error in errors[line]:
            if error["start"] <= col <= error["end"]:
                msgs.append(message_template.format(
                    linter=error["linter"],
                    type=error["error_type"],
                    message=error["msg"],
                    code=error["code"]
                ))
        return "; ".join(msgs)
    else:
        return ""


def errors_per_line(errors):
    rv = defaultdict(list)
    for error in errors:
        rv[error['line']].append(error)
    return rv


def get_current_pos(view):
    try:
        return view.rowcol(view.sel()[0].begin())
    except (AttributeError, IndexError):
        return -1, -1

@@ -35,45 +35,8 @@
 in%0A%0A
-from collections import defaultdict%0A%0A
 from
@@ -246,58 +246,10 @@
 s': 
-(
 -1
-, -1),%0A    'errors_per_line': defaultdict(list)
 %0A%7D%0A%0A
@@ -744,118 +744,8 @@
 id:%0A
-        State.update(%7B%0A            'errors_per_line': errors_per_line(persist.errors%5Bbuffer_id%5D),%0A        %7D)%0A%0A
     
@@ -938,47 +938,8 @@
 w):%0A
-        bid = active_view.buffer_id()%0A%0A
     
@@ -1001,77 +1001,8 @@
 ew,%0A
-            'errors_per_line': errors_per_line(persist.errors%5Bbid%5D),%0A
     
@@ -1822,25 +1822,8 @@
 pos,
- errors_per_line,
  **k
@@ -1866,31 +1866,27 @@
 _cursor(
-errors_per_line
+active_view
 , curren
@@ -2109,71 +2109,34 @@
 sor(
-errors, current_pos):%0A    line, col = current_pos%0A    msgs = %5B%5D
+active_view, current_pos):
 %0A   
@@ -2207,17 +2207,16 @@
 plate')%0A
-%0A
     if m
@@ -2250,87 +2250,136 @@
     
-for error in errors%5Bline%5D:%0A            if error%5B%22start%22%5D %3C= col %3C= error%5B%22end%22%5D
+msgs = %5B%5D%0A        for error in persist.errors.get(active_view.buffer_id()):%0A            if error%5B'region'%5D.contains(current_pos)
 :%0A  
@@ -2684,145 +2684,8 @@
 %22%0A%0A%0A
-def errors_per_line(errors):%0A    rv = defaultdict(list)%0A    for error in errors:%0A        rv%5Berror%5B'line'%5D%5D.append(error)%0A    return rv%0A%0A%0A
 def 
@@ -2735,20 +2735,8 @@
 urn 
-view.rowcol(
 view
@@ -2752,17 +2752,16 @@
 .begin()
-)
 %0A    exc
@@ -2815,9 +2815,5 @@
 n -1
-, -1
 %0A

Use region in status_bar_view