"""
    ODBC Socket Server Client Class
    ==== ====== ====== ====== =====

Simple ODBC Socket Server client using pyExpat.
"""
# $Id: OSSClient.py,v 1.4 2002/05/14 13:27:05 ahungate Exp $
#
# $Log: OSSClient.py,v $
# Revision 1.4  2002/05/14 13:27:05  ahungate
# *** empty log message ***
#
# Revision 1.3  2002/05/10 11:23:44  ahungate
# Fixed bug in the OSSClient with retreiving data.
#
# Revision 1.2  2002/04/18 15:34:37  ahungate
# Fixed problem where client duplicated column names if the server put column names on every record.
#
# 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
#
#
__version__ = '$Revision: 1.4 $'[11:-2]

import socket
import Shared.DC.xml.pyexpat

xmlQueryTemplate = """<?xml version="1.0"?>
<request>
<connectionstring>%s</connectionstring>
<sql>%s</sql>
</request>"""

class OSSClient:
    """ A simple ODBC Socket Server client """

    def __init__(self, server, port, dsn, query):
        """ Initiate and run a query """
        # Set the initial state
        self.state = 0         # 0 = No query/dsn/server/port, 1 = Success, -1 = Failure
        self.error = ""
        self.columns = []
        self.data = []
        self.datadictionary = []
        self.nowIn = []
        if not server or not port or not dsn or not query:
            return
        # Go get the results
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        sock.connect((server, port), )
        file = sock.makefile('rb')
        xmlQuery = xmlQueryTemplate % (dsn, query)
        sock.send(xmlQuery)
        xmlRetStr = file.read()
        sock.close()
        # Create the XML Parser
        parser = Shared.DC.xml.pyexpat.ParserCreate()
        parser.StartElementHandler = self.elementStart
        parser.EndElementHandler = self.elementEnd
        parser.CharacterDataHandler = self.cdata
        # Parse the results
        rv = parser.Parse(xmlRetStr, 1)
#	raise "Debug", "%s" % (xmlRetStr, )
        if self.state!=1:
            return
        self.columns = tuple(self.columns)
        tmpData = self.data
        self.data = []
        for row in tmpData:
            newRow = {}
            for colId in range(0, len(self.columns)):
              try:
                newRow[str(self.columns[colId])] = row[colId]
              except:
                newRow[str(self.columns[colId])] = None
#                raise "Debug", "<br>%s<br>%s<br>%d" % (self.columns, row, colId, )
            self.data.append(newRow)
        self.data = tuple(self.data)
        for col in self.columns:
            item = {'Name' : str(col), 'name': str(col), 'type' : 's'}
            self.datadictionary.append(item)
        self.datadictionary = tuple(self.datadictionary)

    def elementStart(self, name, attrs):
        """ Deal with element start """
        self.nowIn.append(name)
        if name=="result":
            if attrs[0] == 'state' and attrs[1] == 'success':
                self.state = 1
            elif attrs[0] == 'state' and attrs[1] == 'failure':
                self.state = -1
        elif name=="error":
            pass
        elif name=="row":
            self.currentRow = []
        elif name=="column":
            if not self.data and attrs:
                if attrs[0] == 'name':
                    self.columns.append(attrs[1])
            self.currentColumn=""
        else:
            raise "XML Processing Error", "Don't know how to handle '%s' element in XML data" % name

    def elementEnd(self, name):
        """ Pop the last name off the stack and sanity check """
        if self.nowIn.pop() != name:
            raise "XML Processing Error", "Element start/end mismatch"
        if name=="row":
            self.data.append(tuple(self.currentRow))
            del self.currentRow
        elif name=="column":
            self.currentRow.append(self.currentColumn)
            del self.currentColumn

    def cdata(self, data):
        """ Put data in the right place """
        if self.nowIn[-1]=="column":
            self.currentColumn = self.currentColumn + data
        elif self.nowIn[-1]=="error":
            self.error = self.error + data
        # Ignore all other data is it is all likely to be whitespace
