#!/usr/bin/env python3
#
# (c) 2017 Fetal-Neonatal Neuroimaging & Developmental Science Center
#                   Boston Children's Hospital
#
#              http://childrenshospital.org/FNNDSC/
#                        dev@babyMRI.org
#

import sys, os
sys.path.insert(1, os.path.join(os.path.dirname(__file__), '../pfdicom'))

import  pfdicom
from    argparse            import RawTextHelpFormatter
from    argparse            import ArgumentParser
import  pudb

import  pfmisc
from    pfmisc._colors      import Colors
from    pfmisc              import other

str_version = "1.7.2"
str_desc = Colors.CYAN + """

        __    _ _                     
       / _|  | (_)                    
 _ __ | |_ __| |_  ___ ___  _ __ ___  
| '_ \|  _/ _` | |/ __/ _ \| '_ ` _ \ 
| |_) | || (_| | | (_| (_) | | | | | |
| .__/|_| \__,_|_|\___\___/|_| |_| |_|
| |                                   
|_|                                   

  

                        Path-File DICOM Base Processor

        A common module/class for various downstream processing on DICOM
        files. This module reads a DICOM file, parses tags, and provides
        the data for additional processing.

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


""" + Colors.NO_COLOUR

def synopsis(ab_shortOnly = False):
    scriptName = os.path.basename(sys.argv[0])
    print(scriptName)
    shortSynopsis =  """
    NAME

        {scriptName} 

    SYNOPSIS

        {scriptSyn}                                             \\
                    -I|--inputDir <inputDir>                \\
                    [--maxdepth <dirDepth>]                 \\
                    [-i|--inputFile <inputFile>]            \\
                    [-e|--extension <DICOMextension>]       \\
                     -O|--outputDir <outputDir>             \\
                    [-t|--threads <numThreads>]             \\
                    [-x|--man]                              \\
                    [-y|--synopsis]                         \\
                    [-v <verbosity>]                        \\
                    [--version]                             \\
                    [--followLinks]                         \\
                    [--json]

    BRIEF EXAMPLE

        {scriptEx}                                              \\
                        -I /var/www/html                    \\
                        -O /tmp                             \\
                        -o %PatientID-%PatientAge           \\
                        -e .dcm                             \\
                        --printElapsedTime 

    """.format(scriptName = scriptName, scriptSyn = scriptName, scriptEx = scriptName)

    description =  """
    DESCRIPTION

        `{script}` in and of itself provides minimal end value. This module/class
        is intended to be a building block for deeper functionality. Its
        purpose is to probe a given directory filesystem for DICOM files and 
        construct a tree representation (using pftree), and then, for each
        directory provide the means to read in a given DICOM file (using
        pydicom) to provide some minimal tag extraction and output file
        templating.

        Most importantly, derived classes of this parent class can provide
        detailed and powerful methods to process the directories containing
        DICOM files, saving results to an output file tree.

    ARGS

        -I|--inputDir <inputDir>
        Input DICOM directory to examine. By default, the first file in this
        directory is examined for its tag information. There is an implicit
        assumption that each <inputDir> contains a single DICOM series.

        [--maxdepth <dirDepth>]
        The maximum depth to descend relative to the <inputDir>. Note, that
        this counts from zero! Default of '-1' implies transverse the entire
        directory tree.

        [-i|--inputFile <inputFile>]
        An optional <inputFile> specified relative to the <inputDir>. If 
        specified, then do not perform a directory walk, but convert only 
        this file.

        -O|--outputDir <outputDir>
        The directory to contain all output files.

        [--outputLeafDir <outputLeafDirFormat>]
        If specified, will apply the <outputLeafDirFormat> to the output
        directories containing data. This is useful to blanket describe
        final output directories with some descriptive text, such as 
        'anon' or 'preview'. 

        This is a formatting spec, so 

            --outputLeafDir 'preview-%s'

        where %s is the original leaf directory node, will prefix each
        final directory containing output with the text 'preview-' which
        can be useful in describing some features of the output set.

        [-e|--extension <DICOMextension>]
        An optional extension to filter the DICOM files of interest from the 
        <inputDir>. This is merely held by this base class as a member 
        variable. Derived classes can access this for further processing.

        [-t|--threads <numThreads>]
        If specified, break the innermost analysis loop into <numThreads>
        threads. Please note the following caveats:

            * Only thread if you have a high CPU analysis loop. Since
              most of the operations of this module will entail reading
              and writing DICOM files, and since these operations are 
              the bulk of the execution time, adding threading will not
              really help.

            * Threading will change the nature of the innermost looping
              across the problem domain, with the result that *all* of the
              problem data will be read into memory! That means all of 
              DICOMs across all of the subdirs! In non-threading mode,
              only DICOMs from a single directory at a time are read
              and then discarded.

        This flag is less applicable to this base class. It is here
        to provide fall-through compatibility with derived classes.

        [-x|--man]
        Show full help.

        [-y|--synopsis]
        Show brief help.

        [--json]
        If true, dump the final return as JSON formatted string.

        [--followLinks]
        If specified, follow symbolic links.

        [--version]
        If specified, print a version string.

        -v|--verbosity <level>
        Set the app verbosity level. 

            0: No internal output;
            1: Run start / stop output notification;
            2: As with level '1' but with simpleProgress bar in 'pftree';
            3: As with level '2' but with list of input dirs/files in 'pftree';

    STRING PROCESSING ON TAG VALUES

    ``pfidcom`` offers some functions on tag values -- these are typically
    string based. The syntax is:

        %_<functionName>|<arg>_<tagName>

    For example, 

        %_name|patientID_PatientName
        Generate a random name and replace the PatientName with this value.
        Since each DICOM file in a series could conceivably have a different
        generated random name, use the 'PatientID' tag as a seed for the name
        generator. Note that in order to protect the parsing of DICOM tags,
        if used in sub-function arguments, the tag MUST start with a lower 
        case.

        %_md5|7_PatientID
        An md5 hash of the 'PatientID' is determined. Of the resultant string, 
        the first 7 chars are used. This is returned as the value for the 
        PatientID tag.

        %_strmsk|******01_PatientBirthDate
        The 'PatientBirthDate' value is masked such that the first six 
        chars are conserved, but the final two are replaced by '01'. This 
        has the effect of setting the PatientBirthDate to the first day of
        the birth month.

        %_nospc|-_ProtocolName
        The 'ProtocolName' is processed to remove all white space, and using
        a '-' character instead of any whitespace components.
    
    EXAMPLES

    Run on a target tree, creating internal representations of specific file
    and directory strucutres.


        pfdicom         -I /var/www/html                \\
                        -O /tmp                         \\
                        -o %PatientID-%PatientAge       \\
                        -e .dcm                         \\
                        -v 0 --json

        which will output only at script conclusion and will log a JSON 
        formatted string.

    """.format(script=scriptName)

    if ab_shortOnly:
        return shortSynopsis
    else:
        return shortSynopsis + description



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


parser.add_argument("-I", "--inputDir",
                    help    = "input dir",
                    dest    = 'inputDir',
                    default = '')
parser.add_argument("-d", "--maxDepth",
                    help    = "max depth, counting from zero, to descend",
                    dest    = 'maxDepth',
                    default = '-1')
parser.add_argument("-i", "--inputFile",
                    help    = "input file",
                    dest    = 'inputFile',
                    default = '')
parser.add_argument("-O", "--outputDir",
                    help    = "output image directory",
                    dest    = 'outputDir',
                    default = '')
parser.add_argument("-o", "--outputFileStem",
                    help    = "output file",
                    default = "",
                    dest    = 'outputFileStem')
parser.add_argument("-x", "--man",
                    help    = "man",
                    dest    = 'man',
                    action  = 'store_true',
                    default = False)
parser.add_argument("-e", "--extension",
                    help    = "DICOM file extension",
                    dest    = 'extension',
                    default = '')
parser.add_argument("-t", "--threads",
                    help    = "number of threads for innermost loop processing",
                    dest    = 'threads',
                    default = "0")
parser.add_argument("--outputLeafDir",
                    help    = "formatting spec for output leaf directory",
                    dest    = 'outputLeafDir',
                    default = "")
parser.add_argument("-y", "--synopsis",
                    help    = "short synopsis",
                    dest    = 'synopsis',
                    action  = 'store_true',
                    default = False)
parser.add_argument("-v", "--verbosity",
                    help    = "verbosity level for app",
                    dest    = 'verbosity',
                    default = "1")
parser.add_argument("--printElapsedTime",
                    help    = "print program run time",
                    dest    = 'printElapsedTime',
                    action  = 'store_true',
                    default = False)
parser.add_argument("--json",
                    help    = "output final return in json",
                    dest    = 'json',
                    action  = 'store_true',
                    default = False)
parser.add_argument("--followLinks",
                    help    = "follow symbolic links",
                    dest    = 'followLinks',
                    action  = 'store_true',
                    default = False)
parser.add_argument('--version',
                    help    = 'if specified, print version number',
                    dest    = 'b_version',
                    action  = 'store_true',
                    default = False)

args = parser.parse_args()

if args.man or args.synopsis:
    print(str_desc)
    if args.man:
        str_help     = synopsis(False)
    else:
        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()

pf_dicom             = pfdicom.pfdicom(
                        inputDir            = args.inputDir,
                        maxDepth            = args.maxDepth,
                        inputFile           = args.inputFile,
                        outputDir           = args.outputDir,
                        outputFileStem      = args.outputFileStem,
                        outputLeafDir       = args.outputLeafDir,
                        extension           = args.extension,
                        threads             = args.threads,
                        followLinks         = args.followLinks,
                        verbosity           = args.verbosity,
                        json                = args.json
                    )

# And now run it!
d_pfdicom = pf_dicom.run(timerStart = True)

if args.printElapsedTime: 
    pf_dicom.dp.qprint(
                        "Elapsed time = %f seconds" % 
                        d_pfdicom['runTime']
                        )

sys.exit(0)
