""" All Oath functions take an OathWindow; over time, I intend to move
away all direct curses calls and put them into OathWindow which will
form an abstraction layer. The OathWindow also handles any unicode
encoding or decoding that may be required; when it is created, you
tell it what encoding the terminal expects.  Perhaps this can later be
autodetected.

To Start Oath and get your initial oath window, you should call the
function start() in this file.  It starts up curses, creates an
initial oath window, and calls your user function with a single
argument (the oath window).  Very similar to curses.wrapper."""

import codecs, types
import curses, curses.textpad, curses.ascii, traceback, re

# Copy key/attr/color constants:
for item in dir (curses):
    if item[:4] == "KEY_" or item[:2] == "A_" or item[:6] == "COLOR_":
        globals() [item] = getattr (curses, item)
        pass
    pass

class OathWindow:

    def __init__ (self, scr, height, width, encoding, colors):
        self.scr = scr # curses screen object
        self.height = height
        self.width = width
        self.encoding = encoding
        self.debug_file = None
        self.colors = colors
        pass

    def clear (self):
        self.scr.clear ()
        self.scr.refresh ()
        pass

    def str (self, object):
        if type (object) in (types.UnicodeType, types.StringType):
            return object
        return str (object)

    def debug_on (self):
        self.debug_file = open ('x.debug', 'w')
        pass

    def debug (self, str, *choices):
        if self.debug_file:
            if choices: str = str % choices
            str = self.encode (str)
            self.debug_file.write (str)
            pass
        pass
    
    # The OathWindow configuration specifies an encoding to write data to
    # the window in.  Most Oath functions handle data in unicode form,
    # then encode at the last minute.  All Oath Window functions take data
    # in unicode form.
    def encode (self, object):
        if type (object) == types.UnicodeType:
            return object.encode (self.encoding, 'replace')
        if type (object) == types.StringType:
            return object
        return self.encode (str (object))

    # Curses "abstraction" barrier:

    def newwin (self, height, width, y, x):

        """ Returns a subwindow """

        subscr = curses.newwin (height, width, y, x)
        res = OathWindow (subscr, height, width, self.encoding, self.colors)
        res.debug_file = self.debug_file
        return res

    def border (self):
        self.scr.border ()
        pass

    def refresh (self):
        self.scr.refresh ()
        pass

    def move (self, y, x):
        self.scr.move (y, x)
        pass

    def untouchwin (self):
        self.scr.untouchwin ()
        pass

    def getch (self):
        return self.scr.getch ()

    def color (self, name):
        return self.colors[name]

    def addstr (self, y, x, text, attr = A_NORMAL):
        bytes = self.encode (text)
        assert type (bytes) == types.StringType
        self.scr.addstr (y, x, bytes, attr)
        pass
    pass

def start (funcptr,
           encoding='ascii',
           colors={}):

    """
    funcptr: your main() function which we will invoke

    encoding: the encoding of text to be sent out to the screen.  Defaults
    to ascii.

    colors: a dictionary whose keys are strings indices and whose
    values are a pair (fg,bg) where fg,bg are COLOR_ constants from
    this file.  You can later reference this color by typing
    window.color (name); this will return attributes to be added
    to addstr() """
    
    # Initializes curses library:
    stdscr = curses.initscr ()
    curses.start_color ()
    curses.noecho ()
    curses.cbreak ()
    stdscr.keypad (1)

    colorpairs = {}
    index = 1
    for name, (fgc, bgc) in colors.items():
        curses.init_pair (index, fgc, bgc)
        attr = curses.color_pair (index)
        colorpairs[name] = attr
        index += 1
        pass

    # Create oath window
    win = OathWindow (stdscr, curses.LINES, curses.COLS, encoding, colorpairs)

    try:
        # Run the user's code
        funcptr (win)
    finally:
        # clean up after them:
        curses.nocbreak ()
        stdscr.keypad (0)
        curses.echo ()
        curses.endwin ()
        pass

    return
