# Copyright David Abrahams 2007. Distributed under the Boost
# Software License, Version 1.0. (See accompanying
# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
from datetime import datetime
import imp
import inspect
import os
import re
from StringIO import StringIO

from genshi.builder import Element, tag
from genshi.core import Markup

from trac.core import *
from trac.util.datefmt import format_date, utc
from trac.util.compat import sorted, groupby, any, set
from trac.util.html import escape
from trac.util.translation import _
from trac.wiki.api import IWikiMacroProvider, WikiSystem, parse_args
from trac.wiki.formatter import format_to_html, format_to_oneliner, \
                                extract_link, OutlineFormatter
from trac.wiki.model import WikiPage
from trac.web.chrome import add_stylesheet

from trac.wiki.macros import WikiMacroBase

__all__ = [ 'MyTitleIndexMacro' ]

class MyTitleIndexMacro(WikiMacroBase):
    """Inserts an alphabetic list of all wiki pages into the output.

    Accepts a prefix string as parameter: if provided, only pages with names
    that start with the prefix are included in the resulting list. If this
    parameter is omitted, all pages are listed.

    Alternate `format` and `depth` can be specified:
     - `format=group`: The list of page will be structured in groups
       according to common prefix. This format also supports a `min=n`
       argument, where `n` is the minimal number of pages for a group.
     - `depth=n`: limit the depth of the pages to list. If set to 0,
n       only toplevel pages will be shown, if set to 1, only immediate
       children pages will be shown, etc. If not set, or set to -1,
       all pages in the hierarchy will be shown.
    """

    SPLIT_RE = re.compile(r"( |/|[0-9])")

    def expand_macro(self, formatter, name, content):
        args, kw = parse_args(content)
        prefix = args and args[0] or None
        format = kw.get('format', '')
        hideprefix = kw.get('hideprefix', None) 
        minsize = max(int(kw.get('min', 2)), 2)
        depth = int(kw.get('depth', -1))
        start = prefix and prefix.count('/') or 0

        wiki = formatter.wiki
        pages = sorted(wiki.get_pages(prefix))

        if format != 'group':
            return tag.ul([tag.li(tag.a(wiki.format_page_name(page),
                                        href=formatter.href.wiki(page)))
                           for page in pages
                           if depth < 0 or depth >= page.count('/') - start])

        def lstripstring(s, start):
            if s.startswith(start):
                return s[len(start):]
            else:
                return s

        # the string to strip off the beginning of each displayed page title 
        strip_prefix = hideprefix and prefix or ''

        # How many elements of each title should be stripped?  This eliminates
        # upper levels that have no siblings.  Otherwise, when stripping
        # Foo/Bar/ you get something like:
        #
        # * Foo/
        #   * Bar/
        #     * x1
        #     * x2
        #     * ...
        prefix_parts = hideprefix and len(self.SPLIT_RE.split(strip_prefix)) or 0

        # Group by Wiki word and/or Wiki hierarchy
        pages = [
            (self.SPLIT_RE.split(
                    wiki.format_page_name(
                        page, split=True)
            )[prefix_parts:],
            page)
                 
            for page in pages
            if depth < 0 or depth >= page.count('/') - start]
        
        def split_in_groups(group):
            """Return list of pagename or (key, sublist) elements"""
            groups = []
            for key, subgrp in groupby(group, lambda (k,p): k and k[0] or ''):
                subgrp = [(k[1:],p) for k,p in subgrp]
                if key and len(subgrp) >= minsize:
                    sublist = split_in_groups(sorted(subgrp))
                    if len(sublist) == 1:
                        elt = (key+sublist[0][0], sublist[0][1])
                    else:
                        elt = (key, sublist)
                    groups.append(elt)
                else:
                    for elt in subgrp:
                        groups.append(elt[1])
            return groups

        def render_groups(groups):
            return tag.ul(
                [tag.li(isinstance(elt, tuple) and 
                        tag(tag.strong(elt[0]), render_groups(elt[1])) or
                        tag.a(
                            lstripstring(wiki.format_page_name(elt),strip_prefix),
                            href=formatter.href.wiki(elt)))
                 for elt in groups])
        
        return render_groups(split_in_groups(pages))

