# -*- coding: iso-8859-1 -*-
"""
    MoinMoin - XML Parser

    This parser was tested with 4Suite 1.0a4 and 1.0b1.

    What's new:
    * much cleaner code
    * stylesheet can be extended to support other format:
        e.g. Docbook parser using docbook->html .xsl stylesheet

    @copyright: 2001-2003 Juergen Hermann <jh@web.de>,
                2005 Henry Ho <henryho167@hotmail.com>,
                2005 by MoinMoin:AlexanderSchremmer
    @license: GNU GPL, see COPYING for details.
"""

# cStringIO cannot be used because it doesn't handle Unicode.
import StringIO

from MoinMoin import caching, config, wikiutil, Page

Dependencies = []

class Parser:
    """ Send XML file formatted via XSLT. """
    caching = 1
    Dependencies = Dependencies

    def __init__(self, raw, request, **kw):
        self.raw = raw
        self.request = request
        self.form = request.form
        self._ = request.getText
        self.base_scheme = 'wiki'
        self.base_uri = 'wiki://Self/'
        self.key = 'xslt'

    def format(self, formatter, **kw):
        """ Send the text. """
        _ = self._

        if not self.request.cfg.allow_xslt:
            # use plain text parser if XSLT is not allowed
            # can be activated in wikiconfig.py
            from MoinMoin.parser.text import Parser as TextParser
            self.request.write(formatter.sysmsg(1) +
                               formatter.rawHTML(_('XSLT option disabled, please look at HelpOnConfiguration.', wiki=True)) +
                               formatter.sysmsg(0))
            TextParser(self.raw, self.request).format(formatter)
            return

        try:
            # try importing Ft from 4suite
            # if import fails or its version is not 1.x, error msg
            from Ft.Xml import __version__ as ft_version
            assert ft_version.startswith('1.')
        except (ImportError, AssertionError):
            self.request.write(self.request.formatter.sysmsg(1) +
                               self.request.formatter.text(_('XSLT processing is not available, please install 4suite 1.x.')) +
                               self.request.formatter.sysmsg(0))
        else:
            from Ft.Lib import Uri
            from Ft.Xml import InputSource
            from Ft.Xml.Xslt.Processor import Processor
            from Ft import FtException

            msg = None

            try:
                # location of SchemeRegisteryResolver has changed since 1.0a4
                if ft_version >= "1.0a4" or ft_version == "1.0" or ("1.0.1" <= ft_version <= "1.0.9"):
                    # such version numbers suck!
                    import Ft.Lib.Resolvers # Do not remove! it looks unused, but breaks when removed!!!

                class MoinResolver(Uri.SchemeRegistryResolver):
                    """ supports resolving self.base_uri for actual pages in MoinMoin """
                    def __init__(self, handlers, base_scheme):
                        Uri.SchemeRegistryResolver.__init__(self, handlers)
                        self.supportedSchemes.append(base_scheme)

                # setting up vars for xslt Processor
                out_file = StringIO.StringIO()
                wiki_resolver = MoinResolver(
                                    handlers={self.base_scheme: self._resolve_page, },
                                    base_scheme=self.base_scheme)
                input_factory = InputSource.InputSourceFactory(resolver=wiki_resolver)

                page_uri = self.base_uri + wikiutil.url_quote(formatter.page.page_name)
                # 4Suite needs an utf-8 encoded byte string instead of an unicode object
                raw = self.raw.strip().encode('utf-8')
                self.processor = Processor()
                self.append_stylesheet() # hook, for extending this parser
                self.processor.run(
                    input_factory.fromString(raw, uri=page_uri),
                    outputStream=out_file)
                # Convert utf-8 encoded byte string into unicode
                result = out_file.getvalue().decode('utf-8')
                result = self.parse_result(result) # hook, for extending this parser

            except FtException, msg:
                etype = "XSLT"
            except Uri.UriException, msg:
                etype = "XSLT"
            except IOError, msg:
                etype = "I/O"

            if msg:
                text = wikiutil.escape(self.raw)
                text = text.expandtabs()
                text = text.replace('\n', '<br>\n')
                text = text.replace(' ', '&nbsp;')
                before = _('%(errortype)s processing error') % {'errortype': etype, }
                title = u"<strong>%s: %s</strong><p>" % (before, msg)
                self.request.write(title)
                self.request.write(text.decode(config.charset))
            else:
                self.request.write(result)
                cache = caching.CacheEntry(self.request, formatter.page, self.key, scope='item')
                cache.update(result)

    def _resolve_page(self, uri, base):
        """ URI will be resolved into StringIO with actual page content """
        from Ft.Lib import Uri
        base_uri = self.base_uri

        if uri.startswith(base_uri):
            pagename = uri[len(base_uri):]
            page = Page.Page(self.request, pagename)
            if page.exists():
                result = StringIO.StringIO(page.getPageText().encode(config.charset))
            else:
                raise Uri.UriException(Uri.UriException.RESOURCE_ERROR, loc=uri,
                                       msg='Page does not exist')
        else:
            result = Uri.UriResolverBase.resolve(self, uri, base)

        return result

    def append_stylesheet(self):
        """ for other parsers based on xslt (i.e. docbook-xml) """
        pass

    def parse_result(self, result):
        """ additional parsing to the resulting XSLT'ed result before saving """
        return result

