#!/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__), '../pftree'))

import  pftree
from    argparse            import RawTextHelpFormatter
from    argparse            import ArgumentParser
import  pudb

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

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


        __ _                 
       / _| |                
 _ __ | |_| |_ _ __ ___  ___ 
| '_ \|  _| __| '__/ _ \/ _ \\
| |_) | | | |_| | |  __/  __/
| .__/|_|  \__|_|  \___|\___|
| |                          
|_|                          

  

                            Path-File tree structure

        Recursively walk down an input directory tree and create a dictionary
        representation of the path structure. Each tree "key" has a list
        of files in that corresponding directory in the filesystem. 

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


""" + Colors.NO_COLOUR

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

	    %s - Create a dictionary representation of a filesystem tree.

    SYNOPSIS

            %s                                          \\
                    -I|--inputDir <inputDir>                \\
                    [-r|--relativeDir]                      \\
                    [-i|--inputFile <inputFile>]            \\
                    [-O|--outputDir <outputDir>]            \\
                    [--outputLeafDir <outputLeafDirFormat>] \\
                    [--stats | --statsReverse]              \\
                    [-t|--threads <threads>]                \\
                    [--jsonStats]                           \\
                    [--json]                                \\
                    [-x|--man]                              \\
                    [-y|--synopsis]

    BRIEF EXAMPLE

	    %s                                          \\
                    -I /var/www/html                        \\
                    -O /tmp                                 \\
                    -r                                      \\
                    --printElapsedTime                      \\
                    --stats -v -1 --json


    ''' % (scriptName, scriptName, scriptName)

    description =  '''
    DESCRIPTION

        ``%s`` in and of itself is does not really do any work. It is a
        class that provides the internals for representing file system
        hierarchies in dictionary form.

        As a convenience, however, the ``--stats`` or ``--statsRevers`` 
        flags do provide a useful analog for sorted directory usage down
        a file system tree.

        Given an ``<inputDir>``, ``pftree`` will perform a recursive walk down
        the directory tree. For each directory that contains files, 
        ``pftree`` will create a dictionary key of the directory path,
        and will store a list of filenames for the key value.

        The core the of the class is a tree_analysisApply() method, that
        accepts various kwargs. When called, this method will loop
        over the dictionary, and for each key (i.e. 'path') will execute
        a callback method. This callback is passed the dictionary value
        at that key (i.e. usually just the list of files) as well as
        all the kwargs passed to tree_analysisApply().

    ARGS

        -I|--inputDir <inputDir>
        Input directory to examine. The downstream nested structure of this
        directory is examined and recreated in the <outputDir>.

        [-r|--relativeDir]
        A flag argument. If passed (i.e. True), then the dictionary key values
        are taken to be relative to the <inputDir>, i.e. the key values
        will not contain the <inputDir>; otherwise the key values will
        contain the <inputDir>.

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

        [-O|--outputDir <outputDir>]
        The directory to contain a tree structure identical to the input 
        tree structure, and which contains all output files from the 
        per-input-dir processing.

        [--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.

        [--stats | --statsReverse]
        If specified, return some stats to caller -- summary list ordered
        by directory size (--statsReverse does a reverse sort).

        [-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. Note that
              the input file read and output file write loops are not
              threaded -- only the analysis loop is threaded. Thus, if the
              bulk of execution time is in file IO, 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 potentially
              all the target input file data across the entire input directory
              tree.
              
        [--jsonStats]
        If specified, do a JSON dump of the stats.

        [--json]
        If specified, do a JSON dump of the entire return payload.

        [--test <analysisDelayLength>]
        If specified, perform a test/dummy run through the 

            - read
            - analyze
            - write

        callbacks. The <analysisDelayLength> denotes time (in seconds)
        to delay in the analysis loop -- useful for testing threading
        performance.

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

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

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

            0: No internal output;
            1: Most important internal output, i.e. sorted stat results;
            2: As with level '1' but with simpleProgress bar;
            3: As with level '2' but with list of input dirs/files;

    EXAMPLES

    Run on a target tree and output some detail and stats

        pftree            -I /var/www/html                  \\
                            --printElapsedTime              \\
                            --stats -v -0 --json

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


    ''' % (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("-i", "--inputFile",
                    help    = "input file",
                    dest    = 'inputFile',
                    default = '')
parser.add_argument("-O", "--outputDir",
                    help    = "output image directory",
                    dest    = 'outputDir',
                    default = '.')
parser.add_argument("-x", "--man",
                    help    = "man",
                    dest    = 'man',
                    action  = 'store_true',
                    default = False)
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("-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("-r", "--relativeDir",
                    help    = "use relative directories",
                    dest    = 'relativeDir',
                    action  = 'store_true',
                    default = False)
parser.add_argument("--stats",
                    help    = "show some quick stats",
                    dest    = 'stats',
                    action  = 'store_true',
                    default = False)
parser.add_argument("--statsReverse",
                    help    = "show some quick stats (reverse order)",
                    dest    = 'statsReverse',
                    action  = 'store_true',
                    default = False)
parser.add_argument("--jsonStats",
                    help    = "JSON dump stats",
                    dest    = 'jsonStats',
                    action  = 'store_true',
                    default = False)
parser.add_argument("--json",
                    help    = "JSON final return",
                    dest    = 'json',
                    action  = 'store_true',
                    default = False)
parser.add_argument("--test",
                    help    = "perform a test run of the read/analyze/write loop -- arg indicates sleep length in analyze",
                    dest    = 'test',
                    default = '')
parser.add_argument("--printElapsedTime",
                    help    = "print program run time",
                    dest    = 'printElapsedTime',
                    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_tree             = pftree.pftree(
                        inputDir            = args.inputDir,
                        inputFile           = args.inputFile,
                        outputDir           = args.outputDir,
                        relativeDir         = args.relativeDir,
                        stats               = args.stats,
                        statsReverse        = args.statsReverse,
                        threads             = args.threads,
                        json                = args.json,
                        jsonStats           = args.jsonStats,
                        test                = args.test,
                        outputLeafDir       = args.outputLeafDir,
                        verbosity           = args.verbosity
                    )

# And now run it!
d_pftree = pf_tree.run(timerStart = True)

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

sys.exit(0)
