"""
cgitb.py
  By Ka-Ping Yee <ping@lfw.org> http://web.lfw.org/python/
  Modified for Webware by Ian Bicking <ianb@colorstudy.com>
"""

import sys, os, types, string, keyword, linecache, tokenize
# We include a copy of pydoc but since it's in the Python 2.1
# standard library, we'll try to import it there first.
try:
    import pydoc
except ImportError:
    from MiscUtils import pydoc
# But we need to use a fixed version of inspect, so we won't use the one that comes with Python 2.1.
from MiscUtils import inspect

DefaultOptions = {
    'table.bgcolor':        '#F0F0F0',
    'default.fgcolor':      '#000000',
    'row.location.fgcolor': '#0000AA',
    'row.code.fgcolor':     '#FF0000',
    'header.fgcolor':       '#ffffff',
    'header.bgcolor':       '#a00000',
    'subheader.fgcolor':    '#000000',
    'subheader.bgcolor':    '#ccccff',
    'code.accent.bgcolor':  '#ddeeff',
    'code.unaccent.fgcolor':'#909090',
}

def breaker():
    return ('<body bgcolor="#f0f0ff">' +
            '<font color="#f0f0ff" size="-5"> > </font> ' +
            '</table>' * 5)

def html(context=5, options = None):
    if options:
        opt = DefaultOptions.copy()
        opt.update(options)
    else:
        opt = DefaultOptions

    etype, evalue = sys.exc_info()[:2]
    if type(etype) is types.ClassType:
        etype = etype.__name__
    inspect_trace = inspect.trace(context)
    inspect_trace.reverse()

    pyver = 'Python ' + string.split(sys.version)[0] + '<br>' + sys.executable
    javascript = """
    <script language="JavaScript"><!--
    function popup_repr(title, value) {
        var w = window.open('', '_blank',
                        'directories=no,height=200,width=400,location=no,menubar=yes,scrollbars=yes,status=no,toolbar=no');
        w.document.write('<html><head><title>' + title + '</title></head><body bgcolor="#ffffff">');
        w.document.write(value);
        w.document.write('<form><input type="button" onClick="window.close()" value="close window"></form></body></html>');
    }
    // --></script>"""
        
    traceback_summary = []
    for frame, file, lnum, func, lines, index in inspect_trace:
        traceback_summary.append('<a href="#%s%i"><font color="%s">%s</font></a><font color="%s">:<tt style="font-family: Courier, sans-serif">%s</tt></font>' %
                                 (string.replace(file, "/", "_"),
                                  lnum,
                                  opt["header.fgcolor"],
                                  os.path.splitext(os.path.basename(file))[0],
                                  opt["header.fgcolor"],
                                  string.replace("%5i" % lnum, " ", " ")))
    head = '<table bgcolor="%s" cellspacing=0 border=0><tr><td valign=top align=left><font color="%s"><big><big><strong>%s</strong></big></big>: %s</font></td><td rowspan=2 valign=top align=right>%s</td></tr>' % \
        (opt['header.bgcolor'], opt['header.fgcolor'], str(etype),
         pydoc.html.escape(str(evalue)),
         string.join(traceback_summary, "<br>\n"))

    head = head + '<tr><td valign=top bgcolor="#ffffff"><br>\n'
    head = head + ('<p>A problem occurred while running a Python script. '
                   'Here is the sequence of function calls leading up to '
                   'the error, with the most recent (innermost) call first.')
    head = head + '</td></tr></table>\n'

    indent = '<tt><small>%s</small> </tt>' % (' ' * 5)
    traceback = []
    for frame, file, lnum, func, lines, index in inspect_trace:
        if not file: file = "not found"
        file = os.path.abspath(file)
        try:
            file_list = string.split(file, "/")
            display_file = string.join(file_list[file_list.index("Webware") + 1:], "/")
        except ValueError:
            display_file = file
        if display_file[-3:] == ".py":
            display_file = display_file[:-3]
        link = '<a name="%s%i"></a><a href="file:%s">%s</a>' % (string.replace(file, "/", "_"), lnum, file, pydoc.html.escape(display_file))
        args, varargs, varkw, locals = inspect.getargvalues(frame)
        if func == '?':
            call = ''
        else:
            call = 'in <strong>%s</strong>' % func + inspect.formatargvalues(
                    args, varargs, varkw, locals,
                    formatvalue=lambda value: '=' + html_repr(value))

        names = []
        dotted = [0, []]
        def tokeneater(type, token, start, end, line, names=names, dotted=dotted):
            if type == tokenize.OP and token == ".":
                dotted[0] = 1
            if type == tokenize.NAME and token not in keyword.kwlist:
                if dotted[0]:
                    dotted[0] = 0
                    dotted[1].append(token)
                    if token not in names:
                        names.append(dotted[1][:])
                elif token not in names:
                    if token != "self": names.append(token)
                    dotted[1] = [token]
            if type == tokenize.NEWLINE: raise IndexError
        def linereader(file=file, lnum=[lnum]):
            line = linecache.getline(file, lnum[0])
            lnum[0] = lnum[0] + 1
            return line

        try:
            tokenize.tokenize(linereader, tokeneater)
        except IndexError: pass
        lvals = []
        for name in names:
            if type(name) is type([]):
                if locals.has_key(name[0]) or frame.f_globals.has_key(name[0]):
                    name_list, name = name, name[0]
                    if locals.has_key(name_list[0]):
                        value = locals[name_list[0]]
                    else:
                        value = frame.f_globals[name_list[0]]
                        name = "<em>global</em> %s" % name
                    for subname in name_list[1:]:
                        if hasattr(value, subname):
                            value = getattr(value, subname)
                            name = name + "." + subname
                        else:
                            name = name + "." + "(unknown: %s)" % subname
                            break
                    name = '<strong>%s</strong>' % name
                    if type(value) is types.MethodType and 1:
                        value = None
                    else:
                        value = html_repr(value)
            elif name in frame.f_code.co_varnames:
                if locals.has_key(name):
                    value = html_repr(locals[name])
                else:
                    value = '<em>undefined</em>'
                name = '<strong>%s</strong>' % name
            else:
                if frame.f_globals.has_key(name):
                    value = html_repr(frame.f_globals[name])
                else:
                    value = '<em>undefined</em>'
                name = '<em>global</em> <strong>%s</strong>' % name
            if value is not None:
                lvals.append('%s = %s' % (name, value))
        if lvals:
            lvals = string.join(lvals, ', ')
            lvals = indent + '''
<small><font color="%s">%s</font></small><br>''' % (opt['code.unaccent.fgcolor'], lvals)
        else:
            lvals = ''

        level = '''
<table width="100%%" bgcolor="%s" cellspacing=0 cellpadding=2 border=0>
<tr><td><font color="%s">%s %s</font></td></tr></table>''' % (opt['subheader.bgcolor'], opt['subheader.fgcolor'], link, call)
        excerpt = []
        try:
            i = lnum - index
        except TypeError:
            i = lnum
        lines = lines or ['file not found']
        for line in lines:
            number = ' ' * (5-len(str(i))) + str(i)
            number = '<small><font color="%s">%s</font></small>' % (opt['code.unaccent.fgcolor'], number)
            line = '<tt>%s %s</tt>' % (number, pydoc.html.preformat(line))
            if i == lnum:
                line = '''
<table width="100%%" bgcolor="%s" cellspacing=0 cellpadding=0 border=0>
<tr><td>%s</td></tr></table>''' % (opt['code.accent.bgcolor'], line)
            excerpt.append('\n' + line)
            if i == lnum:
                excerpt.append(lvals)
            i = i + 1
        traceback.append('<p>' + level + string.join(excerpt, '\n'))

    exception = '<p><strong>%s</strong>: %s' % (str(etype), str(evalue))
    attribs = []
    if type(evalue) is types.InstanceType:
        for name in dir(evalue):
            value = html_repr(getattr(evalue, name))
            attribs.append('<br>%s%s = %s' % (indent, name, value))

    return javascript + head + string.join(traceback) + exception + string.join(attribs)

def handler():
    print breaker()
    print html()

def html_repr(value):
    html_repr_instance = pydoc.html._repr_instance
    enc_value = pydoc.html.repr(value)
    if len(enc_value) > html_repr_instance.maxstring:
        plain_value = pydoc.html.escape(repr(value))
        return '%s <a href="#" onClick="popup_repr(\'Long repr\', \'Full representation:<br>\\n%s\'); return false">(complete)</a>' \
               % (enc_value, string.replace(string.replace(pydoc.html.escape(plain_value), "'", "\\'"), '"', '"'))
    else:
        return enc_value

if __name__ == '__main__':
    try: import tester
    except: handler()