#!/usr/bin/env python3
from standard_script_setup import *
from CIME.utils import copyifnewer, run_bld_cmd_ensure_logging, expect, symlink_force
from CIME.case import Case
from CIME.build import get_standard_cmake_args
from CIME.XML.files import Files
import glob

logger = logging.getLogger(__name__)

###############################################################################
def parse_command_line(args, description):
###############################################################################
    parser = argparse.ArgumentParser(
        usage="""\n{0} [--debug]
OR
{0} --verbose
OR
{0} --help

\033[1mEXAMPLES:\033[0m
    \033[1;32m# Run \033[0m
    > {0}
""" .format (os.path.basename(args[0])),

description=description,

formatter_class=argparse.ArgumentDefaultsHelpFormatter
)

    CIME.utils.setup_standard_logging_options(parser)

    parser.add_argument("buildroot",
                        help="build path root")

    parser.add_argument("installpath",
                        help="install path ")

    parser.add_argument("caseroot", nargs="?", default=os.getcwd(),
                        help="Case directory to build")

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

    return args.buildroot, args.installpath, args.caseroot

###############################################################################
def buildlib(bldroot, installpath, case):
###############################################################################
    comp_interface = case.get_value("COMP_INTERFACE")
    srcroot = case.get_value("SRCROOT")
    caseroot = case.get_value("CASEROOT")

    csm_share_dir = os.environ.get("csm_share_ROOT")
    if csm_share_dir is not None:
        # We are using a pre-installed csm_share
        expect(os.path.exists(csm_share_dir), f"Non-existent csm_share root {csm_share_dir}")
        return
    else:
        csm_share_dir = os.path.join(srcroot, "share")

    filepath = [os.path.join(caseroot,"SourceMods","src.share"),
                os.path.join(srcroot,"share","streams"),
                os.path.join(srcroot,"share","util"),
                os.path.join(srcroot,"share","RandNum","src"),
                os.path.join(srcroot,"share","RandNum","src","dsfmt_f03"),
                os.path.join(srcroot,"share","RandNum","src","kissvec"),
                os.path.join(srcroot,"share","RandNum","src","mt19937")]

    # Append path for driver - currently only values of 'mct' and 'nuopc' are accepted

    files = Files(comp_interface=comp_interface)

    filepath.append(os.path.join(files.get_value("COMP_ROOT_DIR_CPL"), "shr"))

    if case.get_value("USE_ESMF_LIB"):
        use_esmf = "esmf"
    else:
        use_esmf = "noesmf"
        filepath.append(os.path.join(srcroot, "share", "esmf_wrf_timemgr"))

    comp_interface = case.get_value("COMP_INTERFACE")
    ninst_value = case.get_value("NINST_VALUE")
    libdir = os.path.join(bldroot,comp_interface,use_esmf, ninst_value,"csm_share")
    if not os.path.isdir(libdir):
        os.makedirs(libdir)

    config_dir = os.path.join(caseroot, "Buildconf", "csm_shareconf")
    if not os.path.isdir(config_dir):
        os.makedirs(config_dir)

    filepathfile = os.path.join(config_dir, "Filepath")
    # if the filepathfile has a different number of lines than filepath, replace it
    file_len = 0
    if os.path.isfile(filepathfile):
        file_len = len(open(filepathfile).readlines())

    if len(filepath) != file_len:
        with open(filepathfile, "w") as fd:
            for path in filepath:
                fd.write("{}\n".format(path))

    components = case.get_values("COMP_CLASSES")
    multiinst_cppdefs = ""
    multi_driver = case.get_value("MULTI_DRIVER")
    for comp in components:
        if comp == "CPL":
            continue
        if multi_driver:
            ninst_comp = 1
        else:
            ninst_comp = case.get_value("NINST_{}".format(comp))
        multiinst_cppdefs += " -DNUM_COMP_INST_{}={}".format(comp, ninst_comp)

    if case.get_value("COMP_OCN") == "nemo":
        multiinst_cppdefs += " -DNEMO_IN_CCSM "

    cppdefs_file = os.path.join(config_dir, "CIME_cppdefs")
    if not os.path.isfile(cppdefs_file):
        with open(cppdefs_file, "w") as fd:
            fd.write(multiinst_cppdefs + " -DTIMING\n")

    installdir = os.path.join(installpath, comp_interface,
                              use_esmf, ninst_value)
    for ndir in ("lib", "include"):
        if not os.path.isdir(os.path.join(installdir,ndir)):
            os.makedirs(os.path.join(installdir,ndir))
    # copy some header files
    for _file in glob.iglob(os.path.join(srcroot,"share","include","*")):
        copyifnewer(_file, os.path.join(installdir, "include", os.path.basename(_file)))
    for _file in glob.iglob(os.path.join(srcroot,"share","RandNum","include","*")):
        copyifnewer(_file, os.path.join(installdir, "include", os.path.basename(_file)))

    # This runs the cmake command
    cmake_args = get_standard_cmake_args(case, installpath)
    run_bld_cmd_ensure_logging(f"cmake {cmake_args} {csm_share_dir}", logger, from_dir=libdir)

    gmake_cmd = case.get_value("GMAKE")
    gmake_j   = case.get_value("GMAKE_J")

    cmd = "{} -j {}".format(gmake_cmd, gmake_j)
    run_bld_cmd_ensure_logging(cmd, logger, from_dir=libdir)
    #
    # The pgi compiler sometimes has issues with long include paths
    # on the command line, this is a workaround for that problem
    #
    case_inc_dir = os.path.join(libdir, "..", "include")
    if not os.path.isdir(case_inc_dir):
        os.mkdir(case_inc_dir)

    for _file in glob.iglob(os.path.join(libdir,"*.mod")):
        symlink_force(_file, os.path.join(case_inc_dir,os.path.basename(_file)))

    for _file in glob.iglob(os.path.join(libdir,"*.h")):
        symlink_force(_file, os.path.join(case_inc_dir,os.path.basename(_file)))

###############################################################################
def _main(argv, documentation):
###############################################################################
    bldroot, installpath, caseroot = parse_command_line(argv, documentation)
    with Case(caseroot) as case:
        buildlib(bldroot, installpath, case)

###############################################################################
if (__name__ == "__main__"):
    _main(sys.argv, __doc__)
