"""
Download data from an ODBC Socket Server.
"""
# $Id: XMLODBCClient.py,v 1.1.1.1 2002/02/03 17:07:16 root Exp $
#
# $Log: XMLODBCClient.py,v $
# Revision 1.1.1.1  2002/02/03 17:07:16  root
#
#
# Revision 1.8  2002/01/30 11:36:14  adrian
# Depricated XMLODBCClient. Does not work on Zope 2.3.x
# which does not support the 'visibility=' attribute to registerClass
#
# Revision 1.6  2002/01/13 01:20:04  adrian
# Added brain support to ODBC Socket Client
#
# Revision 1.5  2002/01/11 18:55:35  adrian
# no message
#
# Revision 1.4  2002/01/02 07:52:03  adrian
# Fixed minor bug in title and corrected management tabs
#
# Revision 1.3  2001/11/14 20:00:21  adrian
# Change parameters for socket_object.connect to a tuple for
# compatibility with Python 2.x (Should still work with Python 1.5)
#
# Revision 1.2  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.1  2001/11/14 13:35:33  adrian
# Added ODBC Socket Server client object.
#
#
__version__ = '$Revision: 1.1.1.1 $'[11:-2]

import Globals
import AccessControl.Role
import OFS.SimpleItem
import OFS.PropertyManager
import Persistence
import Acquisition
import XML
import OFS.History
import urllib
import socket
import string
from DocumentTemplate import DT_HTML
import Shared.DC.ZRDB.Results
import Shared.DC.ZRDB.DA
from App.Extensions import getBrain
import XMLKitBase

manage_addXMLODBCClientForm = Globals.HTMLFile('www/addXMLODBCClient', globals())
def manage_addXMLODBCClient(self, id, server, port, dsn, query, submit=None, REQUEST=None):
    """ """
    raise "Depricated Product", "This XML ODBC Client has been superceeded by ODBC Client from ZDataQueryKit"
    obj = XMLODBCClient(str(id), str(server), int(port), str(dsn), str(query))
    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 XMLODBCClient(
        XMLKitBase.XMLReloadBase,
        XMLKitBase.XMLServerBase,
        OFS.PropertyManager.PropertyManager,
        OFS.SimpleItem.SimpleItem,
        Persistence.Persistent,
        Acquisition.Implicit,
        AccessControl.Role.RoleManager,
        OFS.History.Historical,
#        Shared.DC.ZRDB.DA.DA,
    ):
    """ """
    id = "XMLODBCClient"
    title = "XML ODBC Socket Server Client"
    meta_type = "Z ODBC Client"
    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 = (
        OFS.PropertyManager.PropertyManager.manage_options +
        (
            {'label' : 'Preview',   'action' : 'manage_preview', },
        ) +
        XMLKitBase.XMLServerBase.manage_options[1:] +
        XMLKitBase.XMLReloadBase.manage_options +
        (
            {'label':'Advanced', 'action':'manage_advancedForm',
             'help':('ZSQLMethods','Z-SQL-Method_Advanced.stx')},
        ) +
        OFS.History.Historical.manage_options +
        OFS.SimpleItem.SimpleItem.manage_options
    )
    _properties=(
        (
            {'id':  'server',   'type': 'string',   'mode': 'w'},
            {'id':  'port',     'type': 'int',      'mode': 'w'},
            {'id':  'dsn',      'type': 'string',   'mode': 'w'},
            {'id':  'query',    'type': 'text',     'mode': 'w'},
        )+
        XMLKitBase.XMLServerBase._properties +
        XMLKitBase.XMLReloadBase._properties
    )
    __ac_permissions__ = (
        ('View',
            ('title', 'DOM', '', ),
            ('Manager', 'Anonymous', ),
        ),
        ('View management screens',
            ('manage_preview', ),
            ('Manager', ),
        ),
    )

    server  = "localhost"
    port    = 9628
    dsn     = "DSN=;"
    query   = "select * from table"

    class_name_ = ""
    class_file_ = ""
    _v_brain = None
    max_rows_ = -1
    enable_max_rows_ = 0

    manage_advancedForm = Globals.HTMLFile('www/advanced', globals())
    
    def __init__(self, id, server, port, dsn, query):
        """ """
        self.id = id
        self.server = server
        self.port = port
        self.dsn = dsn
        self.query = query
        self.xp = XML.XMLParser.XMLParser()

    def cache_time_(self):
        """ Kludge """
        return self.reloadtimer

    def title(self, REQUEST=None):
        """ """
        try:
            return "XML OSS on %s:%d %s" % (self.server, self.port, self.dsn, )
        except:
            return "XML OSS"

    def manage_preview(self, REQUEST=None, RESPONSE=None):
        """Returns an HTML representation of the OSS's data"""
        self._auto_reload()
        colNames = self._col_names()
        dtml = "<dtml-var manage_page_header><dtml-var manage_tabs><br><table border=1><tr><th>"
        dtml = dtml + string.join(colNames, "</th>\n<th>") + "</th></tr>\n"
        rows = self._rows()
        for row in rows:
            dtml = dtml + "<tr>"
            for col in colNames:
                dtml = dtml + "<td>%s</td>" % (row[col], )
            dtml = dtml + "</tr>\n"
        dtml = dtml + "</table><br>\n"
        dtml = dtml + "%d records selected" % (len(rows), )
        dtml = dtml + "<dtml-var manage_page_footer>"
        obj = DT_HTML.HTML(dtml, self.REQUEST,
            'XMLODBCClient - manage_preview - %s' % self.getId())
        return obj(self.aq_inner, REQUEST)

    def manage_advanced(self, cache_time,
                        class_name, class_file, direct=None,
                        REQUEST=None, zclass=''):
        """ Change Advanced Properties (Borrowed from Shared.ZRDB.DA.DA)
            The max rows, and cache controls have been removed """
        self.last_reload = long(0.0)
        # paranoid type checking
        if type(cache_time) is not type(1):
            cache_time=atoi(cache_time)
        self.reloadtimer = cache_time
        class_name=str(class_name)
        class_file=str(class_file)
        self.class_name_, self.class_file_ = class_name, class_file
        self._v_brain=getBrain(self.class_file_, self.class_name_, 1)
        self.allow_simple_one_argument_traversal=direct
        if zclass:
            for d in self.aq_acquire('_getProductRegistryData')('zclasses'):
                if ("%s/%s" % (d.get('product'),d.get('id'))) == zclass:
                    self._zclass=d['meta_class']
                    break
        if REQUEST is not None:
            m="%s advanced settings have been set" % (self.meta_type,)
            return self.manage_advancedForm(self,REQUEST,manage_tabs_message=m)

    def _check_result(self):
        """ Raise the error """
        dom = self._internal_getDOMref()
        result = dom.getNextChildByName("result")
        cols = []
        if result["state"] != "success":
            error = result.getNextChildByName("error")
            raise "% - Query Failed: %s" % (self.meta_type, error.getCDATA(), )

    def _col_names(self):
        """ Return the column names from the first data record """
        self._auto_reload()
        self._check_result()
        dom = self._internal_getDOMref()
        result = dom.getNextChildByName("result")
        cols = []
        row = result.getNextChildByName("row")
        for item in row.getChildrenByName("column"):
            cols.append(item["name"])
        return tuple(cols)

    def _data_dictionary(self):
        """ Construct a fake data dictionary """
        dd = []
        for col in self._col_names():
            item = {'name' : '%s' % col, 'type' : 's'}
            dd.append(item)
        return tuple(dd)

    def _rows(self):
        """ Return the data rows """
        self._auto_reload()
        colNames = self._col_names()
        rows = []
        self._auto_reload()
        self._check_result()
        dom = self._internal_getDOMref()
        result = dom.getNextChildByName("result")
        cols = []
        for row in result.getChildrenByName("row"):
            resRow = {}
            item = None
            for col in colNames:
                item = row.getNextChildByName("column", item)
                resRow[col] = item.getCDATA()
            rows.append(resRow)
        return tuple(rows)

    def _results(self, rows):
        """ """
        if hasattr(self, '_v_brain'):
            brain = self._v_brain
        else:
            brain = self._v_brain = getBrain(self.class_file_, self.class_name_)
        return Shared.DC.ZRDB.Results.Results((self._data_dictionary(), rows), brains=brain, parent=None)

    def __call__(self, *args, **kargs):
        """ """
        return self._results(self._rows())

    def DOM(self):
        """ Return the DOM """
        return self._internal_getDOMref()

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

    def _internal_reload(self):
        """ Reload the XML data """
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        sock.connect((self.server, self.port), )
        file = sock.makefile('rb')
        Ssend = "<?xml version=\"1.0\"?>\r\n <request>\r\n<connectionstring>" 
        Ssend = Ssend + self.dsn + "</connectionstring>\r\n<sql>" 
        Ssend = Ssend + self.query + "</sql>\r\n</request>\r\n"
        sock.send(Ssend)
        retStr = file.read()
        sock.close()
        self.xp.runString(retStr)

    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

Globals.default__class_init__(XMLODBCClient)
