import sublime
import sublime_plugin
import json
from threading import Thread

from ..lib.ycmd_handler import server
from ..lib.utils import *
from ..lib.ycmd_events import Event
from ..lib.msgs import MsgTemplates

output_panel = None


def notification_func(server, filepath, contents, callback):
    '''
    Thread that send event notification
    '''
    data = server.SendEventNotification(Event.FileReadyToParse,
                                        filepath=filepath,
                                        contents=contents,
                                        filetype='cpp')
    if data == '':
        return
    callback(data)


class CppycmHighlightProblemsCommand(sublime_plugin.WindowCommand):

    '''
    Goto command
    '''

    def __init__(self, window):
        global output_panel
        self.window = window
        self.output_panel = self.window.create_output_panel(
            'CppYCM.{}'.format(self.window.id()))
        self.output_panel_name = 'output.CppYCM.{}'.format(self.window.id())
        self.output_panel.set_syntax_file(get_error_panel_syntax_file())
        output_panel = self.output_panel

    def run(self):
        view = active_view()
        filepath = get_file_path(view.file_name())
        contents = view.substr(sublime.Region(0, view.size()))

        t = Thread(None, notification_func, 'NotifyAsync',
                   [server(), filepath, contents, self._on_errors])
        t.daemon = True
        t.start()

    def is_enabled(self):
        ''' 
        Determine if this command is enabled or not
        '''
        return is_cpp(active_view())

    def _on_errors(self, data):
        view = active_view()
        data = json.loads(data)
        filepath = get_file_path(view.file_name())
        self.highlight_problems(view,
                                [_ for _ in data
                                    if get_file_path(_['location']['filepath']) == filepath])
        # self.update_statusbar(active_view(), force=True)

    def highlight_problems(self, view, problems):
        view.erase_regions('clang-code-errors')
        view_id = view.id()
        view_cache = {}
        regions = []
        # erase output panel
        self.output_panel.set_read_only(False)
        self.output_panel.run_command('select_all')
        self.output_panel.run_command('right_delete')
        for problem in problems:
            lineno = problem['location']['line_num']
            colno = problem['location']['column_num']
            line_regions = view_cache.setdefault(lineno - 1, {})
            message = MsgTemplates.ERROR_MESSAGE_TEMPLATE.format(**problem)
            problem_output = MsgTemplates.PRINT_ERROR_MESSAGE_TEMPLATE.format(
                message, lineno, colno)
            self.output_panel.run_command(
                'insert', {'characters': problem_output}
            )

            region = view.word(view.text_point(lineno - 1, colno - 1))
            regions.append(region)
            line_regions[(region.a, region.b)] = message

        self.output_panel.set_read_only(True)
        self.output_panel.run_command(
            'move_to', {'to': 'bof', 'extend': False})
        if problems:
            self.window.run_command(
                'show_panel', {'panel': self.output_panel_name})
        # self.view_cache[view_id] = view_cache
        style = (sublime.DRAW_NO_FILL | sublime.DRAW_NO_OUTLINE |
                 sublime.DRAW_SQUIGGLY_UNDERLINE)
        view.add_regions(
            key='clang-code-errors',
            regions=regions,
            scope='invalid',
            flags=style)