#!/usr/bin/env python

'''

Copyright (C) 2017 The Board of Trustees of the Leland Stanford Junior
University.
Copyright (C) 2016-2017 Vanessa Sochat.

This program is free software: you can redistribute it and/or modify it
under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or (at your
option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Affero General Public
License for more details.

You should have received a copy of the GNU Affero General Public License
along with this program.  If not, see <https://www.gnu.org/licenses/>.

'''

import scif
import argparse
import sys
import os


def get_parser():
    parser = argparse.ArgumentParser(description="scientific filesystem tools")


    # Global
    
    parser.add_argument('--debug', dest="debug", 
                        help="use verbose logging to debug.", 
                        default=False, action='store_true')

    parser.add_argument('--quiet', dest="quiet", 
                        help="suppress print output", 
                        default=False, action='store_true')

    parser.add_argument('--writable','-w', dest="writable", 
                        help="for relevant commands, if writable SCIF is needed", 
                        default=False, action='store_true')

    description = 'actions for Scientific Filesystem'
    subparsers = parser.add_subparsers(help='scif actions',
                                       title='actions',
                                       description=description,
                                       dest="command")

    version = subparsers.add_parser("version",
                                    help="show software version")
 

    # Shell and Interactive Terminal (it)

    pyshell = subparsers.add_parser("pyshell",
                                     help="Interactive python shell to scientific filesystem")

    pyshell.add_argument("recipe", nargs='*',
                          help="recipe file or scientific filesystem base", 
                          type=str)


    shell = subparsers.add_parser("shell",
                                  help="shell to interact with scientific filesystem")

    shell.add_argument("app", nargs='?',
                       help="app shell to, defaults to SCIF base if not set.", 
                       type=str)


    preview = subparsers.add_parser("preview",
                                     help="preview changes to a filesytem")

    # if the user provides more than one argument here, they are apps
    preview.add_argument("recipe", nargs="*", 
                         help="recipe file for the filesystem", 
                         type=str)


    # Help
    help = subparsers.add_parser("help",
                                 help="look at help for an app, if it exists.")


    help.add_argument("app", nargs='*',
                       help="app(s) to print help for", 
                       type=str)


    # Install

    install = subparsers.add_parser("install",
                                     help="install a recipe on the filesystem")

    install.add_argument("recipe", nargs="*", 
                         help="recipe file for the filesystem", 
                         type=str)


    # Inspect

    inspect = subparsers.add_parser("inspect",
                                     help="inspect an attribute for a scif installation")

    inspect.add_argument('attributes',
                         nargs='*',
                         help='''attribute to inspect (runscript|r),
                                                      (environment|e),
                                                      (labels|l), or (all|a) (default)''')


    # Run

    run = subparsers.add_parser("run",
                                 help="entrypoint to run a scientific filesystem")


    run.add_argument("cmd", nargs='*',
                     help="app and optional arguments to target for the entry", 
                     type=str)


    # List and dump
    ls = subparsers.add_parser("apps",
                                help="list apps installed")

    ls.add_argument('-l', dest="longlist", 
                     help="show long listing, including paths", 
                     default=False, action='store_true')


    dump = subparsers.add_parser("dump",
                                help="dump recipe")




    # Execute

    execute = subparsers.add_parser("exec",
                                     help="execute a command to a scientific filesystem")


    execute.add_argument("cmd", nargs='*',
                         help="app and command to execute. Eg, exec appname echo $SCIF_APPNAME", 
                         type=str)

    # Not sure if this is needed.
    #write = subparsers.add_parser("write",
    #                               help="write a Dockerfile (default) or Singularity Recipe.")

    #write.add_argument('--write',
    #                   default='docker',
    #                   const='docker',
    #                   nargs='?',
    #                   choices=['docker', 'singularity'],
    #                   help='write a container build specification from the scif recipe (default: %(default)s)')
        
    return parser


def get_subparsers(parser):
    '''get_subparser will get a dictionary of subparsers, to help with printing help
    '''

    actions = [action for action in parser._actions 
               if isinstance(action, argparse._SubParsersAction)]

    subparsers = dict()
    for action in actions:
        # get all subparsers and print help
        for choice, subparser in action.choices.items():
            subparsers[choice] = subparser

    return subparsers



def main():
    '''main is the entrypoint to managing or interacting with an scif 
       organized filesystem.
    '''

    parser = get_parser()
    subparsers = get_subparsers(parser)

    def help(return_code=0):
        '''print help, including the software version and active client 
           and exit with return code.
        '''
        version = scif.__version__

        print("\nScientific Filesystem [v%s]" %(version))
        parser.print_help()
        sys.exit(return_code)
    
    # If the user didn't provide any arguments, show the full help
    if len(sys.argv) == 1:
        help()
    try:
        args, unknown = parser.parse_known_args()
    except:
        sys.exit(0)

    # If unknown arguments were provided, pass on to cmd to run
    if args.command in ['run', 'exec'] and len(unknown) > 0:
        args.cmd += unknown

    # if environment logging variable not set, make silent
    if args.debug is False:
        os.environ['SCIF_MESSAGELEVEL'] = 'INFO'
        os.putenv('SCIF_MESSAGELEVEL', 'INFO')

    if args.quiet is True:
        os.environ['SCIF_MESSAGELEVEL'] = 'QUIET'
        os.putenv('SCIF_MESSAGELEVEL', 'QUIET')

    # Show the version and exit
    if args.command == "version":
        print(scif.__version__)
        sys.exit(0)

    # Does the user want a shell?   
    if args.command == "apps": from .list import main
    if args.command == "dump": from .dump import main
    if args.command == "exec": from .execute import main
    if args.command == "help": from .help import main
    if args.command == "install": from .install import main
    if args.command == "preview": from .preview import main
    if args.command == "pyshell": from .pyshell import main
    if args.command == "shell": from .shell import main
    if args.command == "inspect": from .inspect import main
    if args.command == "run": from .run import main

    # Pass on to the correct parser
    return_code = 0
    try:
        main(args=args,
             parser=parser,
             subparser=subparsers[args.command])
        sys.exit(return_code)
    except UnboundLocalError:
        return_code = 1

    help(return_code)

if __name__ == '__main__':
    main()
