"""
    "All of your base are belong to us"
"""
# $Id: XMLKitBase.py,v 1.1.1.1 2002/02/03 17:07:16 root Exp $
#
# $Log: XMLKitBase.py,v $
# Revision 1.1.1.1  2002/02/03 17:07:16  root
#
#
# Revision 1.6  2001/11/14 17:08:49  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 11:33:14  adrian
# Fixed bug with calling DateTime.DateTime() that was preventing reloading
# of data after a "Product Refresh".
#
# Revision 1.3  2001/10/26 12:37:53  adrian
# Added return value from _reload and _auto_reload to signal if
# any work was done. They now return 1 for a successful
# download, or 0 if no work was done or an error occured.
# This can be used to provide multi-level caching as in PatchKit's
# PackageUpdate patch.
#
# Revision 1.2  2001/10/24 15:34:12  adrian
# Completed factoring out common code into 3 base classes
# (XMLClientBase, XMLServerBase, and XMLReloadBase)
#
# Completed XMLProxy.
#
# Revision 1.1  2001/10/23 00:30:10  adrian
# no message
#
#
__version__ = '$Revision: 1.1.1.1 $'[11:-2]

import Globals
from DateTime import DateTime
import Acquisition
from DocumentTemplate import DT_HTML
import OFS.PropertyManager

class XMLClientBase:
    """ Miscellaneous client (XML Downloader) methods """
    source = ''
    manage_options = (
    )
    _properties = (
        {'id':  'source',       'type': 'string',   'mode': 'w'},
    )
    __ac_permissions__ = (
        ('View',
            ('title', ),
            ('Manager', 'Anonymous', ),
        ),
    )

    def title(self, REQUEST=None):
        """ """
        return "XML from %s" % self.source

Globals.default__class_init__(XMLClientBase)

class XMLServerBase:
    """ Miscellaneous server (XML Creator) methods """
    manage_options = (
        {'label': 'View', 'action': '', },
    )
    _properties = (
    )
    __ac_permissions__ = (
        ('View',
            ('__call__', '__str__', '', ),
            ('Manager', 'Anonymous', ),
        ),
    )

# Must be defined in descendants to replace the DOM with a new one
    def _internal_getDOMref(self, newDOM):
        """
            Return a reference to the internal DOM
        """
        raise "_internal_setDOMref() not defined in %s" + self.name

    def _auto_reload(self):
        """
            Do-nothing method. This could be replaced by a reparser or whatever.
            This is only called (Internally) by __str__ or a number of methods
            in XMLReloadBase. If you need standard reloading, list XMLReloadBase
            BEFORE XMLServerBase.
        """
        return 1

    def __call__(self, client=None, REQUEST={}, RESPONSE=None, **kw):
        """
            Return the content of this DOM as text/xml.
        """
        if not REQUEST:
            REQUEST = self.REQUEST
        if not RESPONSE:
            RESPONSE = REQUEST.RESPONSE
        if not client:
            RESPONSE.setHeader('content-type', 'text/xml')
        return str(self)

    def __str__(self):
        """
            Return the content of this DOM as text without setting the content_type.
        """
        self._auto_reload()
        return str(self._internal_getDOMref())

Globals.default__class_init__(XMLServerBase)

class XMLReloadBase:
    """ Supports manual and timed reloading of XML data """
    autoreload = 1
    reloadtimer = 30
    last_reload = long(0.0)
    manage_options = (
        {'label': 'View DOM', 'action': 'viewdom',
         'help':('XMLKit', 'viewdom.stx'), },
        {'label': 'Reload', 'action': 'manage_reload'},
    )
    _properties = (
        {'id':  'autoreload',   'type': 'boolean',  'mode': 'w'},
        {'id':  'reloadtimer',  'type': 'int',      'mode': 'w'},
    )
    __ac_permissions__ = (
        ('View',
            ('viewdom', ),
            ('Manager', 'Anonymous', ),
        ),
        ('Manage XML Objects',
            ('manage_reload', ),
            ('Manager', ),
        )
    )

# Must be defined in descendants to clear the DOM
    def _internal_initEmpty(self):
        raise "_internal_initEmpty() not defined in %s" + self.name

# Must be defined in descendants to reload the DOM
    def _internal_reload(self):
        raise "_internal_reload() not defined in %s" + self.name

# Must be defined in descendants to return a reference to the DOM
    def _internal_getDOMref(self):
        raise "_internal_getDOMref() not defined in %s" + self.name

# Must be defined in descendants to replace the DOM with a new one
    def _internal_setDOMref(self, newDOM):
        raise "_internal_setDOMref() not defined in %s" + self.name

    def viewdom(self, REQUEST=None):
        """ Display a pretty dump of the XML data stored in the DOM """
        self._auto_reload()
        dtml = "<dtml-var manage_page_header>\n<dtml-var manage_tabs>\n\n"
        dtml = dtml + "&lt;!-- XML Last Downloaded: %s --&gt;\n<br />\n<pre>" % (
            DateTime(self.last_reload).rfc822())
        dtml = dtml + self._internal_getDOMref().dump()
        dtml = dtml + "</pre>\n\n<dtml-var manage_page_footer>"
        obj = DT_HTML.HTML(dtml, self.REQUEST, str(self.title_and_id()))
        return obj(self.aq_inner, self.REQUEST)

    def _updateProperty(self, id, value):
        """ Catch changes to properties and recache the DOM """
        self.last_reload = long(0.0)
        OFS.PropertyManager.PropertyManager._updateProperty(self, id, value)

    def manage_reload(self, REQUEST=None):
        """ Reload the datasource (And return to the props) """
        self._reload(2)
        if REQUEST:
            return Globals.MessageDialog(
                title='XML data reloaded',
                message='XML data reloaded!',
                action ='./manage_workspace',
            )

    def _auto_reload(self):
        """ Test if the file should be auto-reloaded.
            It will auto-reload if the autoreload is set and the data
            is more than 30 mins old.
            Return 1 on successful reload, 0 otherwise
        """
        if self.autoreload:
            dt = long(DateTime()) - long(self.last_reload)
            if dt > (self.reloadtimer * 60.0):
                return self._reload(1)
        return 0

    def _reload(self, preserve = 0):
        """ Reload the data-set - Calls self.reload()
            Values from 'preserve':
                0   -   Destroy existing data if the reload fails
                1   -   Keep the existing data if the reload fails
                2   -   Raise an exception if the reload fails
            Return 1 on successful reload, 0 otherwise
        """
        saveDOM = self._internal_getDOMref()
        try:
            self._internal_reload()
            self.last_reload = long(DateTime())
            return 1
        except:
            if preserve == 0:
                self._internal_initEmpty()
            elif preserve == 1:
                self._internal_setDOMref(saveDOM)
            else:
                raise
            return 0

Globals.default__class_init__(XMLReloadBase)
