from curses import ascii
import os, os.path
import box, window

debug_file = None

def file_completion (path):
    # returns a list of all files/directories in the same directory as path
    dirname = os.path.dirname (path)
    try:
        return os.listdir (dirname)
    except OSError: pass
    return ()

def complete_partial (str, completion):
    options = completion (str)

    # filter out those options that don't match the string so far, if
    # any
    options = filter (lambda opt: opt.startswith (str), options)

    # if we just ruled out everything, nothing we can do
    if not options:
        return str

    # otherwise find the most characters we can insert that are present
    # in all of those options and return it
    return os.path.commonprefix (options) 

def read_input (win, y, x, width, initial, completion):

    """ Reads a string on a single line.  Supports insertion, maneuvering,
    and the like. 

    win:        window to draw on
    y,x:        coordinate to start text input
    width:      max num of chars to display without scrolling
    initial:    initial value of string
    completion: a function which, when provided with a partial string,
                returns a list of valid completions for the string.
                We will automatically insert the characters we can and
                perhaps prompt with the remaining choices """

    curx = x
    strval = initial
    startidx = 0

    while 1:
        # Determine portion of string to display and display it:
        dispstr = strval [ startidx : startidx + width ]
        win.addstr (y, x, "%-*s" % (width,dispstr))
        win.move (y, curx)               # set cursor position
        win.refresh ()

        # Compute index of string that cursor represents.
        curidx = curx - x + startidx
        assert curidx <= len (strval) and curidx >= 0

        # Get input.  These commands may adjust 'curx' or 'strval';
        # after they have run we will do some post processing to ensure
        # that the cursor stays within the desired region etc
        ch = win.getch ()
        if ch == window.KEY_LEFT:
            curx -= 1
            pass
        elif ch == window.KEY_RIGHT:
            curx += 1
            pass
        elif ch in (10,13):                             # newline
            return strval
        elif ch in (ascii.BS, window.KEY_BACKSPACE):
            if curidx:
                strval = strval[:curidx-1] + strval[curidx:]
                curx -= 1
                pass
            pass
        elif ch == ascii.SOH:                           # ^a
            curx -= curidx
            pass
        elif ch == ascii.ENQ:                           # ^e
            curx += len (strval) - curidx
            pass
        elif ch == ascii.EOT:                           # ^d
            strval = strval[:curidx] + strval[curidx+1:]
            pass
        elif ch == ascii.VT:                            # ^k
            strval = strval[:curidx]
            pass
        elif ascii.isprint(ch):
            strval = strval[:curidx] + chr(ch) + strval[curidx:]
            curx += 1
            pass

        # If we scrolled off the right side, shift the string to the right
        # (if we can)
        maxx = x + width
        if curx > maxx:
            if len (strval) > width:
                # shift string to the right by as many characters as
                # we went over
                startidx += curx - maxx
                
                # always display as much of the string as we can though, don't
                # shift too far
                if startidx + width > len (strval):
                    startidx = len (strval) - width
                    pass
                assert startidx + width <= len (strval)
                pass
            else:
                startidx = len (strval) - width
                if startidx < 0: startidx = 0
                pass
            curx = maxx # set to far right; it may be adjusted below
            pass
                
        if curx < x:
            startidx -= x - curx
            curx = x
            if startidx < 0: startidx = 0
            pass

        # Don't let user maneuver past the end of the string either
        if curx - x + startidx > len (strval):
            curx = x + len (strval) - startidx
            pass

        pass
    pass

def input_box (win, prompt, initial, inputsize, completionfunc=None):

    """ Draws a box on the screen with a space for input.  The prompt
    given will be displayed, and then a space for input that initially
    contains 'initial' and is 'inputsize' characters long is
    displayed. """

    totalsz = len (prompt) + inputsize
    y = win.height/2 - 1
    x = win.width/2 - totalsz/2
    box.box (win, y, x, 1, totalsz)
    win.addstr (y+1, x+1, prompt)
    return read_input (win, y+1, x+len(prompt)+1,
                       inputsize, initial, completionfunc)

def test (win):
    global choiceres

    size = 10
    initial = "ten characters"
    prompt = "Type: "
    choiceres = input_box (win, prompt, initial, size)
    pass
        
if __name__ == "__main__":
    debug_file = open ('x.debug.out', 'w')
    window.start (test)
    print "chose: %s" % choiceres

            
        
    
