from trac.core import *
from trac.util import escape
from trac.util.html import Markup
from trac.wiki.formatter import wiki_to_oneliner
from trac.wiki.macros import WikiMacroBase
from StringIO import StringIO
import csv

class SmartTable(WikiMacroBase):
    """
    Builds a table based on CSV or tab-delimited text. The first row contains
    parameters to configure the interpretation of the data. All parameters are
    optional, so it is OK to not specify any.

    == Dialect parameters ==
    If no formatting parameters are specified, the macro tries to guess the
    format. This should work for most CSV types, but if there is a lot of
    wiki markup, specifically quotes (') to do bold or italics, it can confuse
    the guessing process thinking that the wiki markup are delimiters or
    attempts to quote whitespace.
    
     * tab: Excel tab-delimited format (good for copy/paste to/from Excel)
     * comma: Excel comma-delimited ("CSV file") format

    == Other parameters ==
     * nowiki: prints text verbatim, not interpreting any wiki markup
     * heading: the first data row contains header cells
     
    The data begins in the second row.
    """
    
    def render_macro(self, req, name, content):
        sniffer = csv.Sniffer()
        enc = content.encode('ascii', 'replace')
        data = StringIO(enc)
        firstline = data.readline()
        #nieve argument "parsing" -- the real format is:
        #a b c (words separated by whitespace)
        #in case the "find" method turns unambiguous
        if firstline.find('tab') >= 0:
            dialect = csv.excel_tab()
        elif firstline.find('comma') >= 0:
            dialect = csv.excel()
        else:
            temp = StringIO(enc) #read lines 2 and after and sniff
            temp.readline()
            dialect = sniffer.sniff( temp.read(-1) )

        if firstline.find('heading') >= 0:
            rowTemplate = '<th>%s</th>' #start with header row
        else:
            rowTemplate = '<td>%s</td>' #start with normal row

        if firstline.find('nowiki') >= 0:
            wikify = False
        else:
            wikify = True
        
        reader = csv.reader( data, dialect )
        out = StringIO()
        out.write('<table class="wiki">\n')
        for row in reader:
            out.write('<tr>')
            for col in row:
                if wikify:
                    out.write(rowTemplate % wiki_to_oneliner(col, self.env))
                else:
                    out.write(rowTemplate % escape(col))
            out.write('</tr>\n')
            rowTemplate = '<td>%s</td>' #go back to normal rows
        out.write('</table>\n')
        return Markup( out.getvalue() )
