"""
A document that can render text/xml data (provided elsewhere). This is
almost like xsl. (I did say almost)
"""
# $Id: XMLDocument.py,v 1.2 2002/05/01 22:41:43 adrian Exp $
#
# $Log: XMLDocument.py,v $
# Revision 1.2  2002/05/01 22:41:43  adrian
# *** empty log message ***
#
# Revision 1.1.1.1  2002/02/03 17:07:16  root
#
#
# Revision 1.8  2002/01/16 07:54:50  adrian
# Fixed annoying message in error log from XMLDocument
#
# Revision 1.7  2001/12/11 08:06:31  adrian
# Still not quite right
#
# Revision 1.6  2001/11/14 17:08:48  adrian
# Corrected Auto Update bug where changing properties failed to
# cause a data-reload.
# Changed XMLODBCClient to return brains instead of XML
# (DOM(self) returns the DOM for clients if required)
#
# Revision 1.5  2001/10/31 01:25:46  adrian
# Fixed several problems with creation and editing of XMLFiles
# Fixed pretty-printing of XML (Indentation)
#
# Revision 1.4  2001/10/29 09:20:48  adrian
# Cleaned up a number of "Ambiguous name..." warnings
#
# Revision 1.3  2001/10/24 15:34:12  adrian
# Completed factoring out common code into 3 base classes
# (XMLClientBase, XMLServerBase, and XMLReloadBase)
#
# Completed XMLProxy.
#
# Revision 1.2  2001/10/21 15:10:15  adrian
# no message
#
#
__version__ = '$Revision: 1.2 $'[11:-2]

import Globals
import OFS.SimpleItem
import OFS.PropertyManager
import OFS.History
import OFS.Cache
import AccessControl.Role
import App.Undo
import Persistence
import Acquisition
import XML
import urllib
from DocumentTemplate import DT_HTML
import string
import DateTime
import XMLKitBase

manage_addRSSDocumentForm = Globals.DTMLFile('www/addRSSDocument', globals())
def manage_addRSSDocument(self, id, source='', submit=None, REQUEST=None):
    """ """
    obj = RSSDocument(str(id), str(source))
    self._setObject(obj.getId(), obj)
    if REQUEST is not None:
        try: u=self.DestinationURL()
        except: u=REQUEST['URL1']
        if submit==" Add and Edit ": u="%s/%s" % (u, urllib.quote(obj.getId()))
        REQUEST.RESPONSE.redirect(u+'/manage_workspace')
    return ''

manage_addXMLDocumentForm = Globals.DTMLFile('www/addXMLDocument', globals())
def manage_addXMLDocument(self, id, source='', submit=None, REQUEST=None):
    """ """
    obj = XMLDocument(str(id), str(source))
    self._setObject(obj.getId(), obj)
    if REQUEST is not None:
        try: u=self.DestinationURL()
        except: u=REQUEST['URL1']
        if submit==" Add and Edit ": u="%s/%s" % (u, urllib.quote(obj.getId()))
        REQUEST.RESPONSE.redirect(u+'/manage_workspace')
    return ''

class XMLDocument(
        XMLKitBase.XMLReloadBase,
        XMLKitBase.XMLClientBase,
        OFS.PropertyManager.PropertyManager,
        OFS.SimpleItem.SimpleItem,
        Persistence.Persistent,
        Acquisition.Implicit,
        AccessControl.Role.RoleManager,
        OFS.History.Historical,
        OFS.Cache.Cacheable,
    ):
    """ A simple object to download and render XML files """
    id = "XMLDocument"
    title = "XML Document"
    meta_type = "XML Document"
    manage_editForm = Globals.DTMLFile('www/editXMLDocument', globals(), property_extensible_schema__=1)
    manage_main = Globals.ComputedAttribute.ComputedAttribute('manage_editForm')
#    manage_editForm.setName('manage_editForm')
    manage_editInsert = Globals.DTMLFile('www/insertXMLDocument', globals())
    index_html = None

    # Masquerade as function:
    class func_code: pass
    func_code=func_code()
    func_code.co_varnames='self','REQUEST','RESPONSE'
    func_code.co_argcount=3

    manage_options  = (
        (
            {'label': 'Edit', 'action': 'manage_editForm'},
        ) +
        OFS.PropertyManager.PropertyManager.manage_options +
        (
            {'label': 'View', 'action': 'preview'},
        ) +
        XMLKitBase.XMLClientBase.manage_options +
        XMLKitBase.XMLReloadBase.manage_options +
        App.Undo.UndoSupport.manage_options +
        AccessControl.Role.RoleManager.manage_options
    )
    _properties = (
        (
            {'id':  'use_headers',  'type': 'boolean',  'mode': 'w'},
        ) +
        XMLKitBase.XMLClientBase._properties +
        XMLKitBase.XMLReloadBase._properties
    )
    __ac_permissions__ = (
        ('Change XML Documents',
            (
                'manage_editForm', 'manage_editInsert',
                'manage_addEntity', 'manage_delEntity',
                'manage_listEntities',
                'manage_edit', 'manage_reload',
            ),
            ('Manager', ),
        ),
    )
    use_headers = 1

    def __init__(self, id, source):
        """ Initialize this RSSDocument """
        self.id = id
        self.source = source
        self.xp = XML.XMLParser.XMLParser()
        em = {}
        em['error'] = (str(default_error_open), str(default_error_close))
        self.entityMap = em

    def _internal_initEmpty(self):
        """ Clear the DOM """
        self.xp.reset()

    def _internal_reload(self):
        """ Reload the XML data """
        try:
            source = self.unrestrictedTraverse(self.source).absolute_url()
        except:
            source = self.source
        self.xp.runURL(source)

    def _internal_getDOMref(self):
        """ Return a reference to the DOM """
        return self.xp.DOM

    def _internal_setDOMref(self, newDOM):
        """ replace the DOM with a new one """
        self.xp.DOM = newDOM

    def manage_listEntities(self):
        """ """
        return self.entityMap.keys()

    def manage_edit(self, entity, open, close, REQUEST=None):
        """ """
        if self.entityMap.has_key(entity):
            em = self.entityMap
            em[entity] = (str(open), str(close))
            self.entityMap = em
            msg = "Entity %s updated" % entity
        else:
            msg = "Entity %s does not exist" % entity
        if REQUEST:
            return self.manage_editForm(self, REQUEST,
                manage_tabs_message = msg)

    def manage_addEntity(self, entity, REQUEST=None):
        """ """
        if self.entityMap.has_key(entity):
            msg = "Entity %s already exists" % entity
        else:
            em = self.entityMap
            em[entity] = (str(default_open), str(default_close))
            self.entityMap = em
            msg = "Entity %s created" % entity
        if REQUEST:
            return self.manage_editForm(self, REQUEST,
                manage_tabs_message = msg)

    def manage_delEntity(self, entity, REQUEST=None):
        """ """
        if self.entityMap.has_key(entity):
            em = self.entityMap
            del em[entity]
            self.entityMap = em
            msg = "Entity %s deleted" % entity
        else:
            msg = "Entity %s does not exist" % entity
        if REQUEST:
            return self.manage_editForm(self, REQUEST,
                manage_tabs_message = msg)

    def _getChildCData(self, Node, name):
        """ """
        retval = ''
        if Node:
            child = Node.getNextChildByName(name)
            if child:
                retval = child.getCDATA()
        return retval

    def _renderNode(self, Node, REQUEST=None, kw={}):
        """ """
        dtml = ''
        ns = {}
        objO = None
        objC = None
        if hasattr(Node, 'getTag'):
            tag = Node.getTag()
        else:
            tag = ''
        if self.entityMap.has_key(tag):
            objO = DT_HTML.HTML(self.entityMap[tag][0], self.REQUEST,
                'XMLDocument - open - %s' % tag)
            objC = DT_HTML.HTML(self.entityMap[tag][1], self.REQUEST,
                'XMLDocument - close - %s' % tag)
            if hasattr(Node, 'getChildrenByName'):
                for child in Node.getChildrenByName():
                    if hasattr(child, 'getTag'):
                        ns[child.getTag()] = self._getChildCData(Node, child.getTag())
            ns['tag'] = tag;
            for k in kw.keys():
                ns[k] = kw[k]
            ns['cdata'] = Node.getCDATA()
            if hasattr(Node, 'keys'):
                for attr in Node.keys():
                    ns[attr] = Node.getAttr(attr)
        if objO:
            dtml = dtml + apply(objO.__call__,
                (self.aq_parent.aq_inner, REQUEST), ns)
        if hasattr(Node, 'getChildrenByName'):
            for child in Node.getChildrenByName():
                dtml = dtml + self._renderNode(child, REQUEST, kw)
        if objC:
            dtml = dtml + apply(objC.__call__,
                (self.aq_parent.aq_inner, REQUEST), ns)
        return dtml

    def preview(self, REQUEST={}):
        """ """
        return self(REQUEST=REQUEST, manage_headers=1)

    def __call__(self, client=None, REQUEST={}, RESPONSE=None, **kw):
        """ """
        self._auto_reload()
        if kw.has_key('manage_headers'):
            dtml = '<dtml-var manage_page_header>\n<dtml-var manage_tabs>\n'
        elif self.use_headers or kw.has_key('use_headers'):
            dtml = '<dtml-var standard_html_header>'
        else:
            dtml = ''
        ns = {}
        for k in kw.keys():
            ns[k] = kw[k]
        ns['last_reload'] = DateTime.DateTime(self.last_reload)
        ns['source_url'] = self.source
        dtml = dtml + self._renderNode(self.xp.DOM, REQUEST, ns)
        if kw.has_key('manage_headers'):
            dtml = dtml + '<dtml-var manage_page_footer>'
        elif self.use_headers or kw.has_key('use_headers'):
            dtml = dtml + '<dtml-var standard_html_footer>'
        obj = DT_HTML.HTML(dtml, self.REQUEST,
            'XMLDocument - __call__ - %s' % self.title_and_id())
        return obj(self.aq_inner, REQUEST)

class RSSDocument(
        XMLDocument,
    ):
    """ A simple object to download and render RSS files """
    id = "RSSDocument"
    title = "RSS Document"
    meta_type = "RSS Document"
    manage_editInsert = ''

    def __init__(self, id, source):
        """ Initialize this RSSDocument """
        XMLDocument.__init__(self, id, source)
        em = {}
        em['channel'] = (str(default_channel_open), str(default_channel_close))
        em['item'] = (str(default_item_open), str(default_item_close))
        em['textinput'] = (str(default_input_open), str(default_input_close))
        em['error'] = (str(default_error_open), str(default_error_close))
        self.entityMap = em

    def title(self, REQUEST=None):
        """ Return the rss.channel.title.cdata (a-hem..) """
        self._auto_reload()
        title = None
        rss = self.xp.DOM.getNextChildByName('rss')
        if rss:
            chan = rss.getNextChildByName('channel')
            if chan:
                title = self._getChildCData(chan, 'title')
        if not title:
            title = 'Untitled'
        return title

Globals.default__class_init__(XMLDocument)

default_open = """<!-- Entity &dtml-tag; opened -->
"""

default_close = """<!-- Entity &dtml-tag; closed -->
"""

default_channel_open = """<h2 align="center"><dtml-var description></h2>
<dtml-if link><h4 align="center"><a href="<dtml-var
link>">Click here to visit "<dtml-var
title>"</a></h4></dtml-if>
<dl>
"""

default_channel_close = """
</dl>
<h6 align="right">Last Downloaded: <dtml-var last_reload fmt=rfc822></h6>"""

default_item_open = """
<dt><dtml-if link><a href="<dtml-var link>"></dtml-if>
<dtml-var title missing="No title for this item">
<dtml-if link></a></dtml-if></dt>
<dd><dtml-var description></dd>
"""

default_item_close = ''

default_input_open = """
<form action="<dtml-var link>" method="post">
<table width="100%" cellpadding="2" cellspacing="0">
<tr>
 <th align="left" valign="middle" width="33%"><dtml-var description></th>
 <td align="center" valign="middle" width="33%"><input type="text" size="35" name="<dtml-var name>" /></td>
 <td align="right" valign="middle" width="33%"><input type="submit" name="submit" value="<dtml-var title>" /></td>
</tr>
</table></form>"""

default_input_close = ''

default_error_open = """<h2 align="center"><dtml-var title></h2>
<h4 align="center"><dtml-var description></h4>
"""

default_error_close = """<dtml-comment>
This element is created if an error occurs that prevents the XML from being downloaded.
</dtml-comment>"""