"""
    MoinMoin - PageDicts

    This macro uses the wikidicts mechanism for treating pages as dicts to
    then display a selection of pages in a table.

    Use it like this:
    [[PageDicts(Bug0, Description, Status, Status ~= open)]]

    This will draw a table with the columns pages, Description and
    Status for all pages whos titles match Bug0 with Status matching
    open. This can be used in many different scenarios, with
    appropriate templates.

    @copyright: 2006 by michael cohen <scudette@users.sourceforge.net>
    @license: GNU GPL, see COPYING for details.
    History:
    0.3: Fix typo, allow the "transpose" keyword to change the table layout
    0.2: original version
"""
import re
from MoinMoin import wikiutil, wikidicts
from MoinMoin.Page import Page
from MoinMoin.util.dataset import TupleDataset, Column
from MoinMoin.widget.browser import DataBrowserWidget

Dependencies = ["pages"]

def parse_condition(arg):
    """ arg is a string which will be parsed into a condition dict.

    A condition is a way of enforcing a requirement on a dict d. For example:

    ## This will match if regex matches d['column_name']
    column_name ~= regex

    ## This will not match if regexp matches (inverse of above)
    column_name !~= regex
    """
    if '!~=' in arg:
        tmp = arg.split("!~=",1)
        result=dict(
            column= tmp[0].strip(),
            regex= re.compile(tmp[1].strip(), re.IGNORECASE),
            func = lambda condition,dictionary: not condition['regex'].search(dictionary[condition['column']])
            )

        return result
    elif '~=' in arg:
        tmp = arg.split("~=",1)
        result = dict(
            column = tmp[0].strip(),
            regex = re.compile(tmp[1].strip(), re.IGNORECASE),
            func = lambda condition,dictionary: condition['regex'].search(dictionary[condition['column']])
            )

        return result

def match_conditions(conditions, dictionary):
    """ Returns true if all conditions match, false if any fail to match """
    for condition in conditions:
        if not condition['func'](condition,dictionary):
            return False

    return True

def execute(macro, args):
    request = macro.request
    args = [ arg.strip() for arg in args.split(',') ]
    conditions = []
    transpose = 0 ## if we transpose the results
    needle = args[0]
    if not needle:
        return macro.formatter.text("It is probably not a good idea to parse all pages as dicts? You must specify a title filter")

    try:
        args = args[1:]
    except IndexError:
        args = []

    ## Remove the args which are conditions and look for transpose flag
    for i in range(len(args)):
        condition = parse_condition(args[i])
        if condition:
            conditions.append(c)
            args[i]=None
        elif 'transpose' in args[i]:
            transpose = 1
            args[i]=None

    results = request.rootpage.getPageList(filter=re.compile(needle).search)
    results.sort()
    
    table = TupleDataset()
    table.addRow( [ '', ] + [ arg for arg in args if arg ])

    ## Look at all the pages that matched our string
    for page in results:
        dictionary = wikidicts.Dict(request, page)
        
        ## Check to make sure that the conditons are matched
        if not match_conditions(conditions, dictionary):
            continue

        ## Add the row to the table
        row = [ Page(request, page).link_to(request) ]
	cols = [ dictionary.get(column,'') for column in args if column ]
        
	## look if we have something in a column at all
	found = [ 1 for col in cols if col ]

	## only print the row if it has something
	if found:
        	table.addRow(row + cols)

    if transpose:
        ## transpose table (make column rows and rows columns)
        table.data = map(None, zip(*table.data))
    ## create the top columns
    table.columns = [ Column(col, label=col, align='right') for col in table.data[0] ]
    ## remove the row extracted as the column
    table.data = table.data[1:]
    tmp = DataBrowserWidget(request)
    tmp.setData(table)
    return tmp.toHTML()
