import json
import os.path
import re
import sublime
import sublime_plugin


class ProjectSpecificSyntax(sublime_plugin.EventListener):

    def on_load(self, view):
        self._ensure_project_specific_syntax(view)

    def on_post_save(self, view):
        self._ensure_project_specific_syntax(view)

    def _ensure_project_specific_syntax(self, view):
        filename = view.file_name()
        if not filename:
            return

        syntax = self._get_project_specific_syntax(view, filename)
        if syntax:
            self._set_syntax(view, syntax)

    def _get_project_specific_syntax(self, view, filename):
        project_data = _resolve_window(view).project_data()

        if not project_data:
            return None

        syntax_settings = project_data.get('syntax_override', {})

        for regex, syntax in syntax_settings.items():
            if re.search(regex, filename):
                return syntax

        return None

    def _set_syntax(self, view, syntax):
        syntax_path = '/'.join(syntax)

        # prefer the newer .sublime-syntax files over .tmLanguage
        ss_path = 'Packages/{0}.sublime-syntax'.format(syntax_path)
        if os.path.isfile(ss_path):
            view.set_syntax_file(ss_path)
        else:
            view.set_syntax_file('Packages/{0}.tmLanguage'.format(syntax_path))

        print('Switched syntax to: {0}'.format(syntax_path))


class ProjectSpecificSyntaxToClipboardCommand(sublime_plugin.TextCommand):

    def __init__(self, view):
        super().__init__(view)
        self._view = view

    def run(self, edit):
        suggested_setting = self._build_suggested_setting()

        if not suggested_setting:
            sublime.set_clipboard('Unable to create syntax setting')
        else:
            sublime.set_clipboard(suggested_setting)

    def _build_suggested_setting(self):
        suggested_setting = self._build_syntax_setting_for_current_file()
        if not suggested_setting:
            return None

        return self._enclose_in_syntax_override_block_if_not_present_in_settings(suggested_setting)

    def _build_syntax_setting_for_current_file(self):
        syntax_path_parts = self._get_syntax_path_parts()

        if not syntax_path_parts:
            return None

        syntax_path_json = json.dumps(syntax_path_parts)
        file_regex = self._get_example_file_regex_for_current_file()
        return '"{0}": {1}'.format(file_regex, syntax_path_json)

    def _get_syntax_path_parts(self):
        syntax = self.view.settings().get('syntax')

        match = re.search(r'^Packages/(.*)\.(tmLanguage|sublime-syntax)$', syntax)

        if not match:
            print('Syntax does not match expected format: {0}'.format(syntax))
            return None

        return match.group(1).split('/')

    def _enclose_in_syntax_override_block_if_not_present_in_settings(self, suggested_setting):
        if self._is_syntax_override_already_present_in_settings():
            return suggested_setting

        return '"syntax_override": {{\n\t{0}\n}}'.format(suggested_setting)

    def _is_syntax_override_already_present_in_settings(self):
        project_data = _resolve_window(self._view).project_data()
        return 'syntax_override' in project_data

    def _get_example_file_regex_for_current_file(self):
        file_name = self.view.file_name()

        if file_name:
            ext = os.path.splitext(file_name)[1]
        else:
            ext = '.xyz'

        return '\\\\{0}$'.format(ext)


def _resolve_window(view):
    window = view.window()

    if window:
        return window

    return sublime.active_window()