#!/usr/bin/env python3

"""
build model executable
"""

import sys, os

_CIMEROOT = os.environ.get("CIMEROOT")
if _CIMEROOT is None:
    raise SystemExit("ERROR: must set CIMEROOT environment variable")

sys.path.append(os.path.join(_CIMEROOT, "scripts", "Tools"))

from standard_script_setup import *
from CIME.buildlib         import parse_input
from CIME.build            import get_standard_makefile_args
from CIME.case             import Case
from CIME.utils            import expect, run_cmd

#pylint: disable=undefined-variable
logger = logging.getLogger(__name__)

###############################################################################
def _main_func():
###############################################################################

    caseroot, _, _ = parse_input(sys.argv)

    logger.info("Building a single executable version of target coupled model")

    with Case(caseroot) as case:
        casetools = case.get_value("CASETOOLS")
        exeroot   = case.get_value("EXEROOT")
        gmake     = case.get_value("GMAKE")
        gmake_j   = case.get_value("GMAKE_J")
        cime_model = case.get_value("MODEL")
        num_esp   = case.get_value("NUM_COMP_INST_ESP")
        ocn_model = case.get_value("COMP_OCN")
        gmake_args = get_standard_makefile_args(case)
        link_libs = case.get_value("CAM_LINKED_LIBS", subgroup="build_component_cam")
        esmf_aware_threading = case.get_value("ESMF_AWARE_THREADING")

    # Determine valid components
    valid_comps = []
    comp_classes = case.get_values("COMP_CLASSES")
    for item in comp_classes:
        comp = case.get_value("COMP_" + item)
        valid = True
        if comp == 's' + item.lower():
            valid = False
        if valid:
            valid_comps.append(item)

    datamodel_in_compset = False
    for comp in comp_classes:
        dcompname = "d"+comp.lower()
        if dcompname in case.get_value("COMP_{}".format(comp)):
            datamodel_in_compset = True

    if len(valid_comps) == 2 and not datamodel_in_compset:
        skip_mediator = True
    else:
        skip_mediator = False

    if ocn_model == 'mom':
        gmake_args += "USE_FMS=TRUE"

    if link_libs is not None:
        gmake_args += 'USER_SLIBS="{}"'.format(link_libs)

    comp_classes = case.get_values("COMP_CLASSES")
    for comp in comp_classes:
        model = case.get_value("COMP_{}".format(comp))
        stubcomp = "s{}".format(comp.lower())
        if model == stubcomp:
            gmake_args += " {}_PRESENT=FALSE".format(comp)
    if skip_mediator:
        gmake_args += " MED_PRESENT=FALSE"
    if esmf_aware_threading:
        gmake_args += " USER_CPPDEFS=-DESMF_AWARE_THREADING"

    gmake_args += " IAC_PRESENT=FALSE"
    expect((num_esp is None) or (int(num_esp) == 1), "ESP component restricted to one instance")

    bld_root = os.path.join(exeroot,'cpl','obj')
    if not os.path.isdir(bld_root):
        os.makedirs(bld_root)

    with open(os.path.join(bld_root,'Filepath'), 'w', encoding="utf-8") as out:
        cmeps_dir = os.path.join(os.path.dirname(__file__), os.pardir)
        # SourceMods dir needs to be first listed
        out.write(os.path.join(caseroot, "SourceMods", "src.drv") + "\n")
        if not skip_mediator:
            out.write(os.path.join(cmeps_dir, "mediator") + "\n")
            out.write(os.path.join(cmeps_dir, "cesm", "flux_atmocn") + "\n")
        out.write(os.path.join(cmeps_dir, "cesm", "driver") + "\n")

    # build model executable
    makefile = os.path.join(casetools, "Makefile")
    exename = os.path.join(exeroot, cime_model + ".exe")

    # always rebuild file esm.F90 this is because cpp macros in that file may have changed
    esm = os.path.join(bld_root,"esm.o")
    if os.path.isfile(esm):
        os.remove(esm)

    # always relink
    if os.path.isfile(exename):
        os.remove(exename)

    cmd = "{} exec_se -j {} EXEC_SE={} COMP_NAME=driver {} -f {} "\
        .format(gmake, gmake_j, exename, gmake_args, makefile)


    rc, out, err = run_cmd(cmd,from_dir=bld_root)
    expect(rc==0,"Command {} failed rc={}\nout={}\nerr={}".format(cmd,rc,out,err))
    if err:
        logger.info(err)
    logger.info(out)

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

if __name__ == "__main__":
    _main_func()
