import re, StringIO
from MoinMoin import config, wikimacro, wikiutil

class DocEmitter:
    """
    Generate the output for the document tree consisting of DocNodes.
    """

    def __init__(self, root, formatter, request):
        self.root = root
        self.formatter = formatter
        self.request = request
        self.form = request.form
        self.macro = None

    def get_image(self, addr, text=''):
        """Return markup for image depending on the address."""
        url = wikiutil.url_unquote(addr, want_unicode=True)
        if addr.startswith('http:'):
            return self.formatter.image(src=url,alt=text, html_class='external_image')
        else:
            return self.formatter.attachment_image(url, alt=text, html_class='image')

    def get_text(self, node):
        """Try to emit whatever text is in the node."""
        try:
            return node.children[0].content or ''
        except:
            return node.content or ''

    # *_emit methods for emitting nodes of the document
    
    def document_emit(self, node):
        return self.emit_children(node)

    def text_emit(self, node):
        return self.formatter.text(node.content or '')
    
    def rule_emit(self, node):
        return self.formatter.rule()
    
    def paragraph_emit(self, node):
        return ''.join([
            self.formatter.paragraph(1),
            self.emit_children(node),
            self.formatter.paragraph(0),
        ])
        
    def bullet_list_emit(self, node):
        return ''.join([
            self.formatter.bullet_list(1),
            self.emit_children(node),
            self.formatter.bullet_list(0),
        ])
        
    def number_list_emit(self, node):
        return ''.join([
            self.formatter.number_list(1),
            self.emit_children(node),
            self.formatter.number_list(0),
        ])
        
    def list_item_emit(self, node):
        return ''.join([
            self.formatter.listitem(1),
            self.emit_children(node),
            self.formatter.listitem(0),
        ])
        
    def definition_list_emit(self, node):
        return ''.join([
            self.formatter.definition_list(1),
            self.emit_children(node),
            self.formatter.definition_list(0),
        ])

    def term_emit(self, node):
        return ''.join([
            self.formatter.definition_term(1),
            self.emit_children(node),
            self.formatter.definition_term(0),
        ])
        
    def definition_emit(self, node):
        return ''.join([
            self.formatter.definition_desc(1),
            self.emit_children(node),
            self.formatter.definition_desc(0),
        ])

    def table_emit(self, node):
        return ''.join([
            self.formatter.table(1, attrs=node.attrs),
            self.emit_children(node),
            self.formatter.table(0),
        ])
        
    def table_row_emit(self, node):
        return ''.join([
            self.formatter.table_row(1, attrs=node.attrs),
            self.emit_children(node),
            self.formatter.table_row(0),
        ])

    def table_cell_emit(self, node):
        return ''.join([
            self.formatter.table_cell(1, attrs=node.attrs),
            self.emit_children(node),
            self.formatter.table_cell(0),
        ])


        
    def emphasis_emit(self, node):
        return ''.join([
            self.formatter.emphasis(1),
            self.emit_children(node),
            self.formatter.emphasis(0),
        ])
        
    def quote_emit(self, node):
        return ''.join([
            self.formatter.rawHTML('<q>'),
            self.emit_children(node),
            self.formatter.rawHTML('</q>'),
        ])
        
    def strong_emit(self, node):
        return ''.join([
            self.formatter.strong(1),
            self.emit_children(node),
            self.formatter.strong(0)
        ])
        
    def smiley_emit(self, node):
        return self.formatter.smiley(node.content)
    
    def header_emit(self, node):
        import sha
        pntt = self.formatter.page.page_name + self.get_text(node)
        ident ="head-"+sha.new(pntt.encode(config.charset)).hexdigest()
        return ''.join([
            self.formatter.heading(1, node.level, id=ident),
            self.formatter.text(node.content or ''),
            self.formatter.heading(0, node.level),
        ])
        
    def code_emit(self, node):
        return ''.join([
            self.formatter.code(1),
            self.formatter.text(node.content or ''),
            self.formatter.code(0),
        ])
        
    def abbr_emit(self, node):
        return ''.join([
            self.formatter.rawHTML('<abbr title="%s">'%node.title),
            self.formatter.text(node.content or ''),
            self.formatter.rawHTML('</abbr>'),
        ])
        
    def page_link_emit(self, node):
        word = node.content
        # handle relative links
        if word.startswith(wikiutil.CHILD_PREFIX):
            word = self.formatter.page.page_name + '/' + word[wikiutil.CHILD_PREFIX_LEN:]
        # handle anchors
        parts = word.split("#", 1)
        anchor = ""
        if len(parts)==2:
            word, anchor = parts
        return ''.join([
            self.formatter.pagelink(1, word, anchor=anchor),
            self.emit_children(node),
            self.formatter.pagelink(0, word),
        ])
        
    def external_link_emit(self, node):
        return ''.join([
            self.formatter.url(1, node.content, css='www %s'%node.proto),
            self.emit_children(node),
            self.formatter.url(0),
        ])

    def anchor_link_emit(self, node):
        return ''.join([
            self.formatter.url(1, node.content, css='anchor'),
            self.emit_children(node),
            self.formatter.url(0),
        ])
        
    def interwiki_link_emit(self, node):
        word = node.content
        (   wikitag,
            wikiurl,
            wikitail,
            wikitag_bad ) = wikiutil.resolve_wiki(self.request, word)
        href = wikiutil.join_wiki(wikiurl, wikitail)
        return ''.join([
            self.formatter.interwikilink(1, wikitag, wikitail),
            self.emit_children(node),
            self.formatter.interwikilink(0),
        ])
        
    def attachment_emit(self, node):
        url = wikiutil.url_unquote(node.content, want_unicode=True)
        text = self.get_text(node)
        return self.formatter.attachment_link(url, text)
    
    def inlined_attachment_emit(self, node):
        url = wikiutil.url_unquote(node.content, want_unicode=True)
        text = self.get_text(node)
        return self.formatter.attachment_inlined(url, text)
     
    def image_emit(self, node):
        text = self.get_text(node)
        return self.get_image(node.content, text)
    
    def drawing_emit(self, node):
        url = wikiutil.url_unquote(node.content, want_unicode=True)
        text = self.get_text(node)
        return self.formatter.attachment_drawing(url, text)
    
    def figure_emit(self, node):
        text = self.get_text(node)
        url = wikiutil.url_unquote(node.content, want_unicode=True)
        return ''.join([
            self.formatter.rawHTML('<div class="figure">'),
            self.get_image(url, text), self.emit_children(node),
            self.formatter.rawHTML('</div>')
        ])
        
    def bad_link_emit(self, node):
        return self.formatter.text(''.join([
            '[[',
            node.content or '',
            ']]',
        ]))
    
    def macro_emit(self, node):
        macro_name = node.content
        args = node.args
        if self.macro is None:
            self.macro = wikimacro.Macro(self)
        try:
            return self.formatter.macro(self.macro, macro_name, args)
        except:
            return self.formatter.text(self.request.getText('macro error'))
        
    def section_emit(self, node):
        return ''.join([
            self.formatter.rawHTML(
                '<div class="%s" style="%s">'%(node.sect, node.style)
            ),
            self.emit_children(node),
            self.formatter.rawHTML('</div>'),
        ])
        
    def blockquote_emit(self, node):
        return ''.join([
            self.formatter.rawHTML('<blockquote>'),
            self.emit_children(node),
            self.formatter.rawHTML('</blockquote>'),
        ])
        
    def preformatted_emit(self, node):
        content = node.content
        self.processor_name = node.sect
        self.processor = None
        if self.processor_name:
            self._setProcessor(self.processor_name)
        if self.processor is None:
            return ''.join([
                self.formatter.preformatted(1),
                self.formatter.text(content),
                self.formatter.preformatted(0),
            ])
        else:
            buff = StringIO.StringIO()
            self.request.redirect(buff)
            try:
                self.formatter.processor(
                    self.processor_name,
                    content.split('\n'),
                    self.processor_is_parser
                )
            finally:
                self.request.redirect()
            return buff.getvalue()

    def default_emit(self, node):
        return ''.join([
            self.formatter.preformatted(1),
            self.formatter.text('<%s>\n'%node.kind),
            self.emit_children(node),
            self.formatter.preformatted(0)
        ])

##
    def emit_children(self, node):
        """Emit all the children of a node."""
        return ''.join([self.emit_node(child) for child in node.children])
   
    def emit_node(self, node):
        try:
            emit = getattr(self, '%s_emit'%node.kind)
        except:
            emit = self.default_emit
        return emit(node)

    def emit(self):
        return '\n'.join([
            self.emit_node(self.root),
        ])

    # From the wiki.py parser
    def _setProcessor(self, name):
        """ Set processer to either processor or parser named 'name' """
        cfg = self.request.cfg
        try:
            self.processor = wikiutil.importPlugin(
                cfg,
                "processor",
                name,
                "process"
            )
            self.processor_is_parser = 0
        except wikiutil.PluginMissingError:
            try:
                self.processor = wikiutil.importPlugin(
                    cfg,
                    "parser",
                    name,
                    "Parser"
                )
                self.processor_is_parser = 1
            except wikiutil.PluginMissingError:
                self.processor = None
