#date sorts studies from orthanc dataset into target study dataset

#takes transferQuery as the list of images that should be available on orthanc


import os
import json
import re
import sys
import datetime
import re

def main(parameterFile):
    fhome=os.path.expanduser('~')
    fsetup=os.path.join(fhome,'.labkey','setup.json')
    with open(fsetup,'r') as f:
        setup=json.load(f)

    sys.path.insert(0,setup['paths']['nixWrapper'])

    import nixWrapper

    nixWrapper.loadLibrary("labkeyInterface")

    import labkeyInterface
    import labkeyDatabaseBrowser
    import labkeyFileBrowser

    fconfig=os.path.join(fhome,'.labkey','network.json')

    net=labkeyInterface.labkeyInterface()
    net.init(fconfig)
    db=labkeyDatabaseBrowser.labkeyDB(net)
    fb=labkeyFileBrowser.labkeyFileBrowser(net)

    with open(parameterFile,'r') as f:
        pars=json.load(f)



    i=0
    #from orthancDatabase/Imaging dataset
    projectOrthanc=pars['Orthanc']['project']
    inputQuery=pars['Orthanc']['queryName']
    inputSchema=pars['Orthanc']['schemaName']
    inputParticipantField=pars['Orthanc']['participantField']

    #to target project dataset
    projectStudy=pars['Database']['project']
    #'iPNUMMretro/Study'
    #for prospective, set
    #projectStudy='IPNUMMprospektiva/Study'
    outputQuery=pars['Database']['queryName']
    outputSchema=pars['Database']['schemaName']
    #select patientId that are contained in the demographics dataset
    transferQuery=pars['Database']['transferQuery']
    dbParticipantField=pars['Database']['participantField']

    missingSchema=pars['Database']['missingImagesSchema']
    missingQuery=pars['Database']['missingImagesQuery']

    #delete all rows from missingQuery (should be rebuilt for every run)
    dsMissing=db.selectRows(projectStudy,missingSchema,missingQuery,[])
    db.modifyRows('delete',projectStudy,missingSchema,missingQuery,dsMissing['rows'])


    #make a list of images from transferQuery
    dsImage=db.selectRows(projectStudy,outputSchema,transferQuery,[])

    for im in dsImage['rows']:


        #for orthanc
        inputIdFilter={'variable':inputParticipantField,\
                'value':im[dbParticipantField],\
                'oper':'eq'}

        #for database
        idFilter={'variable':dbParticipantField,\
                'value':im[dbParticipantField],\
                'oper':'eq'}


        seqNum=im['imagingVisitId']
        seqFilter={'variable':'SequenceNum','value':str(seqNum),'oper':'eq'}

        
        #for speedup one should check if a match was already done in Database/queryName
        #ds1 are the matching outputs in target dataset
        ds1=db.selectRows(projectStudy,outputSchema,outputQuery,\
                [idFilter,seqFilter])

        if len(ds1['rows'])>1:
            #never happens (idFilter and seqFilter)
            print('ERROR: too many matches in {} for {}/{}'.\
                    format(outputQuery,im[dbParticipantField],seqNum))
            continue
        if len(ds1['rows'])>0:
            #just the one match, fine
            print('Entry for {}/{} already resolved'.\
                    format(im[dbParticipantField],seqNum))
            
            entry=ds1['rows'][0]
            try:
                if len(entry['PETWB_orthancId'])>0 and len(entry['CT_orthancId'])>0:
                    continue
            except:
                pass
            print('Debug mode for missing cases')

        #have to convert from datetime to %Y%m%d format
        #dateFilter={'variable':'imageDate','value':im['imageDate'],'oper':'eq'}

        dsOrthanc=db.selectRows(projectOrthanc,inputSchema,inputQuery,[inputIdFilter])

        #what if dsOrthanc['rows'] is empty?
        #this is part of QA and is reported in missingImages Schema/Query
    
        #convert dates
        sDates={r['orthancSeries']:datetime.datetime.strptime(r['studyDate'],'%Y/%m/%d %H:%M:%S') 
                for r in dsOrthanc['rows']}

        sDates={x:sDates[x].strftime('%Y%m%d') for x in sDates}

        #unique dates (for date mismatch)
        dates=list(set(sDates.values()))
        
        #select dates
        sDatesMatch={x:sDates[x] for x in sDates if sDates[x]==im['imageDate']}
        
        #select 
        rowsMatch=[r for r in dsOrthanc['rows'] if r['orthancSeries'] in list(sDatesMatch.keys())]

        #select CT matches
        rowsCT=[r for r in rowsMatch if r['seriesDescription'].find('CT WB')==0]
        #should not include fov
        rowsCT=[r for r in rowsCT if r['seriesDescription'].find('fov')<0]
        print('entry[{}/{}] rowsCT : {}'.format(im[dbParticipantField],seqNum,rowsCT))
        
        #should be one and one only
        rowsPET=[r for r in rowsMatch if r['seriesDescription']=='PET WB']
        print('entry[{}/{}] rowsPET: {}'.format(im[dbParticipantField],seqNum,rowsPET))
        
        #deal with erroneous outcomes (ie- no CT, more then 1 CT, no PET, more than 1 PET)
        if len(rowsPET)!=1 or len(rowsCT)!=1:
            mode='insert'
            #copy values en mass
            vals=[dbParticipantField,'imagingVisitId','imageDate']
            orow={v:im[v] for v in vals}
            orow['imageDateMismatch']=','.join(dates)
            
            #generate description of failure
            failDesc=''
            if len(rowsPET)==0:
                failDesc+='[MISSSING PET]'
            if len(rowsPET)>1:
                failDesc+='[MULTIPLE PET]'
            if len(rowsCT)==0:
                failDesc+='[MISSSING CT]'
            if len(rowsCT)>1:
                failDesc+='[MULTIPLE CT]'
            orow['failureDescription']=failDesc

            #generate fail entries
            db.modifyRows(mode,projectStudy,missingSchema,\
                    missingQuery,[orow])
            #don't break, but fill only for singular outcomes
         

        #figure out which row in output study to update
        filters=[]
        print('Participant {} Sequence number {}'.\
               format(im[dbParticipantField],str(seqNum)))
        #refresh the matching study list (after CT we have found PET)
        ds1=db.selectRows(projectStudy,outputSchema,outputQuery,\
                [idFilter,seqFilter])

        mode='update'
        outRow={}
        if len(ds1['rows'])==0:
            mode='insert'
        
            outRow[dbParticipantField]=im[dbParticipantField]
            outRow['SequenceNum']=seqNum
        
        else:
            #never happens if we check for sd1 before matches are found
            outRow=ds1['rows'][0]
        
        if len(rowsPET)==1:    
            outRow['PETWB_orthancId']=rowsPET[0]['orthancSeries']
            outRow['studyDate']=rowsPET[0]['studyDate']
        if len(rowsCT)==1:
            outRow['CT_orthancId']=rowsCT[0]['orthancSeries']
            outRow['studyDate']=rowsCT[0]['studyDate']

        outRow['imagingVisitId']=im['imagingVisitId']
        outRow['visitCode']='VISIT_'+str(im['imagingVisitId'])
        outRow['patientCode']=re.sub('/','_',im[dbParticipantField])

        modifyStatus=db.modifyRows(mode,projectStudy,outputSchema,\
                outputQuery,[outRow])
        print('{}'.format(modifyStatus))
        
    print("Done")

if __name__=='__main__':
    main(sys.argv[1])