import glob, os, pwd
import method, util

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:
    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)
        if s.startswith('~'):
            users = ['~%s' % (x[0]) for x in pwd.getpwall()]
            candidates = [util.expand_tilde(user) for user in users if user.startswith(s)]
        else:
            candidates = glob.glob(s + '*')
        for i in range(0, len(candidates)):
            c = candidates[i]
            if os.path.isdir(os.path.realpath(c)):
                candidates[i] = c + '/'
        return candidates

class BufferCompleter(Completer):
    def __init__(self, application):
        self.application = application
    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 get_candidates(self, s, w=None):
        path = os.getenv('PATH')
        path_dirs = path.split(':')
        candidates = []
        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.append(p)
        return candidates

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

class MethodCompleter(Completer):
    def get_candidates(self, s, w=None):
        return [n for n in w.application.methods 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)]

class PerlFunctionCompleter(Completer):
    def get_candidates(self, s, w=None):
        old_window = w.buffer.method.old_window
        functions = old_window.mode.get_functions()
        return [n for n in functions if n.startswith(s)]