# -*- coding: iso-8859-1 -*-
"""
MoinMoin - "text/word" Formatter

Experimental by RS, derived from text_html.py

Create MS Word Document as 'side effect'

ORS modifications
=================
-        13.01.04 RS upgrade to 1.1.
-        20.01.04 RS fatal errors handling
-        22.01.04 RS print replaced by self.request.write
-        28.01.05 RS fixed img handling (path problem)
-        27.09.05 RS upgrade to 1.3.5, old 1.1 code removed

@todo: Handle distorted tables (with spanning cells)        
"""

# Imports
import cgi, string, sys, time, os, re, copy,traceback,urllib
from MoinMoin.formatter.base import FormatterBase
from MoinMoin import wikiutil, config, user,webapi, i18n

from MoinMoin.Page import Page
#RS Word
import win32com.client, win32com.client.dynamic
vbTrue=-1
vbFalse=0
#RS end

DOC_SUFFIX = ".doc"  # perhaps put this in config.py as html_suffix?

#############################################################################
### HTML Formatter
#############################################################################

_debug=1

class Formatter(FormatterBase):
    """
        Send HTML data.
    """

#    hardspace = '&#160;'
    hardspace = ' '

    def __init__(self, request, **kw):
        if _debug:
            traceback.print_stack(limit=1,file=sys.stdout)
        apply(FormatterBase.__init__, (self, request), kw)
#RS additional property "mimetype"
        self.mimetype="text/word"
        sys.stderr.write("\nThis is the Word Formatter....")
#RS end
        self.dead=0
        self.store_text=0 # store text in self._text instead of emitting it
        self.recordedtext=""
        self.recordedcursor=0
        # inline tags stack. When an inline tag is called, it goes into
        # the stack. When a block element starts, all inline tags in
        # the stack are closed.
        self._inlineStack = []

        self._in_li = 0
        self._first_li = 0
        self._first_tr = 0
        self._first_td = 0
        self._table_start=0
        self._ignore_next_paragraph=0
        self.list_levels={'ul':0,'ol':0,'dl':0,'table':0,'all':0}
        self.last_indent_type=''
        self._in_code = 0
        self._base_depth = 0
        self._in_code_area = 0
        self._in_code_line = 0
        self._code_area_num = 0
        self._code_area_js = 0
        self._code_area_state = ['', 0, -1, -1, 0]
        self._show_section_numbers = None
        self._content_ids = []
        self.pagelink_preclosed = False
        self._is_included = kw.get('is_included',False)
        self.request = request
        self.cfg = request.cfg
#        self.targetdir=kw.get('targetdir',config.data_dir)
        self.targetdir=kw.get('targetdir',request.cfg.data_dir)

        if not hasattr(request, '_fmt_hd_counters'):
            request._fmt_hd_counters = []
        self.document=None
        self.doctemplate="D_ORS_Entwicklungsauftrag_v02.dot"
        self.doctemplate="Normal.dot"
        self.word_host = None
        self.doccount=0
        self.tt_start=0
        
    def _reset_indents(self):
        if _debug:
            traceback.print_stack(limit=1,file=sys.stdout)
        self._in_li = 0
        self._first_li = 0
        self._first_tr = 0
        self._first_td = 0
        self._table_start=0
        self._ignore_next_paragraph=0
        self.list_levels={'ul':0,'ol':0,'dl':0,'table':0,'all':0}
        self.last_indent_type=''
        

    def FatalEnd(self):
        """
        make sure we do not leave any ActiveX corpses behind if errors occur
        """
        if _debug:
            traceback.print_stack(limit=1,file=sys.stdout)
        try:
            if self.document is not None:
                self.document.Close(-1)
            if self.word_host is not None:
                self.word_host.Quit()
            self.document=None
            self.word_host=None
        except:
            pass
#            raise
        self.dead=1
        
    def _save(self):
        if _debug:
            traceback.print_stack(limit=1,file=sys.stdout)
#RS fatal error handling
        if self.dead==1:
            return
#RS end
        if self.document!=None:
            self.document.Save()

    # Primitive formatter functions #####################################

    # all other methods should use these to format tags. This keeps the
    # code clean and handle pathological cases like unclosed p and
    # inline tags.

    def langAttr(self, lang=None):
        """ Return lang and dir attribute

        Must be used on all block elements - div, p, table, etc.
        @param lang: if defined, will return attributes for lang. if not
            defined, will return attributes only if the current lang is
            different from the content lang.
        @rtype: dict
        @return: language attributes
        """
        if not lang:
            lang = self.request.current_lang
            # Actions that generate content in user language should change
            # the content lang from the default defined in cfg.
            if lang == self.request.content_lang:
                # lang is inherited from content div
                return {}

        attr = {'lang': lang, 'dir': i18n.getDirection(lang),}
        return attr

    def formatAttributes(self, attr=None):
        """ Return formatted attributes string

        @param attr: dict containing keys and values
        @rtype: string ?
        @return: formated attributes or empty string
        """
        if attr:
            attr = [' %s="%s"' % (k, v) for k, v in attr.items()]           
            return ''.join(attr)
        return ''

    # TODO: use set when we require Python 2.3
    # TODO: The list is not complete, add missing from dtd
#RS Word: use _blocks for all tags that can only be interpreted on close, i.e. text between open and close must be recorded    
##    _blocks = 'p div pre table tr td ol ul dl li dt dd h1 h2 h3 h4 h5 h6 hr form'
    _blocks = 'div pre dt dd h1 h2 h3 h4 h5 h6 form url pagelink'
#RS end
    _blocks = dict(zip(_blocks.split(), [1] * len(_blocks)))

    def open(self, tag, newline=False, attr=None):
        """ Open a tag with optional attributes
        
        @param tag: html tag, string
        @param newline: render tag on a separate line
        @param attr: dict with tag attributes
        @rtype: string ?
        @return: open tag with attributes
        """
#        if _debug:
#            traceback.print_stack(limit=1,file=sys.stdout)
        if tag in self._blocks:
            # Block elements
#RS word
            if _debug:
                print "OPEN %s (recording)" % tag
#                if self.document!=None:
#                   self.word_host.Selection.TypeText("OPEN %s (recording)" % tag)
            self.store_text=1
            self.recordedtext=""
            if self.word_host:
                self.recordedcursor=int(self.word_host.Selection.Range.End)
#RS end
            result = []
            
            # Add language attributes, but let caller overide the default
            attributes = self.langAttr()
            if attr:
                attributes.update(attr)
            
            # Format
            attributes = self.formatAttributes(attributes)
            result.append('<%s%s>' % (tag, attributes))
            if newline:
                if _debug:
                    print "OPEN with NEWLINE"
                if self.document:
                    self.word_host.Selection.TypeParagraph()
                
                result.append('\n')
            return ''.join(result)
        else:
            # Inline elements
            # Add to inlineStack
            if _debug:
                print "OPEN %s (inline)" % tag
#                if self.document!=None:
#                   self.word_host.Selection.TypeText("OPEN %s (inline)" % tag)
            self._inlineStack.append(tag)
            # Format
            return '<%s%s>' % (tag, self.formatAttributes(attr))
       
    def close(self, tag, newline=False):
        """ Close tag

        @param tag: html tag, string
        @rtype: string ?
        @return: closing tag
        """
#        if _debug:
#            traceback.print_stack(limit=1,file=sys.stdout)
        if tag in self._blocks:
            # Block elements
            # Close all tags in inline stack
            # Work on a copy, because close(inline) manipulate the stack
#RS word            
            if _debug:
                try:
                    print 'CLOSE %s (recorded="%s", at %s)' % (tag,self.recordedtext,self.recordedcursor)
                except:
                    print 'CLOSE %s (recorded=???, at %s)' % (tag,self.recordedcursor)
                    
#                if self.document!=None:
#                   self.word_host.Selection.TypeText("CLOSE %s (recorded)" % tag)
            self.store_text=0
            self.recordedtext=""
            self.recordedcursor=0
#RS end            
            result = []
            stack = self._inlineStack[:]
            stack.reverse()
            for inline in stack:
                result.append(self.close(inline))
            # Format with newline
            if newline:
                if _debug:
                    print "CLOSE with NEWLINE"
                result.append('\n')
            result.append('</%s>\n' % (tag))
            return ''.join(result)            
        else:
            # Inline elements 
            # Pull from stack, ignore order, that is not our problem.
            # The code that calls us should keep correct calling order.
            if _debug:
                print "CLOSE %s (inline)" % tag
#                if self.document!=None:
#                   self.word_host.Selection.TypeText("CLOSE %s (inline)" % tag)
            if tag in self._inlineStack:
                if _debug:
                    print "CLOSE %s (inline stack remove)" % tag
                self._inlineStack.remove(tag)
            return '</%s>' % tag

    def startDocument(self, pagename):
        if _debug:
            traceback.print_stack(limit=1,file=sys.stdout)
            sys.stderr.write("\nThis is the Word Formatter::startDocument....")
        self.doccount+=1
        if self.word_host==None:
            try:
                self.word_host = win32com.client.Dispatch("Word.Application") # open MS Word
                
            except:
                self.request.write( "#STARTDOC %s %s failed at Host Initialisation" % (self.doccount,pagename))
                self.word_host=None
                raise

            try:
                self.word_host.Visible=1
            #Visible is essential, otherwise strange things may happen (Kill Bill!!!)
            except:
                self.request.write("#STARTDOC %s %s failed at Host Visible" % (self.doccount,pagename))
            try:
                self.request.write("#STARTDOC uses template dir %s" % str(self.word_host.Options.DefaultFilePath(win32com.client.constants.wdUserTemplatesPath)))
            except:
                raise
        else:
            self.request.write("\nMSWORD HOST already active!\n")
        if self.document!=None:
            self.request.write("ignore#STARTDOC %s %s" % (self.doccount,pagename))
            return u"ignore#STARTDOC %s %s" % (self.doccount,pagename)
        try:
            
##            self.document=self.word_host.Documents.Add(Template=self.doctemplate,Visible=vbFalse)
            self.document=self.word_host.Documents.Add(Template=self.doctemplate,Visible=vbTrue)
            #we only want the styles from the template, not the content
        except:
            self.FatalEnd()
            self.request.write("#STARTDOC %s %s failed at Documents.Add(%s..." % (self.doccount,pagename,self.doctemplate))
            raise
        
        try:
            self.document.Content.Delete()
            self.wdCharacter=win32com.client.constants.wdCharacter
            self.wdExtend=win32com.client.constants.wdExtend
            self.ul_type=win32com.client.constants.wdListBullet
            self.ol_type=win32com.client.constants.wdListOutlineNumbering
            self.tt_style=win32com.client.constants.wdStyleHtmlTt
            self.pre_style=win32com.client.constants.wdStyleHtmlPre
            self.defchar_style=win32com.client.constants.wdStyleDefaultParagraphFont
            self.defpara_style=win32com.client.constants.wdStyleNormal
            self.wdWord9ListBehavior=win32com.client.constants.wdWord9ListBehavior
            self.wdNumberGallery=win32com.client.constants.wdNumberGallery
            self.wdListApplyToThisPointForward=win32com.client.constants.wdListApplyToThisPointForward
            
            self.word_host.Selection.Style=self.defpara_style
            self.normalstyle=self.word_host.Selection.Style
            self.request.write("NORMSTYLE: %s" % self.normalstyle)
            self._reset_indents()
            
            file = wikiutil.quoteWikinameFS(pagename) + DOC_SUFFIX
            filepath = os.path.abspath(os.path.join(self.targetdir, file))
            self.document.SaveAs(filepath,0)
#            self.request.write("#STARTDOC %s %s" % (self.doccount,pagename)
            return u"#STARTDOC %s %s" % (self.doccount,pagename)
        except:
            self.FatalEnd()
            self.request.write("#STARTDOC %s %s failed" % (self.doccount,pagename))
            raise

    def endDocument(self):
#RS fatal error handling
        if _debug:
            traceback.print_stack(limit=1,file=sys.stdout)
        if self.dead==1:
            return u""
#RS end
        self.doccount-=1
        if self.doccount==0:
            try:
                self.word_host.ActiveDocument.Fields.Update()
                self.document.Close(-1)
                self.word_host.Quit()
                self.document=None
                self.word_host=None
                return u"#ENDDOC"
            except:
                return u"#ENDDOC failed"
                
        return u"#ENDDOC %s" % self.doccount

    def startContent(self, content_id='content', **kwargs):
        """ Start page content div """
        return ''
        if _debug:
            traceback.print_stack(limit=1,file=sys.stdout)
        # Setup id
        if content_id!='content':
            aid = 'top_%s' % (content_id,)
        else:
            aid = 'top'
        self._content_ids.append(content_id)
        result = []
        # Use the content language
        attr = self.langAttr(self.request.content_lang)
        attr['id'] = content_id
        result.append(self.open('div', newline=1, attr=attr))
        result.append(self.anchordef(aid))
        return ''.join(result)
        
    def endContent(self):
        """ Close page content div """
        return ''
        if _debug:
            traceback.print_stack(limit=1,file=sys.stdout)

        # Setup id
        try:
            cid = self._content_ids.pop()
        except:
            cid = 'content'
        if cid!='content':
            aid = 'bottom_%s' % (cid,)
        else:
            aid = 'bottom'

        result = []
        result.append(self.anchordef(aid))
        result.append(self.close('div', newline=1))
        return ''.join(result)
    
    def lang(self, on, lang_name):
        """ Insert text with specific lang and direction.
        
            Enclose within span tag if lang_name is different from
            the current lang    
        """
        tag = 'span'
        if lang_name != self.request.current_lang:
            # Enclose text in span using lang attributes
            if on:
                attr = self.langAttr(lang=lang_name)
                ret=self.open(tag, attr=attr)
                return ret
            else:
                if self.document!=None:
                    pass
#TODO RS word: text with language info?
###                self.document.XXXX
                ret=self.close(tag)
                return ret

        # Direction did not change, no need for span
        return ''            


    def sysmsg(self, on, **kw):
        if _debug:
            traceback.print_stack(limit=1,file=sys.stdout)
#RS fatal error handling
        if self.dead==1:
            return u""
#RS end
        tag = 'div'
        if on:
            ret=self.open(tag, attr={'class': 'message'})
            return ret
        else:
            text=self.recordedtext
            if self.document!=None and text!=None:
                self.document.Content.TypeText('#SYSMSG#'+text+'#')
            ret=self.close(tag)
            return ret
            

    def pagelink(self, on, pagename='', page=None, **kw):
        """ Link to a page.

            formatter.text_python will use an optimized call with a page!=None
            parameter. DO NOT USE THIS YOURSELF OR IT WILL BREAK.

            See wikiutil.link_tag() for possible keyword parameters.
        """
        if _debug:
            traceback.print_stack(limit=1,file=sys.stdout)
#RS fatal error handling
        if self.dead==1:
            return u""
#RS end
        apply(FormatterBase.pagelink, (self, on, pagename, page), kw)
        if page is None:
            page = Page(self.request, pagename, formatter=self);
        tag = 'pagelink'
        url = wikiutil.quoteWikinameFS(pagename) + DOC_SUFFIX
        if on:
            ret=self.open(tag, attr={'class': 'pagelink'})
            return ret
        else:
            text=self.recordedtext
            if text==None:
                text=pagename
            if self.document!=None:
#                if text!=None:
#                    self.word_host.Selection.TypeText('#PLINK#'+str(text)+'#')
#                else:
#                    self.word_host.Selection.TypeText('#PLINK#'+str(pagename)+'#')
                self.word_host.ActiveDocument.Hyperlinks.Add(\
                    Anchor=self.word_host.Selection.Range, Address=url,\
                    SubAddress="", ScreenTip="", TextToDisplay=text)
            ret=self.close(tag)
            return ret

            
            

    def interwikilink(self, on, interwiki='', pagename='', **kw):
        if not on: return '</a>'
        
        wikitag, wikiurl, wikitail, wikitag_bad = wikiutil.resolve_wiki(self.request, '%s:%s' % (interwiki, pagename))
        wikiurl = wikiutil.mapURL(self.request, wikiurl)

        if wikitag == 'Self': # for own wiki, do simple links
            import urllib
            if wikitail.find('#')>-1:
                wikitail, kw['anchor'] = wikitail.split('#', 1)
            wikitail = urllib.unquote(wikitail)
            return apply(self.pagelink, (on, wikiutil.AbsPageName(self.request, self.page.page_name, wikitail)), kw)
        else: # return InterWiki hyperlink
            href = wikiutil.join_wiki(wikiurl, wikitail)
            if wikitag_bad:
                html_class = 'badinterwiki'
            else:
                html_class = 'interwiki'

            icon = ''
            if self.request.user.show_fancy_links:
                icon = self.request.theme.make_icon('interwiki', {'wikitag': wikitag}) 
            return (self.url(1, href, title=wikitag, unescaped=0,
                pretty_url=kw.get('pretty_url', 0), css = html_class) +
                icon)
            # unescaped=1 was changed to 0 to make interwiki links with pages with umlauts (or other non-ascii) work


#SYNC URL

    def url(self, on, url=None, css=None, **kw):
        """ render URL

        @keyword type: "www" or "mailto" to use that icon
        @keyword title: <a> title attribute
        @keyword attrs: just include those <a> attrs "as is"
        """
        if _debug:
            traceback.print_stack(limit=1,file=sys.stdout)
#RS fatal error handling
        if self.dead==1:
            return u""
#RS end
        if url is not None:
            url = wikiutil.mapURL(self.request, url)
        title = kw.get('title', None)
        attrs = kw.get('attrs', None)
#RS 1.1
        target = kw.get('target', None)
#RS stop
        str = ''
        if css: 
            str = '%s class="%s"' % (str, css)
        if title:
            str = '%s title="%s"' % (str, title)
        else:
            title=""
        if attrs:
            str = '%s %s' % (str, attrs)

        # create link
#TODO? insert link icons and other pretty stuff?         
        tag = 'url'
        if on:
            #store this for the close action
            self.url_url=url
            self.url_title=title
            
            ret=self.open(tag, attr=attrs)
            return ret
        else:
            text=self.recordedtext
            url=self.url_url
            title=self.url_title
            if text is None:
                text = url
            if self.document!=None:
                self.word_host.ActiveDocument.Hyperlinks.Add(\
                    Anchor=self.word_host.Selection.Range, Address=wikiutil.escape(url, 1),\
                    SubAddress="", ScreenTip=title, TextToDisplay=text)
            ret=self.close(tag)
            return ret


    def _wordbookmark(self,name):
        """
        transform name into a valid Word bookmark name
        """
        return name.replace("-","_")

    def anchordef(self, id):
        if _debug:
            traceback.print_stack(limit=1,file=sys.stdout)
#RS fatal error handling
        if self.dead==1:
            return u""
#RS end
        if self.document!=None:
            self.document.Bookmarks.Add(Range=self.word_host.Selection.Range,Name=self._wordbookmark(id))
        return '<a id="%s"></a>\n' % (id, )

    def anchorlink(self, on, name='', id = None):
        if _debug:
            traceback.print_stack(limit=1,file=sys.stdout)
##        if self.document!=None:
##            self.word_host.Selection.TypeText('_'+text+'_')
#RS fatal error handling
        if self.dead==1:
            return u""
#RS end
        extra = ''
        if id:
            extra = ' id="%s"' % id
        else:
            id=''
        tag = 'a'
        if on:
            ret=self.open(tag, attr={'id':'%s' % id})
            #store this for the close action
            self.anchorlink_name=name
            self.anchorlink_id=id
            
            return ret
        else:
            text=self.recordedtext
            name=self.anchorlink_name
            id=self.anchorlink_id
            if text==None:
                text=name
            if self.document!=None:
                if _debug:
                    out="""
                self.word_host.ActiveDocument.Hyperlinks.Add(\
                    Anchor=%s, Address="",\
                    SubAddress='%s', ScreenTip="", TextToDisplay='%s')
                    """ % (str(self.word_host.Selection.Range.Start),name,text)
                    sys.stdout.write(out)
                    sys.stdout.flush()
#                self.word_host.Selection.TypeText('##')    
#                self.word_host.Selection.MoveLeft(Unit=self.wdCharacter,Count=2,Extend=self.wdExtend)
                self.word_host.ActiveDocument.Hyperlinks.Add(\
                    Anchor=self.word_host.Selection.Range, Address="",\
                    SubAddress=self._wordbookmark(name), ScreenTip="", TextToDisplay=text)
            ret=self.close(tag)
            return ret
#RS

##    def escape(self,s, quote=None):
##        """
##        """
##        if _debug:
##            traceback.print_stack(limit=1,file=sys.stdout)
###        s = s.replace("&", "&amp;") # Must be done first!
###        s = s.replace("<", "&lt;")
###        s = s.replace(">", "&gt;")#
##        if quote:
##            s = s.replace('"', '""')
##        return s


    def pure(self, text):
        """
        this handles the "not in any markup" case
        used in formatters with "side effects"
        """
        if _debug:
            traceback.print_stack(limit=1,file=sys.stdout)
#RS fatal error handling
        if self.dead==1:
            return u""
#RS end
        if (self._table_start == 1):
            return u''
#        if self.document!=None:
#            self.word_host.Selection.InsertAfter(text)
#            self.word_host.Selection.TypeText(text)
#            self.document.Content.InsertAfter(text)
#            self.document.Content.InsertAfter('#'+text+'#')
        return self._text(text)

    def _text(self, text):
#        return '{'+text+'}'
#RS fatal error handling
        if _debug:
            traceback.print_stack(limit=2,file=sys.stdout)
        if self.dead==1:
            return u""
#RS end
        tx=self.escapedText(text)
        if self._in_code:
            tx=string.replace(self.escapedText(text), u' ', self.hardspace)
        if self.store_text:
            self.recordedtext+=tx
            return tx
        else:
            if self.document!=None:
               self.word_host.Selection.TypeText(tx)
            
        return tx

    # Inline ###########################################################
    def strong(self, on):
#RS fatal error handling
        if self.dead==1:
            return u""
#RS end
        tag = 'strong'
        if on:
            ret=self.open(tag)
            if self.document!=None:
                self.word_host.Selection.Font.Bold=\
                    win32com.client.constants.wdToggle
                self.word_host.Selection.TypeText('')
            return ret
        else:
            if self.document!=None:
                pass
                self.word_host.Selection.Font.Bold=\
                    win32com.client.constants.wdToggle
                self.word_host.Selection.TypeText('')
            ret=self.close(tag)
            return ret


    def emphasis(self, on):
#RS fatal error handling
        if self.dead==1:
            return u""
#RS end
        tag = 'em'
        if on:
            ret=self.open(tag)
            if self.document!=None:
                self.word_host.Selection.Font.Italic=\
                    win32com.client.constants.wdToggle
                self.word_host.Selection.TypeText('')
            return ret
        else:
            if self.document!=None:
                self.word_host.Selection.Font.Italic=\
                    win32com.client.constants.wdToggle
                self.word_host.Selection.TypeText('')
            ret=self.close(tag)
            return ret

    def underline(self, on):
        if _debug:
            traceback.print_stack(limit=1,file=sys.stdout)
#RS fatal error handling
        if self.dead==1:
            return u""
#RS end
        tag = 'span'
        if on:
            ret=self.open(tag,attr={'class': 'u'})
            if self.document!=None:
                self.word_host.Selection.Font.Underline=\
                    win32com.client.constants.wdUnderlineSingle
                self.word_host.Selection.TypeText('')
            return ret
        else:
            if self.document!=None:
                self.word_host.Selection.Font.Underline=\
                    win32com.client.constants.wdUnderlineNone
                self.word_host.Selection.TypeText('')
            ret=self.close(tag)
            return ret

    def highlight(self, on):
#RS fatal error handling
        if self.dead==1:
            return u""
#RS end
        tag = 'strong'
        if on:
            ret=self.open(tag, attr={'class': 'highlight'})
            if self.document!=None:
                self.word_host.Selection.Font.Bold=\
                    win32com.client.constants.wdToggle
                self.word_host.Selection.TypeText('')
            return ret
        else:
            if self.document!=None:
                self.word_host.Selection.Font.Bold=\
                    win32com.client.constants.wdToggle
                self.word_host.Selection.TypeText('')
            ret=self.close(tag)
            return ret

    def sup(self, on):
#RS fatal error handling
        if self.dead==1:
            return u""
#RS end
        tag = 'sup'
        if on:
            ret=self.open(tag)
            if self.document!=None:
                self.word_host.Selection.Font.Superscript=\
                    win32com.client.constants.wdToggle
                self.word_host.Selection.TypeText('')
            return ret
        else:
            if self.document!=None:
                self.word_host.Selection.Font.Superscript=\
                    win32com.client.constants.wdToggle
                self.word_host.Selection.TypeText('')
            ret=self.close(tag)
            return ret

    def sub(self, on):
#RS fatal error handling
        if self.dead==1:
            return u""
#RS end
        tag = 'sub'
        if on:
            ret=self.open(tag)
            if self.document!=None:
                self.word_host.Selection.Font.Subscript=\
                    win32com.client.constants.wdToggle
                self.word_host.Selection.TypeText('')
            return ret
        else:
            if self.document!=None:
                self.word_host.Selection.Font.Subscript=\
                    win32com.client.constants.wdToggle
                self.word_host.Selection.TypeText('')
            ret=self.close(tag)
            return ret
#RS end


    def code(self, on):
        if _debug:
            traceback.print_stack(limit=1,file=sys.stdout)
#RS fatal error handling
        if self.dead==1:
            return u""
#RS end
        tag = 'tt'
        self._in_code = on
        if on:
            ret=self.open(tag)
            if self.document!=None:
                self.word_host.Selection.Style=self.tt_style
                self.word_host.Selection.TypeText('')
            return ret
        else:
            if self.document!=None:
                self.word_host.Selection.Style=self.defchar_style
                self.word_host.Selection.TypeText('')
##                lastend=self.recordedcursor
##                currend=int(self.word_host.Selection.Range.End)
##                if lastend<currend and lastend>0:
##                    ttrange=self.document.Range(lastend,currend)
##                    ttrange.Style=self.tt_style
##                else:
##                    self.request.write("TT formatter error, ignored")
##                self.word_host.Selection.TypeText('')
            ret=self.close(tag)
            return ret

       
    def small(self, on):
        tag = 'small'
        if on:
            ret=self.open(tag)
            if self.document!=None:
                pass
#TODO
#                self.word_host.Selection.Font.Subscript=\
#                    win32com.client.constants.wdToggle
                self.word_host.Selection.TypeText('')
            return ret
        else:
            if self.document!=None:
                pass
#TODO
#                self.word_host.Selection.Font.Subscript=\
#                    win32com.client.constants.wdToggle
                self.word_host.Selection.TypeText('')
            ret=self.close(tag)
            return ret
                                                                                
    def big(self, on):
        tag = 'big'
        if on:
            ret=self.open(tag)
            if self.document!=None:
                pass
#TODO
#                self.word_host.Selection.Font.Subscript=\
#                    win32com.client.constants.wdToggle
#                self.word_host.Selection.TypeText('')
            return ret
        else:
            if self.document!=None:
                pass
#TODO
#                self.word_host.Selection.Font.Subscript=\
#                    win32com.client.constants.wdToggle
#                self.word_host.Selection.TypeText('')
            ret=self.close(tag)
            return ret

    # Block elements ####################################################

#framing pre:
#Selection.ParagraphFormat.Borders(wdBorderLeft).LineStyle = wdLineStyleSingle    
##    Selection.MoveUp Unit:=wdLine, Count:=3, Extend:=wdExtend
##    With Selection.ParagraphFormat
##        With .Borders(wdBorderLeft)
##            .LineStyle = wdLineStyleSingle
##            .LineWidth = wdLineWidth050pt
##            .Color = wdColorAutomatic
##        End With
##        With .Borders(wdBorderRight)
##            .LineStyle = wdLineStyleSingle
##            .LineWidth = wdLineWidth050pt
##            .Color = wdColorAutomatic
##        End With
##        With .Borders(wdBorderTop)
##            .LineStyle = wdLineStyleSingle
##            .LineWidth = wdLineWidth050pt
##            .Color = wdColorAutomatic
##        End With
##        With .Borders(wdBorderBottom)
##            .LineStyle = wdLineStyleSingle
##            .LineWidth = wdLineWidth050pt
##            .Color = wdColorAutomatic
##        End With
##        .Borders(wdBorderHorizontal).LineStyle = wdLineStyleNone
##        With .Borders
##            .DistanceFromTop = 1
##            .DistanceFromLeft = 4
##            .DistanceFromBottom = 1
##            .DistanceFromRight = 4
##            .Shadow = False
##        End With
##    End With
##    With Options
##        .DefaultBorderLineStyle = wdLineStyleSingle
##        .DefaultBorderLineWidth = wdLineWidth050pt
##        .DefaultBorderColor = wdColorAutomatic
##    End With
    

    def preformatted(self, on):
        if _debug:
            traceback.print_stack(limit=1,file=sys.stdout)
#RS fatal error handling
        if self.dead==1:
            return u""
#RS end
        self.in_pre = on != 0
        tag = 'preformatted'
        if on:
            ret=self.open(tag,newline=1)
            if self.document!=None:
###                lastend=self.recordedcursor
###                currend=int(self.word_host.Selection.Range.End)
###                if lastend<currend and lastend>0:
###                    ttrange=self.document.Range(lastend,currend)
##                    ttrange.Style=self.pre_style
##                else:
##                    self.request.write("PRE formatter error, ignored")
                self.word_host.Selection.TypeParagraph()
                self.word_host.Selection.Style=self.pre_style
                self.word_host.Selection.ParagraphFormat.Borders(win32com.client.constants.wdBorderTop).LineStyle = win32com.client.constants.wdLineStyleSingle    
                self.word_host.Selection.ParagraphFormat.Borders(win32com.client.constants.wdBorderBottom).LineStyle = win32com.client.constants.wdLineStyleSingle    
                self.word_host.Selection.ParagraphFormat.Borders(win32com.client.constants.wdBorderLeft).LineStyle = win32com.client.constants.wdLineStyleSingle    
                self.word_host.Selection.ParagraphFormat.Borders(win32com.client.constants.wdBorderRight).LineStyle = win32com.client.constants.wdLineStyleSingle    

                self.word_host.Selection.TypeParagraph()
            return ret
        else:
            if self.document!=None:
                self.word_host.Selection.TypeParagraph()
                self.word_host.Selection.Style=self.defpara_style
                self.word_host.Selection.TypeParagraph()
                self.word_host.Selection.ParagraphFormat.Borders(win32com.client.constants.wdBorderTop).LineStyle = win32com.client.constants.wdLineStyleNone    
                self.word_host.Selection.ParagraphFormat.Borders(win32com.client.constants.wdBorderBottom).LineStyle = win32com.client.constants.wdLineStyleNone    
                self.word_host.Selection.ParagraphFormat.Borders(win32com.client.constants.wdBorderLeft).LineStyle = win32com.client.constants.wdLineStyleNone    
                self.word_host.Selection.ParagraphFormat.Borders(win32com.client.constants.wdBorderRight).LineStyle = win32com.client.constants.wdLineStyleNone    
##                lastend=self.recordedcursor
##                currend=int(self.word_host.Selection.Range.End)
##                if lastend<currend and lastend>0:
##                    ttrange=self.document.Range(lastend,currend)
##                    ttrange.Style=self.pre_style
##                else:
##                    self.request.write("PRE formatter error, ignored")
##                self.word_host.Selection.TypeParagraph()
##                self.word_host.Selection.Style=self.defpara_style
            ret=self.close(tag)
            return ret

# special markup for syntax highlighting #############################

    def code_area(self, on, code_id, code_type='code', show=0, start=-1, step=-1):
#RS word: for now, just use preformatted?
        if on:
            # Open a code area
            self._in_code_area = 1
            self._in_code_line = 0
        else:
            # Close code area
            self._in_code_area = 0
            self._code_area_num += 1
        return self.preformatted(on)
#RS end    
        res = []
        ci = self.request.makeUniqueID('CA-%s_%03d' % (code_id, self._code_area_num))
        if on:
            # Open a code area
            self._in_code_area = 1
            self._in_code_line = 0
            self._code_area_state = [ci, show, start, step, start]

            # Open the code div - using left to right always!
            attr = {'class': 'codearea', 'lang': 'en', 'dir': 'ltr'}
            res.append(self.open('div', attr=attr))

            # Add the script only in the first code area on the page
            if self._code_area_js == 0 and self._code_area_state[1] >= 0:
                res.append(self._toggleLineNumbersScript)
                self._code_area_js = 1

            # Add line number link, but only for JavaScript enabled browsers.
            if self._code_area_state[1] >= 0:
                toggleLineNumbersLink = r'''
<script type="text/javascript">
document.write('<a href="#" onClick="return togglenumber(\'%s\', %d, %d);" \
                class="codenumbers">Toggle line numbers<\/a>');
</script>
''' % (self._code_area_state[0], self._code_area_state[2], self._code_area_state[3])
                res.append(toggleLineNumbersLink)

            # Open pre - using left to right always!
            attr = {'id': self._code_area_state[0], 'lang': 'en', 'dir': 'ltr'}
            res.append(self.open('pre', newline=True, attr=attr))
        else:
            # Close code area
            res = []
            if self._in_code_line:
                res.append(self.code_line(0))
            res.append(self.close('pre'))
            res.append(self.close('div'))

            # Update state
            self._in_code_area = 0
            self._code_area_num += 1

        return ''.join(res)

    def code_line(self, on):
#RS word: for now, just linebreaks on on?
        self._in_code_line = on != 0
        if on:
            ret=self.linebreak(on)
        else:
            ret=''
        return ret
    
        return self.preformatted(on)
#RS end    
#RS end    
        res = ''
        if not on or (on and self._in_code_line):
            res += '</span>\n'
        if on:
            res += '<span class="line">'
            if self._code_area_state[1] > 0:
                res += '<span class="LineNumber">%4d </span>' % (self._code_area_state[4], )
                self._code_area_state[4] += self._code_area_state[3]
        self._in_code_line = on != 0
        return res

    def code_token(self, on, tok_type):
#RS word: for now, just use code?
        return self.code(on)
#RS end
        return ['<span class="%s">' % tok_type, '</span>'][not on]

    # Paragraphs, Lines, Rules ###########################################
    
    def linebreak(self, preformatted=1):
        if _debug:
            traceback.print_stack(limit=1,file=sys.stdout)
#RS fatal error handling
        if self.dead==1:
            return u""
#RS end
        if self._in_code_area:
            preformatted = 1
        if preformatted==1:
            
            self.word_host.Selection.TypeParagraph()
            return '#\n'
        else:    
            self.word_host.Selection.TypeText("#\x0B #")
            return '<br>\n'
#        self.document.Content.InsertAfter("\x0B ")
   

    def paragraph(self, on):
        if _debug:
            traceback.print_stack(limit=1,file=sys.stdout)
#RS fatal error handling
        if self.dead==1:
            return u""
#RS end
        if self._terse:
            return ''
        FormatterBase.paragraph(self, on)
        if self._in_li:
            self._in_li = self._in_li + 1
        tag = 'p'
        if on:
            ret=self.open(tag)
            if self.document!=None:
                if self._ignore_next_paragraph: #we already inserted a paragraph
                    self._ignore_next_paragraph=0
                    return u''
                else:
                    self.word_host.Selection.TypeParagraph()
                    return u'<pli>'
            return ret
        else:
            text=self.recordedtext
            if self.document!=None:
                if self._ignore_next_paragraph: #we already inserted a paragraph
                    self._ignore_next_paragraph=0
                    return u''
                else:
                    self.word_host.Selection.TypeParagraph()
                    return u'</pli>'
            ret=self.close(tag)
            return ret
        

    def rule(self, size=None):
        if _debug:
            traceback.print_stack(limit=1,file=sys.stdout)
#RS fatal error handling
        if self.dead==1:
            return u""
#RS end
#TODO RS draw a line?
        if size:
            # Add hr class: hr1 - hr6
            return self.open('hr', newline=1, attr={'class': 'hr%d' % size})
        return self.open('hr', newline=1)

    def icon(self, type):
#TODO RS or just ignore (probably just wiki control icons)?        
        return self.request.theme.make_icon(type)

    def img_url(self, img):
        """ Generate an image href

        @param img: the image filename
        @rtype: string
        @return: the image href
        """
        return "%s%s\\img\\%s" % (self.cfg.url_prefix_dir, self.request.theme.name, img)


    def smiley(self, text):
        w, h, b, img = config.smileys[text.strip()]
        href = img
        if not href.startswith('/'):
            href = self.img_url(img)
        return self.image(src=href, alt=text, width=str(w), height=str(h))

    # Lists ##############################################################


    def number_list(self, on, type=None, start=None):
        if _debug:
            traceback.print_stack(limit=1,file=sys.stdout)
#RS fatal error handling
        if self.dead==1:
            return u""
#RS end
        tag = 'ol'
        self.request.write("<number_list>:on=%s,type=%s,start=%s" % (str(on),str(type),str(start)))
        if on:
            attr = {}
            if type is not None:
                attr['type'] = type
            if start is not None:
                attr['start'] = start
            ret=self.open(tag, newline=1, attr=attr)

            self.list_levels['ol']=self.list_levels['ol']+1
            self.list_levels['all']=self.list_levels['all']+1
            if self.document!=None:
#                self.word_host.Selection.TypeParagraph()
                self.request.write("<OL> List type was: %s" % str(self.word_host.Selection.Range.ListFormat.ListType))
                if self.list_levels['ol']==1: #only first 
                    if self.word_host.Selection.Range.ListFormat.ListType != self.ol_type:
#                        self.word_host.Selection.TypeText("{bulleton}")
##                        self.word_host.Selection.Range.ListFormat.ApplyNumberDefault(self.wdWord9ListBehavior)
                        if self.last_indent_type=='ul':
                            #need more indent
                            self.request.write("UL->OL 1")
                            self.word_host.Selection.Range.ListFormat.ListIndent()
                        listtemplate=self.word_host.ListGalleries(self.wdNumberGallery).ListTemplates(self.list_levels['ol'])    
                        self.word_host.Selection.Range.ListFormat.ApplyListTemplate(ListTemplate=listtemplate,
                            ContinuePreviousList=vbFalse, ApplyTo=self.wdListApplyToThisPointForward, DefaultListBehavior=self.wdWord9ListBehavior)

                else:
                    if self.word_host.Selection.Range.ListFormat.ListType != self.ol_type:
#                        self.word_host.Selection.TypeText("{bulleton}")
##                        self.word_host.Selection.Range.ListFormat.ApplyNumberDefault(self.wdWord9ListBehavior)
                        listtemplate=self.word_host.ListGalleries(self.wdNumberGallery).ListTemplates(self.list_levels['ol'])    
                        self.word_host.Selection.Range.ListFormat.ApplyListTemplate(ListTemplate=listtemplate,
                            ContinuePreviousList=vbFalse, ApplyTo=self.wdListApplyToThisPointForward, DefaultListBehavior=self.wdWord9ListBehavior)
                        if self.last_indent_type=='ul':
                            #need more indent
                            self.request.write("UL->OL 2")
                            self.word_host.Selection.Range.ListFormat.ListIndent()
#                    else:
                    self.word_host.Selection.Range.ListFormat.ListIndent()
                
            self._ignore_next_paragraph=1
            self._first_li = 1
            self.last_indent_type='ol'
        else:
            self.list_levels['ol']=self.list_levels['ol']-1
            self.list_levels['all']=self.list_levels['all']-1

            if self.document!=None:
#                self.word_host.Selection.TypeParagraph()
                self.request.write("</OL> List type was: %s" % str(self.word_host.Selection.Range.ListFormat.ListType))
                if self.list_levels['ul']==0: 
                    if self.word_host.Selection.Range.ListFormat.ListType == self.ol_type:
#                        self.word_host.Selection.TypeText("{bulletoff}")
                        self.word_host.Selection.Range.ListFormat.ApplyNumberDefault(self.wdWord9ListBehavior)
                        if self.last_indent_type=='ul':
                            #need more outdent
                            self.request.write("UL->OL ??1??")
                            self.word_host.Selection.Range.ListFormat.ListOutdent()

                else:
                    if self.word_host.Selection.Range.ListFormat.ListType == self.ol_type:
                        self.word_host.Selection.Range.ListFormat.ApplyNumberDefault(self.wdWord9ListBehavior)
#                    else:
                    self.word_host.Selection.Range.ListFormat.ListOutdent()
            self._ignore_next_paragraph=1
            self.last_indent_type=''

            ret=self.close(tag)
            return ret
            

    def bullet_list(self, on):
        if _debug:
            traceback.print_stack(limit=1,file=sys.stdout)
#RS fatal error handling
        if self.dead==1:
            return u""
#RS end
        tag = 'ul'
        self.request.write("<bullet_list>:on=%s" % (str(on)))
        if on:
            ret=self.open(tag, newline=1)
            self.list_levels['ul']=self.list_levels['ul']+1
            self.list_levels['all']=self.list_levels['all']+1
            if self.document!=None:
#                self.word_host.Selection.TypeParagraph()
                self.request.write("<UL> List type was: %s" % str(self.word_host.Selection.Range.ListFormat.ListType))
#                self.word_host.Selection.TypeText("[%s]" % self.list_levels['all'])
                if self.list_levels['ul']==1: #only first 
                    if self.word_host.Selection.Range.ListFormat.ListType != self.ul_type:
#                        self.word_host.Selection.TypeText("{bulleton}")
                        self.word_host.Selection.Range.ListFormat.ApplyBulletDefault(self.wdWord9ListBehavior)
                else:
                    if self.word_host.Selection.Range.ListFormat.ListType != self.ul_type:
#                        self.word_host.Selection.TypeText("{bulleton}")
                        self.word_host.Selection.Range.ListFormat.ApplyBulletDefault(self.wdWord9ListBehavior)
#                    else:
                    self.word_host.Selection.Range.ListFormat.ListIndent()
#                    self.word_host.Selection.TypeText("{indent}")
            self._ignore_next_paragraph=1
            self.last_indent_type='ul'
            
            return ret
        else:
            self.list_levels['ul']=self.list_levels['ul']-1
            self.list_levels['all']=self.list_levels['all']-1
            if self.document!=None:
#                self.word_host.Selection.TypeParagraph()
                self.request.write("</UL> List type was: %s" % str(self.word_host.Selection.Range.ListFormat.ListType))
                if self.list_levels['ul']==0: 
                    if self.word_host.Selection.Range.ListFormat.ListType == self.ul_type:
#                        self.word_host.Selection.TypeText("{bulletoff}")
                        self.word_host.Selection.Range.ListFormat.ApplyBulletDefault(self.wdWord9ListBehavior)
                else:
                    if self.word_host.Selection.Range.ListFormat.ListType == self.ul_type:
                        self.word_host.Selection.Range.ListFormat.ApplyBulletDefault(self.wdWord9ListBehavior)
#                    else:
                    self.word_host.Selection.Range.ListFormat.ListOutdent()
#                    self.word_host.Selection.TypeText("{outdent}")
#                self.word_host.Selection.TypeText("[/%s]" % (self.list_levels['all']+1))
            self._ignore_next_paragraph=1
            self.last_indent_type=''

            ret=self.close(tag)
            return ret

    def listitem(self, on, **kw):
        if _debug:
            traceback.print_stack(limit=1,file=sys.stdout)
#RS fatal error handling
        if self.dead==1:
            return u""
#RS end
##        self._in_li = on != 0
        tag = 'li'
        self._in_li = on != 0
        if on:
            attr = {}
            css_class = kw.get('css_class', None)
            if css_class:
                attr['class'] = css_class
            style = kw.get('style', None)
            if style:
                attr['style'] = style
                if style=="list-style-type:none":
                    pass
                    #this is indent, not bullet
            ret=self.open(tag, attr=attr)
            self._ignore_next_paragraph=1
            return ret
        else:
            ret=self.close(tag)
            return ret
#RS end

    def definition_list(self, on):
        if _debug:
            traceback.print_stack(limit=1,file=sys.stdout)
#RS fatal error handling
        if self.dead==1:
            return u""
#RS end
        tag = 'dl'
        if on:
            ret=self.open(tag, newline=1)
            self.list_levels['dl']=self.list_levels['dl']+1
            self.list_levels['all']=self.list_levels['all']+1
            return ret
        else:
            self.list_levels['dl']=self.list_levels['dl']-1
            self.list_levels['all']=self.list_levels['all']-1
            ret=self.close(tag)
            return ret

    def definition_term(self, on):
        if _debug:
            traceback.print_stack(limit=1,file=sys.stdout)
#RS fatal error handling
        if self.dead==1:
            return u""
#RS end
        tag = 'dt'
        if on:
            ret=self.open(tag)
            return ret
        else:
            ret=self.close(tag)
            return ret
        

    def definition_desc(self, on):
        if _debug:
            traceback.print_stack(limit=1,file=sys.stdout)
#RS fatal error handling
        if self.dead==1:
            return u""
#RS end
        tag = 'dd'
        if on:
            ret=self.open(tag)
            return ret
        else:
            ret=self.close(tag)
            return ret


    def heading(self, on, depth, id = None, **kw):
        # remember depth of first heading, and adapt current depth accordingly
        if _debug:
            traceback.print_stack(limit=1,file=sys.stdout)
#RS fatal error handling
        if self.dead==1:
            return u""
#RS end

        self._reset_indents()
        if not self._base_depth:
            self._base_depth = depth
#RS adapt base depth if included
            self._base_depth=long(self.request.getPragma('_base_depth',str(self._base_depth)))
        oridepth=depth

#RS isn't this nonsense???
#        depth = max(depth - (self._base_depth - 1), 1)
        count_depth = max(depth - (self._base_depth - 1), 1)

#?        depth = max(depth + (self._base_depth - 1), self._base_depth)
#RS 1.1
        # check numbering, possibly changing the default
        if self._show_section_numbers is None:
            self._show_section_numbers = self.cfg.show_section_numbers
            numbering = self.request.getPragma('section-numbers', '').lower()
            if numbering in ['0', 'off']:
                self._show_section_numbers = 0
            elif numbering in ['1', 'on']:
                self._show_section_numbers = 1
            elif numbering in ['2', '3', '4', '5', '6']:
                # explicit base level for section number display
                self._show_section_numbers = int(numbering)
#RS stop

        heading_depth = depth + 1
        if on:
            # create section number
            number = ''
            if self._show_section_numbers:
                # count headings on all levels
                self.request._fmt_hd_counters = self.request._fmt_hd_counters[:count_depth]
                while len(self.request._fmt_hd_counters) < count_depth:
                    self.request._fmt_hd_counters.append(0)
                self.request._fmt_hd_counters[-1] = self.request._fmt_hd_counters[-1] + 1
                number = '.'.join(map(str, self.request._fmt_hd_counters[self._show_section_numbers-1:]))
                if number: number += ". "
            attr = {}
            if id:
                attr['id'] = id
            # Add space before heading, easier to check source code
            ret='\n' +self.open('h%d' % heading_depth, attr=attr)
            return "%s%s" % (ret,number)
            
        else:
            # closing tag, with empty line after, to make source more readable
            title=self.recordedtext
            if self.document!=None:
                self.word_host.Selection.TypeParagraph()
                style=win32com.client.constants.wdStyleHeading1 - depth +1
                self.word_host.Selection.Paragraphs.Last.Style=style
                self.word_host.Selection.TypeText('%s' % (title))
                self.word_host.Selection.TypeParagraph()
                self.word_host.Selection.Paragraphs.Last.Style=win32com.client.constants.wdStyleNormal
            ret=self.close('h%d' % heading_depth) + '\n'
            return ret



    # Tables #############################################################

    _allowed_table_attrs = {
        'table': ['class', 'id', 'style'],
        'row': ['class', 'id', 'style'],
        '': ['colspan', 'rowspan', 'class', 'id', 'style'],
    }

    def _checkTableAttr(self, attrs, prefix):
        if _debug:
            traceback.print_stack(limit=1,file=sys.stdout)
        if not attrs: return u''

        result = ''
        for key, val in attrs.items():
            if prefix and key[:len(prefix)] != prefix: continue
            key = key[len(prefix):]
            if key not in self._allowed_table_attrs[prefix]: continue
            result = '%s %s=%s' % (result, key, val)

        return result

    def table(self, on, attrs=None):
        """ Create table

        @param on: start table
        @param attrs: table attributes
        @rtype: string
        @return start or end tag of a table
        """
        if _debug:
            traceback.print_stack(limit=1,file=sys.stdout)
#RS fatal error handling
        if self.dead==1:
            return u""
#RS end
        result = []
        if on:
            # Open div to get correct alignment with table width smaller
            # than 100%
#            ret=self.open('div', newline=1)
#            result.append(ret)

            # Open table
            if not attrs:
                attrs = {}
            else:
                attrs = self._checkTableAttr(attrs, 'table')
            ret= self.open('table', newline=1, attr=attrs)

            self.list_levels['table']=self.list_levels['table']+1
            self.list_levels['all']=self.list_levels['all']+1
            if self.document!=None:
                ##self.word_host.Selection.TypeParagraph()
                if self.word_host.Selection.Range.ListFormat.ListType == win32com.client.constants.wdListBullet:
                    self.word_host.Selection.Range.ListFormat.ApplyBulletDefault(win32com.client.constants.wdWord9ListBehavior)
                self.word_host.Selection.TypeParagraph()
                self.document.Tables.Add(Range=self.word_host.Selection.Range,
                    NumRows=1, NumColumns= 1, DefaultTableBehavior=win32com.client.constants.wdWord9TableBehavior,
                    AutoFitBehavior= win32com.client.constants.wdAutoFitContent)
            self._first_tr = 1
            self._first_td = 1
            self._table_start=1
            return ret
        else:
            self.list_levels['table']=self.list_levels['table']-1
            self.list_levels['all']=self.list_levels['all']-1
            if self.document!=None:
                self.word_host.Selection.MoveDown(Unit=win32com.client.constants.wdLine, Count=1)
                self.word_host.Selection.TypeParagraph()

            ret=self.close('table')
#            ret=self.close('div')
            
            return ret

    def table_row(self, on, attrs=None):
        if _debug:
            traceback.print_stack(limit=1,file=sys.stdout)
#RS fatal error handling
        if self.dead==1:
            return u""
#RS end
        tag = 'tr'
        if on:
            if not attrs:
                attrs = {}
            else:
                attrs = self._checkTableAttr(attrs, 'row')
            ret=self.open(tag, newline=1, attr=attrs)
            if self._first_tr == 0:
                #first row always existing
                if self.document!=None:
                    self.word_host.Selection.InsertRowsBelow(1)
                self._first_td = 1
            elif self._first_td == 1:
#                if self.document!=None:
#                    self.word_host.Selection.TypeText('#')
                self._table_start = 0
            return ret
        else:
            self._first_tr = 0
            ret=self.close(tag)
            return ret
            

    def table_cell(self, on, attrs=None):
        if _debug:
            traceback.print_stack(limit=1,file=sys.stdout)
#RS fatal error handling
        if self.dead==1:
            return u""
#RS end
        tag = 'tr'
        if on:
            if not attrs:
                attrs = {}
            else:
                attrs = self._checkTableAttr(attrs, 'row')
            ret=self.open(tag, newline=1, attr=attrs)
            if self.document!=None:
                self.word_host.Selection.Style=self.defchar_style
            if self._first_tr == 1:
                if self._first_td == 0:
                    #first cell always existing
                    if self.document!=None:
                        self.word_host.Selection.InsertColumnsRight()
                        self.word_host.Selection.Style=self.defchar_style
                        
            else:
                #jump into cell
                if self.document!=None:
                    self.word_host.Selection.MoveRight(Unit=win32com.client.constants.wdCell)
                    self.word_host.Selection.Style=self.defchar_style
                self._first_td = 0
            return ret
        else:
            self._first_td = 0
            ret=self.close(tag)
            return ret

    def macro(self, macro_obj, name, args):
        # call the macro
        if name in ['TableOfContents',]:
            #skip call, emulate behavior
##    With ActiveDocument
##        .TablesOfContents.Add Range:=Selection.Range, RightAlignPageNumbers:= _
##            True, UseHeadingStyles:=True, UpperHeadingLevel:=1, _
##            LowerHeadingLevel:=3, IncludePageNumbers:=True, AddedStyles:="", _
##            UseHyperlinks:=True, HidePageNumbersInWeb:=True
##        .TablesOfContents(1).TabLeader = wdTabLeaderSpaces
##        .TablesOfContents.Format = wdIndexIndent
            try:
                self.mindepth = max(int(self.request.getPragma('section-numbers', 1)),1)
            except (ValueError, TypeError):
                self.mindepth = 1

            try:
                self.maxdepth = max(int(args), 1)
            except (ValueError, TypeError):
                self.maxdepth = 9
            sys.stdout.write("TOCrange:%s-%s" % (self.mindepth,self.maxdepth))
            if self.document!=None:
                self.word_host.ActiveDocument.TablesOfContents.Add(\
                    Range=self.word_host.Selection.Range, UpperHeadingLevel=self.mindepth,\
                    LowerHeadingLevel=self.maxdepth,UseHyperlinks=vbTrue)
            return "<TOC/>"
        
        return macro_obj.execute(name, args)    

    def processor(self, processor_name, lines, is_parser = 0):
        """ processor_name MUST be valid!
            writes out the result instead of returning it!
        """
        if not is_parser:
            processor = wikiutil.importPlugin(self.request.cfg, "processor",
                                              processor_name, "process")
            processor(self.request, self, lines)
        else:
            if processor_name in ['tpython',]:
                processor_name='wiki'
            parser = wikiutil.importPlugin(self.request.cfg, "parser",
                                           processor_name, "Parser")
            args = self._get_bang_args(lines[0])
            if args is not None:
                lines=lines[1:]
            p = parser('\n'.join(lines), self.request, format_args = args)
            p.format(self)
            del p
        return ''



    def escapedText(self, text):
        return text
        return wikiutil.escape(text)


    def _img(self,imgurl,**kw):

        if _debug:
            traceback.print_stack(limit=1,file=sys.stdout)
#RS fatal error handling
        if self.dead==1:
            return u""
#RS end
        trusted=1
        scheme = string.split(imgurl, ":", 1)[0]
        if scheme in tuple(string.split('http|https|ftp|nntp','|')):
            trusted=0
            #retrieve remote file to temp
            try:
                (filename, headers)=urllib.urlretrieve( imgurl)
                print "remote url %s retrieved to %s" % (imgurl,filename)
                filepath=filename
            except:
                filepath=imgurl
            self.request.write("adding http picture, filepath=%s" % (filepath))
        elif scheme in tuple(string.split('file|self|wiki','|')):
            trusted=0
            filepath=imgurl
            self.request.write("adding file|self|wiki picture, filepath=%s" % (filepath))
        else:
            trusted=1
            if imgurl.startswith("./"):
                imgfile=imgurl[2:]        
            else:
                imgfile=imgurl
                
                
            filepath = os.path.abspath(os.path.join(self.cfg.url_prefix_dir, imgfile))
            self.request.write("\n adding .. picture, imgfile=%s, targetdir=%s, filepath=%s" % (imgfile,self.targetdir,filepath))
        if self.document!=None:
            if self.word_host.Selection.Range.ListFormat.ListType == win32com.client.constants.wdListBullet:
                self.word_host.Selection.Range.ListFormat.ApplyBulletDefault(win32com.client.constants.wdWord9ListBehavior)
            try:
                self.word_host.Selection.InlineShapes.AddPicture(FileName=filepath,\
                  LinkToFile=False, SaveWithDocument=True)
            except:
                if trusted:
                    self.request.write("error in img, imgfile=%s, docpath=%s" % (filepath,str(self.document.Path)))
                    self.request.write("Active %s" % str(self.word_host.Selection.Active))
#                    raise
                    errtext='[internal image not found:%s]' % filepath
#                    self.document.Undo()
                    try:
                        self.word_host.Selection.TypeText(errtext)
                    except:
                        self.request.write("error reset did not work, may need Office 2000 SP3?")
                        raise "error reset did not work, may need Office 2000 SP3?"
                else:
                    raise
                    self.request.write("warning in img, imgfile=%s, docpath=%s" % (filepath,str(self.document.Path)))
                    self.word_host.Selection.TypeText('[external image not found:%s]' % filepath)
                    
            self.word_host.Selection.TypeText(' ')
#            self._save()


    def image(self, **kw):
        """ Take HTML <IMG> tag attributes in `attr`.
            Attribute names have to be lowercase!
        """
        if _debug:
            traceback.print_stack(limit=1,file=sys.stdout)
#RS fatal error handling
        if self.dead==1:
            return u""
#RS end
        attrstr = u''
        for attr, value in kw.items():
            if attr=='html_class':
                attr='class'
            attrstr = attrstr + u' %s="%s"' % (attr, wikiutil.escape(value))
        imgurl=kw.get('src','')
        self.request.write("\n try image, imgurl=%s" % (imgurl))
        if imgurl!='':
            self._img(imgurl,**kw)
        result= u'<img%s/>' % attrstr
        return result




    def rawHTML(self, markup):
        """ This allows emitting pre-formatted HTML markup, and should be
            used wisely (i.e. very seldom).

            Using this event while generating content results in unwanted
            effects, like loss of markup or insertion of CDATA sections
            when output goes to XML formats.
        """
        return '<<'+markup+'>>'
