# FILE: SEParser.py
#
# SEParser - Search External core module
#
# parse xml soap data for the "Neuroinfo" standard query protocol
#
# (C) 2003 by CC Open Computer Systems for the "Neuroinfo" project
# This is free software avaiable under the GPL license, see:
#   LICENSE.txt, README.txt for details.
# ==================================================================
"""
Borrowed from wxPython XML tree demo and modified.
"""

import string
import Shared.DC.xml.pyexpat.pyexpat as expat
from DateTime import DateTime


# GB - Elements are used to build a tree or other structer representing object hierarchy
# GB - in fact we don't need this and we don't need elements at all, but we leave them in
# GB - in case the syntax gets more complicated in the future...
class Element:
    'A parsed XML element'
    def __init__(self,name,attributes):
        'Element constructor'
        self.name = name
        self.attributes = attributes
        self.cdata = ''

    def getAttribute(self,key):
        'Get an attribute value'
        return self.attributes.get(key)

    def getData(self):
        'Get the cdata'
        return self.cdata

# GB - Quick and dirty SOAP parser
# GB - we keep the parse state in flag variables: SOAP_in_...
# GB - the parser bulds a simple dictionary of search terms extracted from the
class qd_soap:
    'A parsed XML element'
    def  __init__(self):
        self.element=None
        self.SOAP_in_envelope=0
        self.SOAP_in_body=0

        # query
        self.SOAP_in_neuroquery=0
        self.SOAP_in_querytype=0
        self.SOAP_in_searchabletext=0
        self.SOAP_in_search=0
        self.SOAP_in_item=0
        self.SOAP_in_searchlogic=0
        self.SOAP_in_datebeg=0
        self.SOAP_in_dateend=0
        self.SOAP_in_search=0
        self.SOAP_in_item=0
        self.SOAP_in_pname=0
        self.SOAP_in_pvalue=0
        self.SOAP_defname=0

        # responce error
        self.SOAP_in_fault=0
        self.SOAP_in_faultactor=0
        self.SOAP_in_faultcode=0
        self.SOAP_in_faultstring=0
        self.SOAP_in_detail=0
        self.SOAP_in_what=0
        
        # responce
        self.SOAP_in_neuroresponce=0
        self.SOAP_in_status=0
        self.SOAP_in_results=0
        self.SOAP_in_item=0
        self.SOAP_in_title=0
        self.SOAP_in_dc=0
        self.SOAP_defname_re=0
        
        # universal
        self.SOAP_responce=0
        self.SOAP_query=0
        self.attrib=''
        self.attribs={}
        self.title=''
        self.results={}
        self.item={}
        
        self.step = ''

    def StartElement(self,name,attributes):
        'SAX start element even handler'
        # Instantiate an Element object
        self.element = Element(name.encode(),attributes)
        ## print 'ST', name, attributes
        if name.lower() == 'soap-env:envelope' and not self.SOAP_in_envelope:
            self.SOAP_in_envelope=1
        elif name.lower() == 'soap-env:body' and self.SOAP_in_envelope and not self.SOAP_in_body:
            self.SOAP_in_body=1

        # query
        elif name.lower() == 'neuroquery'  and self.SOAP_in_body and not  self.SOAP_in_neuroquery:
            self.SOAP_in_neuroquery=1
            self.SOAP_query=1
        elif name.lower() == 'querytype' and self.SOAP_in_neuroquery and not self.SOAP_in_querytype:
            self.SOAP_in_querytype=1
        elif name.lower() == 'fulltextquery' and self.SOAP_in_neuroquery and not self.SOAP_in_searchabletext:
            self.SOAP_in_searchabletext=1
        elif name.lower() == 'searchlogic' and self.SOAP_in_neuroquery:
            self.SOAP_in_searchlogic=1
        elif name.lower() == 'datebeg' and self.SOAP_in_neuroquery:
            self.SOAP_in_datebeg=1
        elif name.lower() == 'dateend' and self.SOAP_in_neuroquery:
            self.SOAP_in_dateend=1
        elif name.lower() == 'search' and self.SOAP_in_neuroquery and not self.SOAP_in_search:
            self.SOAP_in_search=1
        elif name.lower() == 'item' and self.SOAP_in_search and not self.SOAP_in_item:
            self.SOAP_in_item=1
        elif name.lower() == 'pname' and self.SOAP_in_item and not self.SOAP_in_pname:
            self.SOAP_in_pname=1
            self.SOAP_defname=1
        elif name.lower() == 'pvalue' and self.SOAP_in_search and not self.SOAP_in_pvalue and self.SOAP_defname:
            self.SOAP_in_pvalue=1

        # responce error
        elif name.lower() == 'fault'  and self.SOAP_in_body and not  self.SOAP_in_fault:
            self.SOAP_in_fault=1
        elif name.lower() == 'faultactor'  and self.SOAP_in_fault and not  self.SOAP_in_faultactor:
            self.SOAP_in_faultactor=1
        elif name.lower() == 'faultstring'  and self.SOAP_in_fault and not  self.SOAP_in_faultstring:
            self.SOAP_in_faultstring=1
        elif name.lower() == 'detail'  and self.SOAP_in_fault and not  self.SOAP_in_detail:
            self.SOAP_in_detail=1
        elif name.lower() == 'what'  and self.SOAP_in_detail and not  self.SOAP_in_what:
            self.SOAP_in_what=1

        # responce
        elif name.lower() == 'neuroqueryresponse'  and self.SOAP_in_body and not  self.SOAP_in_neuroresponce:
            self.SOAP_in_neuroresponce=1
            self.SOAP_responce=1
        elif name.lower() == 'status'  and self.SOAP_in_neuroresponce and not  self.SOAP_in_status:
            self.SOAP_in_status=1
        elif name.lower() == 'results'  and self.SOAP_in_neuroresponce and not  self.SOAP_in_results:
            self.SOAP_in_results=1
        elif name.lower() == 'item'  and self.SOAP_in_results and not  self.SOAP_in_item:
            self.SOAP_in_item=1
            self.step += '<blockquote>'
            self.step += name
        elif name.lower() == 'title'  and self.SOAP_in_item and not  self.SOAP_in_title:
            self.SOAP_in_title=1
            self.step += '<blockquote>'
            self.step += name
        elif name.lower()[:3] == 'dc:'  and self.SOAP_in_item and not self.SOAP_in_dc:
            self.attrib = name[3:]
            self.SOAP_defname_re=1
            self.step += '<blockquote>'
            self.step += name
            self.SOAP_in_dc=1


    def EndElement(self,name):
        'SAX end element event handler'
        ## print 'ED', name
        if name.lower() == 'soap-env:envelope' and self.SOAP_in_envelope:
            self.SOAP_in_envelope=0
        elif name.lower() == 'soap-env:body' and self.SOAP_in_body:
            self.SOAP_in_body=0

        # query
        elif name.lower() == 'neuroquery' and  self.SOAP_in_neuroquery:
            self.SOAP_in_neuroquery=0
        elif name.lower() == 'querytype' and self.SOAP_in_querytype:
            self.SOAP_in_querytype=0
        elif name.lower() == 'fulltextquery' and self.SOAP_in_searchabletext:
            self.SOAP_in_searchabletext=0
        elif name.lower() == 'searchlogic' and self.SOAP_in_searchlogic:
            self.SOAP_in_searchlogic=0
        elif name.lower() == 'datebeg' and self.SOAP_in_datebeg:
            self.SOAP_in_datebeg=0
        elif name.lower() == 'dateend' and self.SOAP_in_dateend:
            self.SOAP_in_dateend=0
        elif name.lower() == 'search' and self.SOAP_in_search:
            self.SOAP_in_search=0
        elif name.lower() == 'item' and  self.SOAP_in_neuroquery and self.SOAP_in_item:
            self.SOAP_in_item=0
            self.SOAP_defname=0
        elif name.lower() == 'pname' and self.SOAP_in_pname:
            self.SOAP_in_pname=0
        elif name.lower() == 'pvalue' and self.SOAP_in_pvalue:
            self.SOAP_in_pvalue=0

        # responce error
        elif name.lower() == 'fault' and self.SOAP_in_fault:
            self.SOAP_in_fault=0
        elif name.lower() == 'faultactor' and self.SOAP_in_faultactor:
            self.SOAP_in_faultactor=0
        elif name.lower() == 'faultstring' and self.SOAP_in_faultstring:
            self.SOAP_in_faultstring=0
        elif name.lower() == 'detail' and SOAP_in_detail:
            self.SOAP_in_detail=0
        elif name.lower() == 'what' and SOAP_in_what:
            self.SOAP_in_what=0

        # responce
        elif name.lower() == 'neuroqueryresponce' and  self.SOAP_in_neuroresponce:
            self.SOAP_in_neuroresponce=0
        elif name.lower() == 'status'  and self.SOAP_in_status:
            self.SOAP_in_status=0
        elif name.lower() == 'results'  and self.SOAP_in_results:
            self.SOAP_in_results=0
        elif name.lower() == 'item' and  self.SOAP_in_neuroresponce and self.SOAP_in_item:
            self.SOAP_in_item=0
            self.results[self.title]=self.item
            self.item={}
            self.step += '<br>'
            self.step += name
            self.step += '</blockquote>'
        elif name.lower() == 'title'  and self.SOAP_in_title:
            self.SOAP_in_title=0
            self.step += '<br>'
            self.step += name
            self.step += '</blockquote>'
        elif self.SOAP_in_dc:
            self.SOAP_defname_re=0
            self.SOAP_in_dc=0
            self.step += '<br>'
            self.step += name
            self.step += '</blockquote>'

    def makeDateTime(self,data):
        return DateTime(data)

    def makeList(self,data):
        return string.split(data,';')

    def CharacterData(self,data):
        'SAX character data event handler'
        if string.strip(data):
            data = data.encode()
            self.element.cdata += data

            # query
            if self.SOAP_in_querytype:
                self.attribs['QueryType']=self.makeList(data)
            elif self.SOAP_in_searchabletext:
                self.attribs['SearchableText']=data
            elif self.SOAP_in_datebeg:
                self.attribs['datebeg']=self.makeDateTime(data)
            elif self.SOAP_in_dateend:
                self.attribs['dateend']=self.makeDateTime(data)
            elif self.SOAP_in_pname:
                self.attrib=data
            elif self.SOAP_in_pvalue and self.SOAP_defname:
                if self.attrib.lower()[:2] == 'dc:':
                    self.attribs[self.attrib]=data
                else:
                    pass

            #responce error
            elif self.SOAP_in_fault:
                self.attribs['error:fault']=data
            elif self.SOAP_in_faultactor:
                self.attribs['error:faultactor']=data
            elif self.SOAP_in_faultcode:
                self.attribs['error:faultcode']=data
            elif self.SOAP_in_faultstring:
                self.attribs['error:faultstring']=data
            elif self.SOAP_in_what:
                self.attribs['error:what']=data
                
            # responce
            elif self.SOAP_in_status:
                self.attribs['res:status']=data
            elif self.SOAP_in_title:
                self.title=data
            elif self.SOAP_in_dc and self.SOAP_defname_re:
                self.item[self.attrib]=data

        return

    def Parse(self,body):
        # Create a SAX parser
        Parser = expat.ParserCreate()

        # SAX event handlers
        Parser.StartElementHandler = self.StartElement
        Parser.EndElementHandler = self.EndElement
        Parser.CharacterDataHandler = self.CharacterData

        # Parse the XML File
        ParserStatus = Parser.Parse(body)

        if self.SOAP_query:
            # query
            return self.attribs

        elif self.SOAP_responce:
            # responce
            return self.results

        else:
            # responce error
            raise Exception, 'RESPONCE<br>' + str(self.results) + '<br> <textarea rows="40">' + str(body) +'</textarea><br>' + self.step
            return None
    
class ParseSoapMessage:
    def ParseSoapMessage(self,body):
        parser = qd_soap()
        ret_dict = parser.Parse(body)
        return ret_dict
