import subprocess
from abc import abstractmethod
from denite.source.base import Base  # pylint: disable=locally-disabled, import-error
import denite.util  # pylint: disable=locally-disabled, import-error


class GtagsBase(Base):
    def gather_candidates(self, context):
        word = self._get_search_word(context)

        candidates = []
        for search_flags in self.get_search_flags():
            if word:
                search_flags += ['--', word]

            tags = self._exec_global(search_flags, context)
            candidates += self.convert_to_candidates(tags)

        return candidates

    @abstractmethod
    def get_search_flags(self):
        return [[]]

    @abstractmethod
    def convert_to_candidates(self):
        raise NotImplementedError()

    def _get_search_word(self, context):
        args_count = len(context['args'])
        if args_count > 0:
            return context['args'][0]

        return context['input']

    def _exec_global(self, search_args, context, input=None):
        command = ['global', '-q'] + search_args
        global_proc = subprocess.Popen(
            command,
            cwd=context['path'],
            universal_newlines=True,
            stdin=subprocess.PIPE if input else None,
            stdout=subprocess.PIPE,
            stderr=subprocess.PIPE)
        try:
            output, error = global_proc.communicate(input=input, timeout=15)
        except subprocess.TimeoutExpired:
            global_proc.kill()
            output, error = global_proc.communicate()
        global_exitcode = global_proc.returncode

        if global_exitcode != 0:
            self._print_global_error(global_exitcode, error)
            return []

        return [t for t in output.split('\n') if len(t) > 0]

    def _print_global_error(self, global_exitcode, error):
        if global_exitcode == 1:
            message = '[denite-gtags] Error: File does not exists'
        elif global_exitcode == 2:
            message = '[denite-gtags] Error: Invalid arguments\n{error}'
        elif global_exitcode == 3:
            message = '[denite-gtags] Error: GTAGS not found'
        elif global_exitcode == 126:
            message = f'[denite-gtags] Error: Permission denied\n{error}'
        elif global_exitcode == 127:
            message = '[denite-gtags] Error: \'global\' command not found'
        else:
            message = '[denite-gtags] Error: global command failed\n{error}'
        denite.util.error(self.vim, message)