# Copyright (C) 2013 - 2016 - Oscar Campos <oscar.campos@member.fsf.org>
# This program is Free Software see LICENSE file for details

import os
from functools import partial

from anaconda_go.lib.plugin import typing

import sublime
from Default.exec import ExecCommand


class ExplorerPanel:
    """Panel to support exploring commands
    """

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

    def run(self, data: typing.Dict =None) -> None:
        """Proccess the data coming from the tools
        """

        if data is not None and not data['success']:
            return self._unable_to_find()

        results = data['result']
        if len(results) == 0:
            return self._unable_to_find()

        self._show_options(results)

    def doc(self, data: typing.Dict =None) -> None:
        """Create a doc panel with the data coming from the tools
        """

        if data is not None and not data['success']:
            return self._unable_to_find()

        result = data['result']
        if len(result) == 0:
            return self._unable_to_find()
        data = result

        doc = ['']
        _type = data.get('detail')
        if _type is None:
            return self._unable_to_find()

        detail = data.get(_type)
        if detail is None:
            return self._unable_to_find()

        description = detail.get('type')
        if description is None:
            return self._unable_to_find()

        doc.append(description)
        doc.append('=' * 79)
        p = {'type': detail.get('namepos')}.get(_type, detail.get('objpos'))
        if p is not None:
            path, line, col = p.split(':')
            doc.append(p)

        namedef = detail.get('namedef')
        if namedef is not None:
            namedef = namedef.replace(
                '; ', '\n\t').replace('{', ' {\n\t').replace('}', '\n}')
            namedef = namedef.replace('struct {', 'struct {} {{'.format(
                description
            ), 1)
            doc.append(namedef)

        methods = detail.get('methods', [])
        if len(methods) > 0:
            doc.append('\nMethods ')
            for method in methods:
                doc.append('{}\n    {}\n'.format(
                    method['pos'], method['name'])
                )

        exe = ExecCommand(sublime.active_window())
        exe.run(
            shell_cmd='echo "{}\n"'.format('\n'.join(doc)),
            file_regex=r'(...*?):([0-9]*):([0-9]*)',
            quiet=True,
        )
        exe.hide_phantoms()

    def _unable_to_find(self):
        """Just show a message in the status bar
        """

        sublime.status_message('Unable to find {}'.format(
            self.view.substr(self.view.word(self.view.sel()[0]))
        ))

    def _show_options(self, options: typing.Dict) -> None:
        """Show a dropdown quickpanel with options on it
        """

        self._options = options
        quick_panel_options = []
        for option in options:
            location = 'file: {} line: {} column: {}'.format(
                option['filename'], option['line'], option['col']
            )
            ident = option['ident']
            if option.get('show_filename', False):
                ident = '{} ({})'.format(
                    option['ident'], os.path.basename(option['filename'])
                )
            quick_panel_options.append(
                [ident, option['full'], location]
            )

        self.point = self.view.sel()[0]
        self.view.window().show_quick_panel(
            quick_panel_options, self._on_select,
            on_highlight=partial(
                self._on_select, transient=True, highlight=True)
        )

    def _on_select(self, index, transient=False, highlight=False):
        """Called when the user selects an option in the quick panel
        """

        if index == -1:
            # restore view
            sublime.active_window().focus_view(self.view)
            self.view.show(self.point)

            if self.view.sel()[0] != self.point:
                self.view.sel().clear()
                self.view.sel().add(self.point)

            return

        opt = self._options[index]
        if opt['keyword'] == 'package' and not highlight:
            sublime.set_timeout(
                sublime.active_window().run_command(
                    'anaconda_go_explore_packages',
                    args={'identificator': opt['ident']}
                ), 0
            )
            return

        if opt['keyword'] != 'package' and highlight is True:
            self._jump(opt['filename'], opt['line'], opt['col'], transient)

    def _jump(self, filename: str, line: int =None,
              col: int =None, transient: bool =False) -> None:
        """Jump to the given destination
        """

        flags = sublime.ENCODED_POSITION
        if transient:
            flags |= sublime.TRANSIENT

        sublime.active_window().open_file(
            '{}:{}:{}'.format(filename, line or 0, col or 0), flags)
        self._toggle_indicator(line, col)

    def _toggle_indicator(self, line: int =0, col: int =0) -> None:
        """Toggle mark indicator for focus the cursor
        """

        pt = self.view.text_point(line - 1, col)
        region_name = 'anaconda.indicator.{}.{}'.format(self.view.id(), line)

        for i in range(3):
            delta = 300 * i * 2
            sublime.set_timeout(lambda: self.view.add_regions(
                region_name,
                [sublime.Region(pt, pt)],
                'comment',
                'bookmark',
                sublime.DRAW_EMPTY_AS_OVERWRITE
            ), delta)
            sublime.set_timeout(
                lambda: self.view.erase_regions(region_name),
                delta + 300
            )


class DocPanel:
    """General doc panel class
    """

    def __init__(self, view):
        self.view = view
        self.panel = view.window().create_output_panel('anaconda_go_doc')
        self.panel.settings().set('scroll_past_end', False)
        self.panel.settings().set('line_numbers', False)
        self.panel.settings().set('rulers', [])
        self.panel.assign_syntax('Packages/Text/Plain text.tmLanguage')
        self.view.window().create_output_panel('anaconda_go_doc')

    def show(self):
        """Show the doc panel
        """

        self.view.window().run_command(
            'show_panel', {'panel': 'output.anaconda_go_doc'}
        )

    def print(self, text: str, se: bool=False):
        """Print the given text into the panel
        """

        self.panel.run_command(
            'append', {'characters': text, 'force': True, 'scroll_to_end': se}
        )