#!/usr/bin/env python

from Tools.standard_script_setup import *
from CIME.utils         import expect, get_model
from CIME.case          import Case
from CIME.check_lockedfiles import lock_file

logger = logging.getLogger(__name__)

###############################################################################
def parse_command_line(args, cimeroot, description):
###############################################################################
    help_str = \
"""
{0} --case [CASE] --compset [COMPSET] --res [GRID] [--machine ...] [--compiler ...]
OR
{0} --help
""".format(os.path.basename(args[0]))
    model = get_model()

    parser = argparse.ArgumentParser(usage=help_str,
                                     description=description,
                                     formatter_class=argparse.ArgumentDefaultsHelpFormatter)


    CIME.utils.setup_standard_logging_options(parser)

    parser.add_argument("--case", "-case", required=True,
                        help="(required) Specify the case name. "
                        "If not a full pathname, then the case is created "
                        "under then current working directory ")

    parser.add_argument("--compset", "-compset", required=True,
                        help="(required) Specify a compset. "
                        "To see list of current compsets, use the utility query_config in this directory")

    parser.add_argument("--res", "-res", required=True,
                        help="(required) Specify a model grid resolution. "
                        "To see list of current compsets, use the utility query_config in this directory")

    parser.add_argument("--machine", "-mach",
                        help="Specify a machine. default: match NODENAME_REGEX in config_machines.xml "
                        "To see list of current  machines, use the utility query_config in this directory"
                        )

    parser.add_argument("--compiler", "-compiler",
                        help="Specify a compiler. "
                        "To see list of supported compilers for each machine, use the utility query_config in this directory")

    parser.add_argument("--ninst",default=1,
                        help="Specify number of component instances"
                        "Set the number of component instances in the case.")

    parser.add_argument("--mpilib", "-mpilib",
                        help="Specify the mpilib. "
                        "To see list of supported mpilibs for each machine, use the utility query_config in this directory. "
                        "The default is the first listing in MPILIBS in config_machines.xml")

    parser.add_argument("--project", "-project",
                        help="Specify a project id")

    parser.add_argument("--pecount", "-pecount",  default="M",
                        help="Specify a target size description for the number of cores"
                         "Allowed options are   ('S','M','L','X1','X2','[0-9]x[0-9]','[0-9]')")

    parser.add_argument("--user-mods-dir", "-user_mods_dir",
                        help="Path to directory with user_nl_* files and xmlchange "
                        "commands to utilize. This can also include SourceMods. "
                        "This can be an absolute path, a path relative to the "
                        "current directory, or a path relative to "
                        "cime_config/usermods_dirs/ under the primary component "
                        "for the given compset (for example, in an F compset "
                        "whose primary component is cam, '--user-mods-dir foo' "
                        "could be found in components/cam/cime_config/usermods_dirs/foo).")

    parser.add_argument("--user-compset", action="store_true",
                        help="If set, then the --compset argument is treated as a user specified compset."
                        "This assumes that all of the compset settings in the"
                        "compset along name have been defined for all of its components"
                        "If the compset name is found as a supported compset, then it will be treated as such.")

    parser.add_argument("--pesfile",
                        help="Full pathname of an optional pes specification "
                        "file. The file can follow either the config_pes.xml or "
                        "the env_mach_pes.xml format.")

    parser.add_argument("--user-grid", action="store_true",
                        help="If set, then the -grid argument is treated as a user specified grid."
                        "As such, the additional argument --gridfile must also be specified"
                        "and all of the grid settings in the --res argument name (which must be a grid longname"
                        "have been defined in the grid file pointed to by --gridfile")

    parser.add_argument("--gridfile",
                        help="Full pathname of config grid file to use"
                        "This should be a copy of config/config_grids.xml"
                        "with the new user grid changes added to it"
                        "This argument is required if --user-grid is True")

    parser.add_argument("--srcroot", default=os.path.dirname(cimeroot),
                        help="Alternative path for source root directory. By default this is set to"
                        "cimeroot/../")

    parser.add_argument("--output-root",
                        help="Alternative path for the directory where case output is written")

    parser.add_argument("--script-root", dest="script_root", default=None,
                        help="Alternative path for the directory where the cime scripts are written")

    if model == "cesm":
        parser.add_argument("--run-unsupported", action="store_true",
                            help="Force the creation of a case not tested or supported by CESM developers")


    # hidden argument indicating called from create_test
    parser.add_argument("--test", "-test", action="store_true",
                        help="Used to indicate that create_newcase was called from create_test"
                        "- do not use otherwise")

    parser.add_argument("--walltime", default=os.getenv("CIME_GLOBAL_WALLTIME"),
                        help="Set the wallclock limit for this case. "
                        "Can use env var CIME_GLOBAL_WALLTIME to set this.")

    parser.add_argument("-q", "--queue", default=None,
                        help="Force batch system to use a certain queue")

    parser.add_argument("--handle-preexisting-dirs", dest="answer", choices=("a", "r", "u"), default=None,
                        help="Pre-answer what to do pre-existing bld/exe dirs. Valid answers are (a)bort (r)eplace or (u)se existing."
                        "This can be useful if you need to run create_newcase non-iteractively.")

    parser.add_argument("-i", "--input-dir",
                        help="Use a non-default location for input files")

    args = CIME.utils.parse_args_and_handle_standard_logging_options(args, parser)

    if args.srcroot is not None:
        expect(os.path.isdir(args.srcroot),
               "Input non-default directory srcroot {} does not exist ".format(args.srcroot))
        args.srcroot = os.path.abspath(args.srcroot)

    if args.gridfile is not None:
        expect(os.path.isfile(args.gridfile),
               "Grid specification file {} does not exist ".format(args.gridfile))

    if args.pesfile is not None:
        expect(os.path.isfile(args.pesfile),
               "Pes specification file {} cannot be found ".format(args.pesfile))

    if args.user_grid:
        expect(args.gridfile is not None,
               "User grid specification file must be set if the user grid is requested")

    run_unsupported = False
    if model == "cesm":
        run_unsupported = args.run_unsupported

    expect(CIME.utils.check_name(args.case, fullpath=True),
           "Illegal case name argument provided")

    if args.input_dir is not None:
        args.input_dir = os.path.abspath(args.input_dir)

    return args.case, args.compset, args.res, args.machine, args.compiler,\
        args.mpilib, args.project, args.pecount, \
        args.user_mods_dir, args.user_compset, args.pesfile, \
        args.user_grid, args.gridfile, args.srcroot, args.test, args.ninst, \
        args.walltime, args.queue, args.output_root, args.script_root, \
        run_unsupported, args.answer, args.input_dir

###############################################################################
def _main_func(description):
###############################################################################
    cimeroot  = os.path.abspath(CIME.utils.get_cime_root())

    casename, compset, grid, machine, compiler, \
        mpilib, project, pecount,  \
        user_mods_dir, user_compset, pesfile, \
        user_grid, gridfile, srcroot, test, ninst, walltime, queue, \
        output_root, script_root, run_unsupported, \
        answer, input_dir = parse_command_line(sys.argv, cimeroot, description)

    if script_root is None:
        caseroot = os.path.abspath(casename)
    else:
        caseroot = os.path.abspath(script_root)

    if user_mods_dir is not None:
        if os.path.isdir(user_mods_dir):
            user_mods_dir = os.path.abspath(user_mods_dir)

    # create_test creates the caseroot before calling create_newcase
    # otherwise throw an error if this directory exists
    expect(not (os.path.exists(caseroot) and not test),
           "Case directory {} already exists".format(caseroot))

    with Case(caseroot, read_only=False) as case:
        # Set values for env_case.xml
        case.set_lookup_value("CASE", os.path.basename(casename))
        case.set_lookup_value("CASEROOT", caseroot)
        case.set_lookup_value("SRCROOT", srcroot)

        # Configure the Case
        case.configure(compset, grid, machine_name=machine, project=project,
                       pecount=pecount, compiler=compiler, mpilib=mpilib,
                       user_compset=user_compset, pesfile=pesfile,
                       user_grid=user_grid, gridfile=gridfile, ninst=ninst, test=test,
                       walltime=walltime, queue=queue, output_root=output_root,
                       run_unsupported=run_unsupported, answer=answer,
                       input_dir=input_dir)

        case.create_caseroot()

        # Write out the case files
        case.flush(flushall=True)
        case.apply_user_mods(user_mods_dir)

    # Lock env_case.xml
    lock_file("env_case.xml", caseroot)

###############################################################################

if __name__ == "__main__":
    _main_func(__doc__)
