import json
import orthanc
import re
# Example items to search and sort on, PatientMainDicomTags or MainDicomTags

#"PatientMainDicomTags": {
# "PatientBirthDate": "YYYYMMDD", 
# "PatientSex": "M", 
# "PatientID": "DEV0000001", 
# "PatientName": "Patient^Test"
#}, 
#"Series": [
# "e46bfef4-2b166666-468cc957-4b942aa8-3a5c6ef8"
#], 
#"ParentPatient": "fa21ff2d-33e9b60a-daedf6a0-64d018da-682fd0a4", 
#"MainDicomTags": {
# "AccessionNumber": "DEVACC00000006", 
# "StudyDate": "YYYYMMDD", 
# "StudyDescription": "StudyDescription", 
# "InstitutionName": "InstitutionName", 
# "ReferringPhysicianName": "Last^First^Middle^Suffix", 
# "RequestingPhysician": "Last^First^Middle^Suffix", 
# "StudyTime": "090425", 
# "StudyID": "DEVACC00000006", 
# "StudyInstanceUID": "2.16.840.1.114151.1052214956401694179114379854103077382390190829"
#}

# Example CURL:
# curl http://localhost:8042/studies/page -d '{"Level":"Study","Query":{"PatientID": "DEV0000001"},"Expand":true,"Metadata":{}, "offset":2,"limit":2,"sortbytaggroup":"MainDicomTags","sortparam":"AccessionNumber","reverse":0}'
# Takes the standard tools find format, with added "Metadata":{}, "offset":2,"limit":2,"sortbytaggroup":"MainDicomTags","sortparam":"AccessionNumber","reverse":0 as additional params
# offset and limit are for paging, offset from the beginning, and number of results
# sortbytaggroup is PatientMainDicomTags or MainDicomTags
# sortparam is the tag within the group to sort on.
# reverse is the order for the sort, 0 or 1


# Get the path in the REST API to the given resource that was returned
# by a call to "/studies/page" as the new REST callback
#only accept queries on the Study, although others could be added.

def GetPath(resource):
    if resource['Type'] == 'Study':
        return '/studies/%s' % resource['ID']
    else:
        raise Exception('Can only Query Studies')
        
# main function
def FindWithMetadata(output, uri, **request):
    # The "/tools/find" route expects a POST method
    if request['method'] != 'POST':
        output.SendMethodNotAllowed('POST')
    else:
        # Parse the query provided by the user, and backup the "Expand" field
        query = json.loads(request['body'])

        if 'Expand' in query:
            originalExpand = query['Expand']
        else:
            originalExpand = False
        offset = 0
        if 'offset' in query:
            offset = query['offset']
        limit = 0
        if 'limit' in query:
            limit = query['limit']
        # The globals are used in the GetSortParam function for the taggroup, sortparam and sortorder
        global param
        param = query['sortparam']
        global taggroup
        taggroup = query['sortbytaggroup']
        global reverse
        reverse = query['reverse']
        # Call the core "/tools/find" route
        query['Expand'] = True
        answers = orthanc.RestApiPost('/tools/find', json.dumps(query))

        # Loop over the matching resources
        filteredAnswers = []
        for answer in json.loads(answers):
            try:
                # Read the metadata that is associated with the resource
                metadata = json.loads(orthanc.RestApiGet('%s/metadata?expand' % GetPath(answer)))

                # Check whether the metadata matches the regular expressions
                # that were provided in the "Metadata" field of the user request
                isMetadataMatch = True
                if 'Metadata' in query:
                    for (name, pattern) in query['Metadata'].items():
                        if name in metadata:
                            value = metadata[name]
                        else:
                            value = ''

                        if re.match(pattern, value) == None:
                            isMetadataMatch = False
                            break

                # If all the metadata matches the provided regular
                # expressions, add the resource to the filtered answers
                if isMetadataMatch:
                    if originalExpand:
                        answer['Metadata'] = metadata
                        filteredAnswers.append(answer)
                    else:
                        filteredAnswers.append(answer['ID'])
            except:
                # The resource was deleted since the call to "/tools/find"
                pass
                
		# Sort the studies according to the "StudyDate" DICOM tag
        studies = sorted(filteredAnswers, key = GetSortParam, reverse=reverse)
        count = len(studies)
        # Truncate the list of studies
        if limit == 0:
            studies = studies[offset : ]
        else:
            studies = studies[offset : offset + limit]
            
        # Return the truncated list of studies
        studies.append({"count":count}) 
        studies.append({"limit":limit})
        studies.append({"offset":offset}) 
        # Return the filtered answers in the JSON format
        output.AnswerBuffer(json.dumps(studies, indent = 3), 'application/json')
        
#param is the tag to sortby
#taggroup is the taggroup for the param
#defined as globals in FindWithMetadata    
def GetSortParam(study):
    if param in study[taggroup]:
        return study[taggroup][param]
    else:
        return ''
        
orthanc.RegisterRestCallback('/studies/page', FindWithMetadata)
