"""
Download data from an ODBC Socket Server.
"""
# $Id: ZODBCClient.py,v 1.2 2002/05/10 11:02:37 ahungate Exp $
#
# $Log: ZODBCClient.py,v $
# Revision 1.2  2002/05/10 11:02:37  ahungate
# Fixed bug that prevented creation/editing of Visual Queries on Zope < 2.4
#
# Revision 1.1.1.1  2002/02/03 17:07:16  root
#
#
# Revision 1.2  2002/01/30 17:37:41  adrian
# Fixed some ODBC Query Bugs
#
# Revision 1.1  2002/01/21 00:58:08  adrian
# Rebased all queries and datacombiner on the Aqueduct DA
# Added argument support
# Added Drill-Down support to ZReportTool
#
# 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.2 $'[11:-2]

import Globals
import OFS.PropertyManager
import urllib
import string
import OSSClient
import AccessControl
import Shared.DC.ZRDB.Aqueduct
import Shared.DC.ZRDB.Results
import Shared.DC.ZRDB.DA
from App.Extensions import getBrain
try: from IOBTree import Bucket
except: Bucket=lambda:{}

manage_addZODBCClientForm = Globals.HTMLFile('www/addZODBCClient', globals())
def manage_addZODBCClient(self, id, server, port, dsn, submit=None, REQUEST=None):
    """ """
    obj = ZODBCClient(str(id), str(server), int(port), str(dsn))
    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 ZODBCClient(
        Shared.DC.ZRDB.DA.DA,
        OFS.PropertyManager.PropertyManager,
    ):
    """ """
    id = "ZODBCClient"
    title = "Z ODBC Client"
    meta_type = "Z ODBC Client"

    manage_main = Globals.HTMLFile('www/editQuery', globals())
    manage_advancedForm = Globals.HTMLFile('www/advanced', globals())
    manage_options = (
        OFS.PropertyManager.PropertyManager.manage_options +
        Shared.DC.ZRDB.DA.DA.manage_options
    )
    _properties=(
        (
            {'id':  'server',   'type': 'string',   'mode': 'w'},
            {'id':  'port',     'type': 'int',      'mode': 'w'},
            {'id':  'dsn',      'type': 'string',   'mode': 'w'},
        )
    )
    __ac_permissions__ = (
        ('View',
            ('title', '', ),
            ('Manager', 'Anonymous', ),
        ),
    )

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

#    class_name_ = ""
#    class_file_ = ""
#    _v_brain = None

    def __init__(self, id, server, port, dsn):
        """ """
        self.id = id
        self.server = server
        self.port = port
        self.dsn = dsn
        self.manage_edit(self.arguments_src, self.src)

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

    def manage_edit(self, arguments, template, SUBMIT='Change',
                    sql_pref__cols='50', sql_pref__rows='20',
                    REQUEST=None):
        """Query/Arguments

        The 'arguments' argument is a string containing an arguments
        specification, as would be given in the SQL method cration form.

        The 'template' argument is a string containing the source for the
        SQL Template.
        """

        if self._size_changes.has_key(SUBMIT):
            return self._er('','',arguments,template,
                            SUBMIT,sql_pref__cols,sql_pref__rows,REQUEST)

        if self.__dict__.has_key('wl_isLocked'):
            if self.wl_isLocked():
                raise ResourceLockedError, 'SQL Method is locked via WebDAV'
        
        arguments=str(arguments)
        self.arguments_src=arguments
        self._arg=Shared.DC.ZRDB.Aqueduct.parse(arguments)
        template=str(template)
        self.src=template
        self.template=t=self.template_class(template)
        t.cook()
        self._v_cache={}, Bucket()
        if REQUEST:
            if SUBMIT=='Change and Test':
                return self.manage_testForm(REQUEST)
            message='%s content changed' % self.meta_type
            return self.manage_main(self, REQUEST, manage_tabs_message=message)
        return ''

    def manage_advanced(self, 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 """
        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 __call__(self, REQUEST=None, __ick__=None, src__=0, test__=0, **kw):
        """Call the database method

        The arguments to the method should be passed via keyword
        arguments, or in a single mapping object. If no arguments are
        given, and if the method was invoked through the Web, then the
        method will try to acquire and use the Web REQUEST object as
        the argument mapping.

        The returned value is a sequence of record objects.
        """

        if REQUEST is None:
            if kw: REQUEST=kw
            else:
                if hasattr(self, 'REQUEST'): REQUEST=self.REQUEST
                else: REQUEST={}

        if hasattr(self, 'aq_parent'):
            p=self.aq_parent
            if self._isBeingAccessedAsZClassDefinedInstanceMethod():
                p=p.aq_parent
        else: p=None

        argdata=self._argdata(REQUEST)
        argdata['sql_delimiter'] = '\0'
        argdata['sql_quote__'] = self.sql_quote__

        security=AccessControl.getSecurityManager()
        security.addContext(self)
        try:     query=apply(self.template, (p,), argdata)
        finally: security.removeContext(self)

        if src__: return query

#        if self.cache_time_ > 0 and self.max_cache_ > 0:
#            result=self._cached_result(DB__, (query, self.max_rows_))
#        else: result=DB__.query(query, self.max_rows_)

        qry = OSSClient.OSSClient(server=self.server, port=self.port, dsn=self.dsn, query=query)
        if qry.state!=1:
            raise "Database Query Error - %s" % (qry.error, )
        result = (qry.datadictionary, qry.data)

        if hasattr(self, '_v_brain'): brain=self._v_brain
        else:
            brain=self._v_brain=getBrain(self.class_file_, self.class_name_)

        zc=self._zclass
        if zc is not None: zc=zc._zclass_

        if type(result) is type(''):
            f=StringIO()
            f.write(result)
            f.seek(0)
            result=RDB.File(f,brain,p, zc)
        else:
            result=Shared.DC.ZRDB.Results.Results(result, brain, p, zc)
        columns=result._searchable_result_columns()
        if test__ and columns != self._col: self._col=columns

        # If run in test mode, return both the query and results so
        # that the template doesn't have to be rendered twice!
        if test__: return query, result

        return result

    def sql_quote__(self, v):
        if string.find(v, "\'") >=0:
            v=string.join(string.split(v,"\'"), "''")
        return "'%s'" % v

Globals.default__class_init__(ZODBCClient)
