import glob, os, pwd
import method, util

_completers = {}

def set_completer(name, completer):
    global _completers
    _completers[name] = completer

def get_completer(*args):
    return _completers.get(*args)

def find_common_string(candidates):
    if len(candidates) == 0:
        return ""
    elif len(candidates) == 1:
        return candidates[0]
    else:
        done = False
        index = 0
        test = candidates[0]
        while True:
            for c in candidates:
                if len(c) <= index or c[index] != test[index]:
                    return test[:index]
            index += 1
        return test

class Completer(object):
    def __init__(self, application):
        self.application = application
    def get_candidates(self, s):
        assert "Not implemented"
    def tab_string(self, s, w=None):
        '''returns a tuple of three things:
        1. the new string
        2. whether the string "exists"
        3. whether the string is "complete"'''
        candidates = self.get_candidates(s, w)
        if len(candidates) == 0:
            return (s, False, True)
        elif len(candidates) == 1:
            return (candidates[0], True, True)
        else:
            s2 = find_common_string(candidates)
            if s2 in candidates:
                return (s2, True, False)
            else:
                return (s2, False, False)

class FileCompleter(Completer):
    def get_candidates(self, s, w=None):
        s = util.expand_tilde(s)
        #raise Exception(s + '*')
        candidates = [util.normal_path(p) for p in glob.glob(s + '*')]

        # ignore some suffixes by default, unless the only possible completions
        # ALL have ignored-suffixes, in which case just return them all.
        candidates2 = []
        for c in candidates:
            ok = True
            for suffix in self.application.config['ignore_suffix']:
                if c.endswith(suffix):
                    ok = False
                    break
            if ok:
                candidates2.append(c)

        if candidates2:
            candidates = candidates2
        #raise(s + "* :: " + repr(candidates))
        return candidates

class BufferCompleter(Completer):
    def get_candidates(self, s, w=None):
        bl = self.application.bufferlist
        candidates = [b.name() for b in bl.buffers if b.name().startswith(s)]
        return candidates

class CommandCompleter(Completer):
    def __init__(self, application):
        Completer.__init__(self, application)
        self.fc = FileCompleter(application)
    def get_candidates(self, s, w=None):
        if s.startswith('~') or s.startswith('/') or s.startswith('./') or s.startswith('../'):
            return self.fc.get_candidates(s)

        path = os.getenv('PATH')
        path_dirs = path.split(':')
        candidates = set()
        for d in path_dirs:
            if (not os.path.isdir(d) or not os.access(d, os.R_OK)):
                continue
            for p in os.listdir(d):
                if not os.path.isfile(os.path.join(d, p)):
                    continue
                elif not p.startswith(s):
                    continue
                else:
                    candidates.add(p)
        return sorted(candidates)

class ShellCompleter(Completer):
    def __init__(self, application):
        Completer.__init__(self, application)
        self.fc = FileCompleter(application)
        self.cc = CommandCompleter(application)
    def get_candidates(self, s, w=None):
        if ' ' in s:
            i = s.rindex(' ') + 1
            base = s[:i]
            last = s[i:]
            candidates = self.fc.get_candidates(last)
            return [base + x for x in candidates]
        else:
            return self.cc.get_candidates(s)

class TokenCompleter(Completer):
    def get_candidates(self, s, w=None):
        w2 = w.buffer.method.old_window
        t = w2.get_token2()
        h = w2.get_highlighter()
        candidates = {}
        for line in h.tokens:
            for t2 in line:
                if t2 is t:
                    continue
                elif t2.string.startswith(s):
                    candidates[t2.string] = 1
        return candidates.keys()

class MethodCompleter(Completer):
    def get_candidates(self, s, w=None):
        return [n for n in w.application.methods if n.startswith(s)]

class ConfigCompleter(Completer):
    def get_candidates(self, s, w=None):
        return [n for n in w.application.config if n.startswith(s)]

class RegisterCompleter(Completer):
    def get_candidates(self, s, w=None):
        return [n for n in w.application.registers if n.startswith(s)]

class ModeCompleter(Completer):
    def get_candidates(self, s, w=None):
        return [n for n in w.application.modes if n.startswith(s)]