# encoding: utf-8
# Copyright 2012 California Institute of Technology. ALL RIGHTS
# RESERVED. U.S. Government Sponsorship acknowledged.

'''Biomarker Json Generator. An Json generator that describes EDRN biomarker mutation statistics using Biomarker webservices.
'''

from Acquisition import aq_inner
from edrn.summarizer import _
from five import grok
from interfaces import IJsonGenerator
from summarizergenerator import ISummarizerGenerator
from rdflib.term import URIRef, Literal
from rdflib.parser import URLInputSource
from rdflib import ConjunctiveGraph
from utils import validateAccessibleURL
from urllib2 import urlopen
from zope import schema
from zope.component import queryUtility
from zExceptions import BadRequest
from plone.i18n.normalizer.interfaces import IIDNormalizer
import jsonlib

COLLABORATIVE_GROUP_BMDB_IDS_TO_NAMES = {
    Literal(u'Breast and Gynecologic'):          Literal(u'Breast and Gynecologic Cancers Research Group'),
    Literal(u'G.I. and Other Associated'):       Literal(u'G.I. and Other Associated Cancers Research Group'),
    Literal(u'Lung and Upper Aerodigestive'):    Literal(u'Lung and Upper Aerodigestive Cancers Research Group'),
    Literal(u'Prostate and Urologic'):           Literal(u'Prostate and Urologic Cancers Research Group'),
}

COLLABORATIVE_GROUP_ECAS_IDS_TO_NAMES = {
    Literal(u'Breast/GYN'):                      Literal(u'Breast and Gynecologic Cancers Research Group'),
    Literal(u'GI and Other Associated'):         Literal(u'G.I. and Other Associated Cancers Research Group'),
    Literal(u'Lung and Upper Aerodigestive'):    Literal(u'Lung and Upper Aerodigestive Cancers Research Group'),
    Literal(u'Prostate and Urologic'):           Literal(u'Prostate and Urologic Cancers Research Group'),
}

INV_COLLABORATIVE_GROUP_BMDB_IDS_TO_NAMES = {v: k for k, v in COLLABORATIVE_GROUP_BMDB_IDS_TO_NAMES.items()}

_typeURI                                 = URIRef('http://www.w3.org/1999/02/22-rdf-syntax-ns#type')
_biomarkerPredicateURI                   = URIRef('http://edrn.nci.nih.gov/rdf/rdfs/bmdb-1.0.0#Biomarker')
_isPanelPredicateURI                     = URIRef('http://edrn.nci.nih.gov/rdf/rdfs/bmdb-1.0.0#IsPanel')
_bmTitlePredicateURI                     = URIRef('http://edrn.nci.nih.gov/rdf/rdfs/bmdb-1.0.0#Title')
_hgncPredicateURI                        = URIRef('http://edrn.nci.nih.gov/rdf/rdfs/bmdb-1.0.0#HgncName')
_groupPredicateURI                       = URIRef('http://edrn.nci.nih.gov/rdf/rdfs/bmdb-1.0.0#AccessGrantedTo')
_typePredicateURI                        = URIRef('http://edrn.nci.nih.gov/rdf/rdfs/bmdb-1.0.0#Type')

_collaborativeGroupDataURI               = URIRef('urn:edrn:CollaborativeGroup')
_collaborativeGroupProURI                = URIRef('http://edrn.nci.nih.gov/rdf/schema.rdf#CollaborativeGroup')

_protocolNameURI                         = URIRef('http://edrn.nci.nih.gov/rdf/schema.rdf#abbreviatedName')
_datasetIdURI                            = URIRef('urn:edrn:DatasetId')

_memberPredicateURI                      = URIRef('http://edrn.nci.nih.gov/xml/rdf/edrn.rdf#member')
_titlePredicateURI                      = URIRef('http://purl.org/dc/terms/title')

MAX_NON_UNIQUE_BIOMARKER_IDS = 100


class ICollaborationSummarizerGenerator(ISummarizerGenerator):
    '''DMCC Committee RDF Generator.'''
    biomarkerURL = schema.TextLine(
        title=_(u'Collaboration Web Service URL'),
        description=_(u'The Uniform Resource Locator to the BMDB SOAP biomarker web service.'),
        required=True,
        constraint=validateAccessibleURL,
    )
    dataURL = schema.TextLine(
        title=_(u'Dataset Web Service URL'),
        description=_(u'The Uniform Resource Locator to the BMDB SOAP dataset web service..'),
        required=True,
        constraint=validateAccessibleURL,
    )
    protocolURL = schema.TextLine(
        title=_(u'Protocol Web Service URL'),
        description=_(u'The Uniform Resource Locator to the BMDB SOAP protocol web service..'),
        required=True,
        constraint=validateAccessibleURL,
    )
    memberURL = schema.TextLine(
        title=_(u'Members Web Service URL'),
        description=_(u'The Uniform Resource Locator to the BMDB SOAP member web service..'),
        required=True,
        constraint=validateAccessibleURL,
    )

class CollaborationJsonGenerator(grok.Adapter):
    '''A Json generator that produces statements about EDRN's biomarker statistics using the BMDB's web service.'''
    def updateCollaborativeGroup(self, objects, groups, allObj, collabFreq):
        print "updateCollab"
        print "groups"
        print groups
        for groupID in groups:
            groupName = ""
            if groupID in COLLABORATIVE_GROUP_ECAS_IDS_TO_NAMES:
                groupName = COLLABORATIVE_GROUP_ECAS_IDS_TO_NAMES[groupID]
            elif groupID in COLLABORATIVE_GROUP_BMDB_IDS_TO_NAMES:
                groupName = COLLABORATIVE_GROUP_BMDB_IDS_TO_NAMES[groupID]
            elif groupID in INV_COLLABORATIVE_GROUP_BMDB_IDS_TO_NAMES:
                groupName = groupID
            else:
                continue
            print "objects:"
            print objects
            for obj in objects:
                #if obj not in allObj:
                #    allObj[obj]=1

                if groupName in collabFreq:
                    collabFreq[groupName] += 1
                else:
                    collabFreq[groupName] = 1
        return collabFreq

    def updateCollaboratorFreq(self, biomarker, predicates, allBiomarkers, collabBmFreq):
        print "updateBm"
        print "accessGroups"
        print predicates[_groupPredicateURI]
        for accessGroup in predicates[_groupPredicateURI]:
            collabGroup = COLLABORATIVE_GROUP_BMDB_IDS_TO_NAMES.get(accessGroup)
            if not collabGroup: continue
            if biomarker not in allBiomarkers:
                if collabGroup in collabBmFreq:
                    collabBmFreq[collabGroup] += 1
                else:
                    collabBmFreq[collabGroup] = 1
        return collabBmFreq

    def _parseRDF(self, graph):
        '''Parse the statements in graph into a mapping {u→{p→o}} where u is a
        resource URI, p is a predicate URI, and o is a list of objects which
        may be literals or URI references.'''
        statements = {}
        for s, p, o in graph:
            if s not in statements:
                statements[s] = {}
            predicates = statements[s]
            if p not in predicates:
                predicates[p] = []
            predicates[p].append(o)
        return statements

    grok.provides(IJsonGenerator)
    grok.context(ICollaborationSummarizerGenerator)
    def generateJson(self):
        collabBmFreq    = {}
        collabPnFreq    = {}
        collabDataFreq  = {}
        collabProtoFreq = {}
        collabMemFreq   = {}

        context = aq_inner(self.context)
        bmDataSource, dataDataSource, protocolDataSource, memberDataSource = context.biomarkerURL, context.dataURL, context.protocolURL, context.memberURL
        if not bmDataSource or not dataDataSource or not protocolDataSource or not memberDataSource:
            raise RDFIngestException(_(u'This generator folder lacks one or both of its RDF source URLs.'))
        normalizerFunction = queryUtility(IIDNormalizer).normalize
        graph = ConjunctiveGraph()
        graph.parse(URLInputSource(bmDataSource))
        statements = self._parseRDF(graph)

        allBiomarkers = {}
        allDatasets   = {}
        allProtocols  = {}
        allMembers    = {}

        for uri, predicates in statements.items():
            try:
                typeURI = predicates[_typeURI][0]
                if typeURI != _biomarkerPredicateURI:
                    continue
                isPanel = bool(int(predicates[_isPanelPredicateURI][0]))
                title = unicode(predicates[_bmTitlePredicateURI][0])
                hgnc = predicates[_hgncPredicateURI][0] if _hgncPredicateURI in predicates else None

                if hgnc is not None:
                    hgnc = hgnc.strip()
                objID = hgnc if hgnc else normalizerFunction(title)
                if URIRef(uri) in allBiomarkers:
                    continue
                #Add frequencies for biomarker associated with biomarker type (Gene, Protein, etc...)
                if isPanel:
                    collabPnFreq = self.updateCollaboratorFreq(objID, predicates, allBiomarkers, collabPnFreq)
                else:
                    collabBmFreq = self.updateCollaboratorFreq(objID, predicates, allBiomarkers, collabBmFreq)
                allBiomarkers[URIRef(uri)] = objID
            except KeyError:
                pass

        graph = ConjunctiveGraph()
        graph.parse(URLInputSource(dataDataSource))
        statements = self._parseRDF(graph)
        for uri, predicates in statements.items():
            if _collaborativeGroupDataURI in predicates:
                collabDataFreq = self.updateCollaborativeGroup(predicates[_datasetIdURI], predicates[_collaborativeGroupDataURI], allDatasets, collabDataFreq)

        graph = ConjunctiveGraph()
        graph.parse(URLInputSource(protocolDataSource))
        statements = self._parseRDF(graph)
        for uri, predicates in statements.items():
            if _collaborativeGroupProURI in predicates:
                collabProtoFreq = self.updateCollaborativeGroup(predicates[_protocolNameURI], predicates[_collaborativeGroupProURI], allProtocols, collabProtoFreq)

        graph = ConjunctiveGraph()
        graph.parse(URLInputSource(memberDataSource))
        statements = self._parseRDF(graph)
        for uri, predicates in statements.items():
            if _memberPredicateURI in predicates:
                collabMemFreq = self.updateCollaborativeGroup(predicates[_memberPredicateURI], predicates[_titlePredicateURI], allMembers, collabMemFreq)
        
        # Coalate all dictionaries into one
        
        jsondata = {"biomarker" : collabBmFreq, "panel" : collabPnFreq, "data" : collabDataFreq, "protocol" : collabProtoFreq, "member" : collabMemFreq}

        # C'est tout.
        return jsonlib.write(jsondata)
