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

import  pfcon
import  socket
from    argparse            import RawTextHelpFormatter
from    argparse            import ArgumentParser
#from    distutils.sysconfig import get_python_lib

import  pudb

# The following convolutions are necessary to accommodate both
# development and deployed instances of the 'pfcon.py' module
# and related dependencies.
# sys.path.insert(1, os.path.join(os.path.dirname(__file__), '../pfcon'))
# try:
#     import  pfcon
# except:
#     sys.path.insert(1, os.path.join(get_python_lib(True, True), 'site-packages'))
#     sys.path.insert(1, os.path.join(get_python_lib(True, True), 'site-packages/pfcon'))
#     import  pfcon

from    pfmisc._colors             import Colors

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_version = "2.2.0.0"
str_desc = Colors.CYAN + """

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


                            Process-File-CONtroller

           A controller for processes and data -- part of the pf* family.

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

    'pfcon' is a module class and stand-alone app that provides a simple API (both
    programmatically and CLI-driven) to coordinate data transfers and process control
    to remote pfioh (for data transfer) and pman (for process management).
    
""" + \
        Colors.BLINK_RED +  """
        
            +-----------------------------------------------------------+
            | NOTE THAT THIS SERVER DOES NOT CURRENTLY AUTHENTICATE AND |
            | WILL HONOR *ALL* DATA PUSH AND PROCESS CONTROL REQUESTS!  |
            +-----------------------------------------------------------+
              
""" + Colors.NO_COLOUR

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

	    pfcon 

        - process-and-file controller

    SYNOPSIS

            pfcon                                                   \\
                [--ip <IPofServer>]                                 \\
                [--port <port>]                                     \\
                [--man <manpage>]                                   \\
                [--forever]                                         \\
                [--coordBlockSeconds <secondsBlock>]                \\
                [--verbosity <level>]                               \\
                [--configFileLoad <file>]                           \\
                [--configFileSave <file>]                           \\
                [--test]                                            \\
                [--httpResponse]                                    \\
                [-x|--desc]                                         \\
                [-y|--synopsis]                                     \\
                [--version]                                         \\
                [--debugToDir <dir>]                                \\
                [--verbosity <level>]

    BRIEF EXAMPLE

            pfcon                                                   \\
                --forever                                           \\
                --port 5005                                         \\
                --httpResponse                                      \\
                --verbosity 1                                       \\
                --debugToDir /tmp                                   \\
                --ip %s

    ''' % str_defIP

    description =  '''
    DESCRIPTION

        ``pfcon`` is a process/file controller, part of the ``pf`` suite of 
        applications, and used mostly in the context of ChRIS.

        Typically ``pfcon`` is launched on the localhost where it 
        listens for directives directing data and compute. Target 
        data is zipped and transmitted to a remote location, and 
        once available on the remote, a containerized computation 
        is started.

        An internal loop monitors the status of the remote processing,
        and once complete, control returns.

    ARGS

        [--ip <IP>]                            

        The IP interface on which to listen. Default %s.

        [--port <port>]
        The port on which to listen. Defaults to '5055'.

        [--man <manpage>]
        Internal man page with more detail on specific calls.

        [--forever]
        Start service and do not terminate.

        [--httpResponse]
        Send return strings as HTTP formatted replies with content-type html.

        [--cordBlockSeconds <blockSeconds>]
        The number of seconds to block/wait internally in the coordination loop.
        This is the time between ``pfioh`` has indicated successful unpack of file
        data and the call to ``pman`` to start processing.

        [--configFileLoad <file>]
        Load configuration information from the JSON formatted <file>.

        [--configFileSave <file>]
        Save configuration information to the JSON formatted <file>.

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

    Start ``pfcon`` in forever mode:

            pfcon                                                   \\
                --forever                                           \\
                --port 5005                                         \\
                --httpResponse                                      \\
                --verbosity 1                                       \\
                --debugToDir /tmp                                   \\
                --ip %s

    ''' % (str_defIP, str_defIP)
    if ab_shortOnly:
        return shortSynopsis
    else:
        return shortSynopsis + description

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

parser.add_argument(
    '--ip',
    action  = 'store',
    dest    = 'ip',
    default = str_defIP,
    help    = 'IP to connect.'
)
parser.add_argument(
    '--port',
    action  = 'store',
    dest    = 'port',
    default = '5005',
    help    = 'Port to use.'
)
parser.add_argument(
    '--version',
    help    = 'if specified, print version number',
    dest    = 'b_version',
    action  = 'store_true',
    default = False
)
parser.add_argument(
    '--man',
    help    = 'request help',
    dest    = 'man',
    action  = 'store',
    default = ''
)
parser.add_argument(
    '--forever',
    help    = 'if specified, serve forever, otherwise terminate after single service.',
    dest    = 'b_forever',
    action  = 'store_true',
    default = False
)
parser.add_argument(
    '--test',
    help    = 'if specified, perform internal tests',
    dest    = 'b_test',
    action  = 'store_true',
    default = False
)
parser.add_argument(
    '--httpResponse',
    help    = 'if specified, return HTTP responses',
    dest    = 'b_httpResponse',
    action  = 'store_true',
    default = False
)
parser.add_argument(
    '--coordBlockSeconds',
    help    = 'the number of seconds to block internally in the coordination loop',
    dest    = 'coordBlockSeconds',
    action  = 'store',
    default = 5
)
parser.add_argument(
    '--configFileLoad',
    help    = 'a file containing configuration information',
    dest    = 'str_configFileLoad',
    action  = 'store',
    default = ''
)
parser.add_argument(
    '--configFileSave',
    help    = 'a file to store configuration information',
    dest    = 'str_configFileSave',
    action  = 'store',
    default = ''
)
parser.add_argument(
    '--debugToDir',
    help    = 'a destination directory to contain debugging info',
    dest    = 'str_debugToDir',
    action  = 'store',
    default = ''
)
parser.add_argument(
    "-v", "--verbosity",
    help    = "verbosity level for app",
    dest    = 'verbosity',
    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
) 

args            = parser.parse_args()
args.port       = int(args.port)

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()
server          = pfcon.ThreadedHTTPServer((args.ip, args.port), pfcon.StoreHandler)
server.setup(args = vars(args), desc = str_desc, ver = str_version)

if args.b_test:
    handler     = pfcon.StoreHandler(test = True)
    handler.do_POST(
        d_msg = {
            "action": "hello",
            "meta": {
                "askAbout":     "sysinfo",
                "echoBack":     "Hi there!"
                }
            }
    )
    sys.exit(0)

if args.b_forever and not args.b_test:
    server.serve_forever()
else:
    server.handle_request()
