# vim: expandtab tabstop=4
from StringIO import StringIO
import re
import string
from trac.util import escape

rules = re.compile(r"""(?P<heading>^\s*(?P<hdepth>=+)\s(?P<header>.*)\s(?P=hdepth)\s*$)""")
anchor = re.compile('[^\w\d]+')
list_types = ['upper-roman', 'upper-alpha', 'decimal', 'lower-alpha', 'lower-roman']
in_li=[False,False,False,False,False,False]

def parse_toc(env, out, page, body):
    depth = 0
    in_example = False
    just_closed = False
    for line in body.splitlines():
        line = escape(line)

        # Skip over wiki-escaped code, e.g. code examples
        if in_example:
            if line == '}}}':
                in_example = False
            else:
                continue
        if line == '{{{':
            in_example = True
            continue

        # If we're not in an example block, check for list stuff
        match = rules.match(line)
        if match:
            header = match.group('header')
            new_depth = len(match.group('hdepth'))
            if new_depth > depth:
                while new_depth > depth:
                    list_type = list_types[depth%len(list_types)]
                    if not in_li[depth] and depth>0:
                        out.write("<li>\n")
                        in_li[depth]=True
                    out.write("<ol class=\"toc-depth%d\" style=\"list-style-type: %s;\">\n" % (depth+1, list_type))
                    depth += 1
                    in_li[depth]=False
            elif new_depth < depth:
                while new_depth < depth:
                    if in_li[depth]:
                        out.write("</li>\n")
                    out.write("</ol>\n")
                    just_closed = True
                    depth -= 1
            else:
                out.write("</li>\n")
                in_li[depth]=False
            link = page + "#" + anchor.sub("", header)

            # If just closed an <ol>, open a new <li>
            if just_closed:
                out.write('</li>\n')
                out.write('<li>\n')
                just_closed = False
            if not in_li[depth]:
                out.write('<li>\n')
                in_li[depth]=True
            #out.write('%s\n' % (header))
            out.write('<a href="%s">%s</a>' % (env.href.wiki(link), header))

    # Done reading, get back to level zero
    new_depth=0
    while new_depth < depth:
        if in_li[depth]:
            out.write("</li>\n")
        out.write("</ol>\n")
        depth -= 1

def execute(hdf, args, env):
    db = env.get_db_cnx()
    out = StringIO()
    out.write("<div class='wiki-toc'>\n")
    out.write("<h4>Table of Contents</h4>\n")
    # Has the user supplied a list of pages?
    if not args:
        args = hdf.getValue("args.page", "WikiStart")
    pages = re.split('\s*,\s*', args)
    for page in pages:
        cursor = db.cursor()
        cursor.execute("SELECT text FROM wiki WHERE name='%s' ORDER BY version desc LIMIT 1" % page)
        row = cursor.fetchone()
        if row:
            parse_toc(env, out, page, row[0])
        else:
            out.write('<div class="system-message"><strong>Error: Page %s does not exist</strong></div>' % page)
    out.write("</div>\n")
    return out.getvalue()

