# -*- coding: utf-8 -*-
"""
    Jinja Documenation Builder
"""
import sys
import os
import re
from docutils import nodes, utils
from docutils.core import publish_parts
from docutils.writers import html4css1
from xml.sax import saxutils
from jinja import Template, Context, StringLoader

TEMPLATE = """
<?xml version="1.0" encoding="utf-8"?>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title>{{ title }} | Jinja Documentation</title>
    <style text="text/css">
        body {
            font-family: 'Arial', sans-serif;
            margin: 1em;
            padding: 0;
        }

        #navigation {
            float: right;
            margin: -1em -1em 1em 1em;
            padding: 1em 2em 0 2em;
            border: 1px solid #bbb;
            border-width: 0 0 1px 1px;
            background-color: #f8f8f8;
        }

        #page {
            width: 45em;
        }

        a {
            color: #d00;
        }

        a:hover {
            color: #d40;
        }

        h1 {
            font-size: 2em;
            color: #d00;
            margin: 0.5em 0 0.5em 0;
            padding: 0;
        }

        h2 {
            font-size: 1.7em;
            color: #bd2121;
            margin: 1em 0 0.5em 0;
        }

        h3 {
            font-size: 1.3em;
            color: #8a2424;
            margin: 0.5em 0 0 0;
        }

        p {
            margin: 0.5em 1em 0.5em 1em;
        }

        pre {
            margin: 1em 0 1em 2em;
            padding: 0.5em;
            border-top: 1px solid #ddd;
            border-bottom: 1px solid #ddd;
            background-color: #f2f2f2;
            overflow: auto;
        }
        
        li {
            line-height: 1.4em;
        }
        
        hr {
            margin: 1em;
            padding: 0;
            height: 1px!important;
            background-color: #ccc;
            border: none!important;
        }
        
        div.admonition {
            margin: 1em 0 1em 1.5em;
            padding: 0.5em 0.5em 0.5em 2em;
            background-color: #f6e3e3;
            border: 1px solid #d50000;
            border-left: none;
            border-right: none;
        }
        
        div.admonition p.admonition-title {
            font-size: 1.1em;
            color: #d40;
            font-weight: bold;
            margin: 0 0 0.5em -1em;
        }
        
        table {
            border-collapse: collapse;
            margin: 1em 2em 1em 1.5em;
        }
        
        table td, table th {
            text-align: left;
            border: 1px solid #eee;
            padding: 0.3em;
        }
        
        table th {
            background-color: #d00000;
            color: white;
            border: 1px solid #d00000;
            border-bottom: 1px solid #eee;
        }
    </style>
</head>
<body>
    <div id="navigation">
        <h3>Documentation</h3>
        <ul>
            {% if not root %}
            <li><a href="index.html">back to index</a></li>
            {% endif %}
            <li><a href="http://wsgiarea.pocoo.org/repos/jinja/trunk/docs/source/{{ fid }}.txt">view source online</a></li>
        </ul>
        {% if toc %}
            <h3>Table of Contents</h3>
            <ul>
            {% for item in toc %}
                <li><a href="{{ item.href }}">{{ item.caption }}</a></li>
            {% endfor %}
            </ul>
        {% endif %}
    </div>
    <h1>{{ title }}</h1>
    <div id="page">
        {{ body }}
    </div>
</body>
</html>
"""[1:]

class DocumentationBuilder(object):

    def __init__(self, root, dest, rules):
        self.root = root
        self.rules = rules
        self.dest = dest
            
    def build(self):
        for folder, subfolders, files in os.walk(self.root):
            searchpath = []
            if '.svn' in subfolders:
                subfolders.remove('.svn')
            for f in files:
                f = os.path.join(folder, f)[len(self.root):]
                for rule, params in self.rules:
                    m = rule.search(f)
                    if m is None:
                        continue
                    fid = f.rsplit('/', 1)[-1].rsplit('.')[0]
                    output = self.render(fid, f, params)
                    self.save(fid, f, output, params)
                    break
                
    def render(self, fid, f, params):
        writer = PageWriter()
        parts = publish_parts(
            file(os.path.join(self.root, f)).read(),
            source_path=f,
            writer=writer,
            settings_overrides={'initial_header_level': 2}
        )
        template = Template(TEMPLATE, StringLoader())
        return template.render(Context({
            'title': parts['title'],
            'body': parts['body'],
            'toc': parts['toc'],
            'root': fid == 'index',
            'fid': fid
        })).encode('utf-8')
        
    def save(self, fid, f, output, params):
        folder = os.path.join(self.dest, params.get('dest', ''))
        filename = '%s.html' % fid
        try:
            os.makedirs(folder)
        except OSError:
            pass
        fp = file(os.path.join(folder, filename), 'w')
        fp.write(output)
        fp.close()


class PageWriter(html4css1.Writer):
    
    def __init__(self):
        html4css1.Writer.__init__(self)
        self.translator_class = PageTranslator

    def translate(self):
        html4css1.Writer.translate(self)
        contents = self.build_contents(self.document)
        contents_doc = self.document.copy()
        contents_doc.children = contents
        contents_visitor = self.translator_class(contents_doc)
        contents_doc.walkabout(contents_visitor)

        toc = []
        tmp = {}
        for item in contents_visitor.fragment:
            if not item or item in ('<li>', '</li>'):
                continue
            elif item.startswith('<a class="reference" '):
                tmp['href'] = re.search('href="(.*?)"', item).group(1)
            elif item == '</a>':
                toc.append(tmp)
                tmp = {}
            else:
                tmp['caption'] = item 
        self.parts['toc'] = toc

    def build_contents(self, node, level=0):
        level += 1
        sections = []
        i = len(node) - 1
        while i >= 0 and isinstance(node[i], nodes.section):
            sections.append(node[i])
            i -= 1
        sections.reverse()
        entries = []
        autonum = 0
        depth = 4   # XXX FIXME
        for section in sections:
            title = section[0]
            entrytext = title
            try:
                reference = nodes.reference('', '', refid=section['ids'][0], *entrytext)
            except IndexError:
                continue
            ref_id = self.document.set_id(reference)
            entry = nodes.paragraph('', '', reference)
            item = nodes.list_item('', entry)
            if level < depth:
                subsects = self.build_contents(section, level)
                item += subsects
            entries.append(item)
        if entries:
            contents = nodes.bullet_list('', *entries)
            return contents
        else:
            return []

class PageTranslator(html4css1.HTMLTranslator):
    
    def visit_table(self, node):
        self.body.append(self.starttag(node, 'table', CLASS='docutils'))
    
    def visit_reference(self, node):
        if node.has_key('refuri'):
            href = node['refuri']
            if ( self.settings.cloak_email_addresses
                 and href.startswith('mailto:')):
                href = self.cloak_mailto(href)
                self.in_mailto = 1
        else:
            assert node.has_key('refid'), \
                   'References must have "refuri" or "refid" attribute.'
            href = '#' + node['refid']
        if not '/' in href and href.endswith('.txt'):
            href = './%s.html' % (href[:-4])
        atts = {'href': href, 'class': 'reference'}
        if not isinstance(node.parent, nodes.TextElement):
            assert len(node) == 1 and isinstance(node[0], nodes.image)
            atts['class'] += ' image-reference'
        self.body.append(self.starttag(node, 'a', '', **atts))


if __name__ == '__main__':
    app = DocumentationBuilder(
        'source/', 'build/', [
            (re.compile(r'\.txt$'), {
                'dest':     './',
                'root':     './'
            })
        ]
    )
    app.build()


syntax highlighted by Code2HTML, v. 0.9.1