#
# -*- coding: utf-8 -*-

''' TBD '''


############################################################################################################
#
#   IMPORTS
#
#===========================================================================================================
from biocase import __version__
from biocase.tools.htmltools import escapeHtml
from biocase.wrapper.operations import recordStatus
from biocase.querytool.querygenerator import QueryGenerator
from xml.etree import ElementTree
from biocase.tools.xmlutils              import prettyprint, cleanupNamespaces
import urllib, StringIO, logging

import biocase.configuration
cfg = biocase.configuration.Cfg()

log = logging.getLogger("lib.querydispatcher")
log.debug("QT testing")

NS_BioCASe=QueryGenerator.NS_BioCASe

def namespaceDefs(node):
    n = node.nsDefs()
    while n:
        yield n
        n = n.next

############################################################################################################
#
#   ERROR CLASSES
#
#===========================================================================================================
class WrapperError(Exception):
    def __init__(self, message):
        self.msg=message
        

############################################################################################################
#
#   CLASSES
#
#===========================================================================================================
class QueryDispatcher:
    '''A class to send queries to wrappers and do simple work with protocol responses.
    Supports DiGIR and BioCASe'''
    
    # ------------------------------------------------------------------------------------
    def __init__(self):
        self.query          = None # the last query XML protocol string used
        self.response       = None # the response XML protocol string
        self.content        = None # the content of the response without the protocol envelope
        self.contentET      = None # ElementTree node of the above content
        self.diagnostics    = []   #  list of diagnostic messages of the response as tuples: (severity, code, message)
        self.recStatus      = recordStatus()
        
    # ------------------------------------------------------------------------------------
    def sendQuery(self, wrapper_url, protocolString, security_role=None):
        '''Sends a query to the wrapper and returns a record status object or raises a WrapperError exception if query failed.'''
        self.query = protocolString
        log.info("SEND QUERY TO %s"%wrapper_url)
        log.info("SECURITY ROLE=%s"%str(security_role))
        
        #We query with the result XML to the wrapper:
        params = {'query': protocolString.encode('utf-8')}
        if security_role is not None:
            params['role'] = security_role
        params = urllib.urlencode(params)
        #
        # risky. use error handling
        try:
            f = urllib.urlopen(wrapper_url, params)
            self.response = f.read()
            log.info("FULL WRAPPER RESPONSE %s"%unicode(self.response, 'utf-8'))
        except:
            msg="HTTP ERROR: WRAPPER URL %s COULD NOT BE OPENED" % wrapper_url
            log.error(msg)
            raise WrapperError(msg)
        # parse the xml into ElementTree
        # try ElementTree.XML instead of parse
        try:
            root = ElementTree.parse(StringIO.StringIO(self.response)).getroot()
        except:
            msg="WRAPPER ERROR: WRAPPER URL %s RETURNED NON VALID XML" % wrapper_url
            log.error(msg)
            raise WrapperError(msg)
        #log.info(ElementTree.tostring(root, 'utf-8'))
        log.info("ANALYZING RESPONSE DOC")
        log.info(" DOC ROOT %s"%root.tag)
        # MAIN CONTENT SECTION
        contentET = root.find('{%s}content'%NS_BioCASe)
        if contentET is not None:
            log.info(" Content section found.")
            if len(contentET.getchildren())>0:
                self.contentET = contentET.getchildren()[0]
                self.content = ElementTree.tostring(self.contentET, 'utf-8')
                log.info(" Content xml found.")
        else:
            log.warn(" No content section found!")
        # DIAGNOSTICS
        log.debug("Looking for diagnostics...")
        diagPath='{%s}diagnostics/{%s}diagnostic'%(NS_BioCASe,NS_BioCASe)
        if root.find(diagPath) is None:
            log.debug(" Cant find any diagnostics")
        else:
            for d in root.find(diagPath):
                severity=None
                code=None
                try:
                    severity=d.attrib['severity']
                    code=d.attrib['code']
                except:
                    pass
                self.diagnostics.append((severity,code,d.text))
            log.debug(" %i diagnostics found."%len(self.diagnostics))
        # RECORD STATUS
        log.debug("Looking for content record status...")
        # try to get record status (paging info)
        if contentET is not None:
            self.recStatus.start = int( contentET.attrib['recordStart'])
            log.info("  Record Start = %i"%(self.recStatus.start))
            self.recStatus.count = int( contentET.attrib['recordCount'] )
            log.info("  Record Count = %i"%(self.recStatus.count))
            self.recStatus.drop = int( contentET.attrib['recordDropped'] )
            log.info("  Record Drop = %i"%(self.recStatus.drop))
            try:
                self.recStatus.total = int( contentET.attrib['totalSearchHits'] )
                log.info("  Record Total = %i"%(self.recStatus.total))
            except:
                self.recStatus.total = None                        
                log.info("  Record Total is not existing")
        return self.recStatus
        
    # ------------------------------------------------------------------------------------
    def getScanValues(self):
        result = []
        if self.contentET is not None:
            #log.debug("SCAN CONTENT THERE")
            #log.debug(ElementTree.tostring(self.contentET, 'utf-8'))
            #xpath='*/{%s}value'%NS_BioCASe
            #rs = self.contentET.findall(xpath)
            #log.debug("%s: %i"%(xpath,len(rs)))

            for elem in self.contentET.findall('{%s}value'%NS_BioCASe):
                result.append(elem.text)
        return result

    # ------------------------------------------------------------------------------------
    def getDiagnostics(self):
        '''Return a list of triplet tuples of severity,code,content.'''
        return self.diagnostics

    def getContent(self, pretty=False):
        if pretty:
            cleanupNamespaces(self.contentET)
            return prettyprint(self.contentET)
        else:
            return self.content

