#!/usr/bin/env python
#                                                            _
# PACS ToolKit findscu (and possible movescu) Wrapper
#
# (c) 2016-2019 Fetal-Neonatal Neuroimaging & Developmental Science Center
#                   Boston Children's Hospital
#
#              http://childrenshospital.org/FNNDSC/
#                        dev@babyMRI.org
#

import sys, os
sys.path.append(os.path.join(os.path.dirname(__file__), '../'))


from    argparse            import RawTextHelpFormatter
from    argparse            import ArgumentParser
from    terminaltables      import SingleTable
from    pfmisc._colors      import Colors
import  json
import  pypx
import  socket
import  pudb

str_defIP   = [l for l in (
                [ip for ip in socket.gethostbyname_ex(socket.gethostname())[2] 
                if not ip.startswith("127.")][:1], 
                    [[(s.connect(('8.8.8.8', 53)), s.getsockname()[0], s.close()) 
                for s in [socket.socket(socket.AF_INET, socket.SOCK_DGRAM)]][0][1]]) if l][0][0]

str_name    = "px-find"
str_version = "1.0.0.1"
str_desc    = Colors.CYAN + """
                    
              __ _           _ 
             / _(_)         | |
 _ __ __  __| |_ _ _ __   __| |
| '_ \\\\ \\/ /|  _| | '_ \\ / _` |
| |_) |>  < | | | | | | | (_| |
| .__//_/\\_\\|_| |_|_| |_|\\__,_|
| |                            
|_|                            

                        PACS ToolKit Wrapper
                            Query / Find

                       -- version """ + \
             Colors.YELLOW + str_version + Colors.CYAN + """ --                          

    ``px-find`` is a module / script that provides functionality for 
    performing a PACS Query operation. 

    ``px-find`` is tested against both Orthanc as well as some 
    commercial PACS offerings.

""" + Colors.NO_COLOUR

def synopsis(ab_shortOnly = False):
    scriptName = os.path.basename(sys.argv[0])
    shortSynopsis =  Colors.YELLOW + '''
    NAME

	    %s

        - PACS find (query)

    SYNOPSIS

            _script mode_:
            px-find                                                 \\
                [--aet <AETitle>]                                   \\
                [--aec <CalledAETitle>]                             \\
                [--serverIP <PACSserverIP>]                         \\
                [--serverPort <PACSserverPort>]                     \\
                [--findscu <findscuAbsolutePath>]                   \\
                [--movescu <movescuAbsolutePath>]                   \\
                [--PatientID <MRN>]                                 \\
                [--PatientName <ExactPatientName>]                  \\
                [--PatientSex <M_or_F>]                             \\
                [--StudyDate <YYYY/MM/DD>]                          \\
                [--ModalitiesInStudy <Modalities>]                  \\
                [--Modality <ModalityToQuery>]                      \\
                [--PerformedStationAETitle <StationTitle>]          \\
                [--StudyDescription <studyDescription>]             \\
                [--SeriesDescription <seriesDescription>]           \\
                [--StudyInstanceUID <studyInstanceUID>]             \\
                [--SeriesInstanceUID <seriesInstanceUID>]           \\
                [--retrieve [--move]]                               \\
                [--reportTags <JSONDesc>]                           \\
                [--colorize light|dark]                             \\
                [--printReport tabular|rawText|json]                \\
                [--waitForUserTerminate]                            \\
                [-x|--desc]                                         \\
                [-y|--synopsis]                                     \\
                [--version]                                         \\
                [--debugToDir <dir>]                                \\
                [--verbosity <level>]

    ''' % scriptName + Colors.NO_COLOUR 

    description = Colors.LIGHT_GREEN + '''

        [--aet <AETitle>]
        The AETitle of *this* entity.

        [--aec <CalledAETitle>]                             
        The called AETitle of *this* entity. Needed for some PACS systems.

        [--serverIP <PACSserverIP>]
        The IP of the PACS server.

        [--serverPort <PACSserverPort>]                     
        The port associated with the PACS server.

        [--executable <findscuAbsolutePath>]                
        The absolute location of the 'findscu' executable.
        
        [--PatientID <MRN>]
        The patient ID on which to Query.

        [--PatientName <ExactPatientName>]
        The patient name on which to Query.

        [--PatientSex <M_or_F>]                             
        The patient sex (largely irrelevant since open ended searches are
        not supported by most PACS servers).
        
        [--StudyDate <YYYY/MM/DD>]                          
        Filter results by <studyDate>.
        
        [--ModalitiesInStudy <Modalities>]   
        Filter by modalities in study.

        [--Modality <Modality>]   
        The modality to filter.

        [--PerformedStationAETitle <StationTitle>]          
        Filter by station ID.

        [--StudyDescription <studyDescription>]             
        Filter by study description.

        [--SeriesDescription <seriesDescription>]           
        Filter by series description.

        [--StudyInstanceUID <studyInstanceUID>]             
        Filter by study instance UID.

        [--SeriesInstanceUID <seriesInstanceUID>]           
        Filter by series instance UID.

        [--retrieve]
        If set, perform a DICOM movescu on the set of filtered 
        SeriesInstanceUIDs using internal calls.

        [--move]
        If set and called with [--retrieve], perform a DICOM movescu on the 
        set of filtered SeriesInstanceUIDs using the pypx/move module.

        [--reportTags <JSONdesc>]
        If specified, print only the JSON specified result tags from either the
        STUDY or SERIES level.

        [--colorize 'light'|'dark']
        An optional directive to colorize the report output, either for 'light'
        or 'dark' consoles.

        [--printReport tabular|rawText|json]               
        If specified, pretty print a report in a variety of formats.

        [--waitForUserTerminate]
        If specified, wait at program conclusion for explicit user termination.
        This is useful in dockerized runs since PACS data might still be 
        in flight when the program ends, and terminating the program then
        will result in non reception of outstanding data.                           

        [-x|--desc]                                     
        Provide an overview help page.

        [-y|--synopsis]
        Provide a synopsis help summary.

        [--version]
        Print internal version number and exit.

        [--debugToDir <dir>]
        A directory to contain various debugging output -- these are typically
        JSON object strings capturing internal state. If empty string (default)
        then no debugging outputs are captured/generated. If specified, then
        ``pfcon`` will check for dir existence and attempt to create if
        needed.

        [-v|--verbosity <level>]
        Set the verbosity level. "0" typically means no/minimal output. Allows for
        more fine tuned output control as opposed to '--quiet' that effectively
        silences everything.

    EXAMPLES

        px-find                                                     \\
            --aec CHRIS                                             \\
            --aet FNNDSC-CHRISDEV                                   \\
            --serverIP 134.174.12.21                                \\
            --serverPort 104                                        \\
            --PatientID 4777764                                     \\
            --colorize dark                                         \\
            --reportTags                                            \\
            '{
                "header": 
                {
                    "study" : [
                            "PatientName",
                            "ScanDate",
                            "AccessionNumber",
                            "PatientID",
                            "PatientSex",
                            "PatientAge",
                            "PerformedStationAETitle",
                            "StudyDescription"
                            ]
                },
                "body": 
                {
                    "series" : [ 
                            "SeriesDescription"
                            ]
                }
            }'

        px-find                                                     \\
            --aec CHIPS                                             \\
            --aec ORTHANC                                           \\
            --serverIP localhost                                    \\
            --serverPort 4242                                       \\
            --PatientID LILLA-9731                                  \\
            --colorize dark					    \\
            --reportTags                                            \\
            '{
                "header": 
                {
                    "study" : [
                            "PatientName",
                            "ScanDate",
                            "AccessionNumber",
                            "PatientID",
                            "PatientSex",
                            "PatientAge",
                            "PerformedStationAETitle",
                            "StudyDescription"
                            ]
                },
                "body": 
                {
                    "series" : [ 
                            "SeriesDescription"
                            ]
                }
            }'
    ''' + Colors.LIGHT_PURPLE + '''

    DOCKERIZED EXAMPLES

        docker run  --rm -ti                                            \\
            -p 10402:10402                                              \\
            -v /tmp:/dicom                                              \\
            fnndsc/pypx                                                 \\
            --px-find                                                   \\
            --aet CHIPS                                                 \\
            --aec ORTHANC                                               \\
            --serverIP  10.72.76.155                                    \\
            --serverPort 4242                                           \\
            --PatientID LILLA-9731                                      \\
            --colorize dark                                             \\
            --reportTags                                                \\
            '{
                "header": 
                {
                    "study" : [
                            "PatientName",
                            "ScanDate",
                            "AccessionNumber",
                            "PatientID",
                            "PatientSex",
                            "PatientAge",
                            "PerformedStationAETitle",
                            "StudyDescription"
                            ]
                },
                "body": 
                {
                    "series" : [ 
                            "SeriesDescription"
                            ]
                }
            }'

        docker run  --rm -ti                                            \\
            -p 10402:10402                                              \\
            -v /tmp:/dicom                                              \\
            fnndsc/pypx                                                 \\
            --px-find                                                   \\
            --aec CHRIS                                                 \\
            --aet FNNDSC-CHRISDEV                                       \\
            --serverIP 134.174.12.21                                    \\
            --serverPort 104                                            \\
            --PatientID 4777764                                         \\
            --colorize dark                                             \\
            --reportTags                                                \\
            '{
                "header": 
                {
                    "study" : [
                            "PatientName",
                            "StudyDate",
                            "AccessionNumber",
                            "PatientID",
                            "PatientSex",
                            "PatientAge",
                            "PerformedStationAETitle",
                            "StudyDescription"
                            ]
                },
                "body": 
                {
                    "series" : [ 
                            "SeriesDescription"
                            ]
                }
            }'

    ''' + Colors.NO_COLOUR

    if ab_shortOnly:
        return shortSynopsis
    else:
        return shortSynopsis + description


parser = ArgumentParser(
            description         = str_desc,
            formatter_class     = RawTextHelpFormatter
        )

# PACS access settings
parser.add_argument(
    '--aet', 
    action  = 'store', 
    dest    = 'aet', 
    type    = str, 
    default = 'CHRIS-ULTRON-AET', 
    help    = 'aet')
parser.add_argument(
    '--aec', 
    action  = 'store', 
    dest    = 'aec', 
    type    = str, 
    default = 'CHRIS-ULTRON-AEC', 
    help    = 'aec')
parser.add_argument(
    '--serverIP', 
    action  = 'store', 
    dest    = 'serverIP', 
    type    = str,
    default = '192.168.1.110', 
    help    = 'PACS server IP')
parser.add_argument(
    '--serverPort', 
    action  = 'store', 
    dest    = 'serverPort', 
    type    = str,
    default = '4242', 
    help    = 'PACS server port')
parser.add_argument(
    '--findscu', 
    action  = 'store', 
    dest    = 'findscu', 
    type    = str,
    default = '/usr/bin/findscu', 
    help    = '"findscu" executable absolute location')
parser.add_argument(
    '--movescu', 
    action  = 'store', 
    dest    = 'movescu', 
    type    = str,
    default = '/usr/bin/movescu', 
    help    = '"movescu" executable absolute location')



# Query settings
parser.add_argument(
    '--PatientID', 
    action  = 'store', 
    dest    = 'PatientID', 
    type    = str, 
    default = '', 
    help    = 'Patient ID')
parser.add_argument(
    '--PatientName', 
    action  = 'store', 
    dest    = 'PatientName', 
    type    = str, 
    default = '', 
    help    = 'Patient name')
parser.add_argument(
    '--PatientSex', 
    action  = 'store',
    dest    = 'PatientSex', 
    type    = str, 
    default = '', 
    help    ='Patient sex')
parser.add_argument(
    '--StudyDate', 
    action  = 'store', 
    dest    = 'StudyDate', 
    type    = str,
    default = '', 
    help    = 'Study date (YYYY/MM/DD)')
parser.add_argument(
    '--ModalitiesInStudy', 
    action  = 'store', 
    dest    = 'ModalitiesInStudy',
    type    = str, 
    default = '', 
    help    = 'Modalities in study')
parser.add_argument(
    '--Modality', 
    action  = 'store', 
    dest    = 'Modality',
    type    = str, 
    default = '', 
    help    = 'Study Modality')
parser.add_argument(
    '--PerformedStationAETitle', 
    action  = 'store',
    dest    = 'PerformedStationAETitle', 
    type    = str, 
    default = '', 
    help    = 'Performed station aet')
parser.add_argument(
    '--StudyDescription', 
    action  = 'store',
    dest    = 'StudyDescription', 
    type    = str, 
    default = '', 
    help    = 'Study description')
parser.add_argument(
    '--SeriesDescription', 
    action  = 'store', 
    dest    = 'SeriesDescription', 
    type    = str,
    default = '', 
    help    = 'Series Description')
parser.add_argument(
    '--SeriesInstanceUID', 
    action  = 'store', 
    dest    = 'SeriesInstanceUID', 
    type    = str,
    default = '', 
    help    = 'Series Instance UID')
parser.add_argument(
    '--StudyInstanceUID', 
    action  = 'store', 
    dest    = 'StudyInstanceUID', 
    type    = str,
    default = '', 
    help    = 'Study Instance UID')

# Retrieve settings
parser.add_argument(
    '--retrieve', 
    action  = 'store_true', 
    dest    = 'retrieve',
    default = False, 
    help    = 'If specified, initiate a PACS pull on the set of SeriesUIDs using internal methods')
parser.add_argument(
    '--move', 
    action  = 'store_true', 
    dest    = 'move',
    default = False, 
    help    = 'If specified with --retrieve, call initiate a PACS pull on the set of SeriesUIDs using pypx/move')

# Behavioural settings
parser.add_argument(
    '--colorize', 
    action  = 'store', 
    dest    = 'colorize', 
    type    = str,
    default = '', 
    help    = 'Colorize report output')
parser.add_argument(
    '--printReport', 
    action  = 'store', 
    dest    = 'printReport', 
    type    = str,
    default = '', 
    help    = 'The returned report component to print')
parser.add_argument(
    '--reportTags', 
    action  = 'store',
    dest    = 'reportTags', 
    type    = str, 
    default = '', 
    help    = 'The tag results to print at the STUDY or SERIES level')
parser.add_argument(
    "-v", "--verbosity",
    help    = "verbosity level for app",
    dest    = 'verbosity',
    type    = int,
    default = 1)
parser.add_argument(
    "-x", "--desc",
    help    = "long synopsis",
    dest    = 'desc',
    action  = 'store_true',
    default = False
)
parser.add_argument(
    "-y", "--synopsis",
    help    = "short synopsis",
    dest    = 'synopsis',
    action  = 'store_true',
    default = False
) 
parser.add_argument(
    '--version',
    help    = 'if specified, print version number',
    dest    = 'b_version',
    action  = 'store_true',
    default = False
)
parser.add_argument(
    '--waitForUserTerminate',
    help    = 'if specified, wait for user termination',
    dest    = 'b_waitForUserTerminate',
    action  = 'store_true',
    default = False
)

args        = parser.parse_args()

if args.desc or args.synopsis:
    print(str_desc)
    if args.desc:
        str_help     = synopsis(False)
    if args.synopsis:
        str_help     = synopsis(True)
    print(str_help)
    sys.exit(1)

if args.b_version:
    print("Version: %s" % str_version)
    sys.exit(1)


# pudb.set_trace()
output = pypx.find(vars(args))

if args.b_waitForUserTerminate:
    l_infoWindow =[
        [Colors.CYAN                                            + 
        "End of program reached."                               + 
        Colors.NO_COLOUR],
        [""],
        [Colors.PURPLE                                          + 
        "If a PACS move/pull/retrieve was requested, not all"   +
        Colors.NO_COLOUR],
        [Colors.PURPLE                                          + 
        "image data might have been received since the PACS"    +
        Colors.NO_COLOUR],
        [Colors.PURPLE                                          + 
        "operates in an asynchronous manner."                   +
        Colors.NO_COLOUR],
        [""],
        [Colors.PURPLE                                          + 
        "If you are running this process containerized, on"     +
        Colors.NO_COLOUR],
        [Colors.PURPLE                                          + 
        "exit the container will close and no additional data"  +
        Colors.NO_COLOUR],
        [Colors.PURPLE                                          + 
        "will be received."                                     +
        Colors.NO_COLOUR],
        [""],
        [Colors.BLINK_RED           + 
        "ONLY EXIT IF YOU ARE SURE YOU HAVE RECEIVED ALL IMAGES!" +
        Colors.NO_COLOUR],
    ]
    tb_infoWindow = SingleTable(l_infoWindow)
    tb_infoWindow.inner_heading_row_border  = False
    print(tb_infoWindow.table)
    input("\nHit ENTER now to exit.")
