#!/usr/bin/env python

"""CICE namelist creator 
"""

# Typically ignore this.
# pylint: disable=invalid-name

# Disable these because this is our standard setup
# pylint: disable=wildcard-import,unused-wildcard-import,wrong-import-position

import os, shutil, sys, glob, filecmp, imp

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.case import Case
from CIME.nmlgen import NamelistGenerator
from CIME.utils import expect
from CIME.buildnml import create_namelist_infile, parse_input

logger = logging.getLogger(__name__)

# pylint: disable=too-many-arguments,too-many-locals,too-many-branches,too-many-statements
####################################################################################
def _create_namelists(case, confdir, infile, nmlgen):
####################################################################################
    """Write out the namelist for this component.

    Most arguments are the same as those for `NamelistGenerator`.
    The `confdir` argument is used to specify the directory  in which output files will be placed.
    """
    #----------------------------------------------------
    # Clear out old data.
    #----------------------------------------------------
    data_list_path = os.path.join(case.get_case_root(), "Buildconf", "cice.input_data_list")
    if os.path.exists(data_list_path):
        os.remove(data_list_path)

    #----------------------------------------------------
    # Create config dictionary
    #----------------------------------------------------
    config = {}

    cice_mode = case.get_value("CICE_MODE")
    hgrid = case.get_value('ICE_GRID')
    config['hgrid'] = hgrid
    config['cice_mode'] = cice_mode

    cice_config_opts = case.get_value('CICE_CONFIG_OPTS')
    if "cice5" in cice_config_opts:
        phys = "cice5"
    elif "cice4" in cice_config_opts:
        phys = "cice4"
    config['phys'] = phys

    cam_config_opts = case.get_value('CAM_CONFIG_OPTS')
    if cam_config_opts is not None:
        if "cam4" in cam_config_opts:
            config['cam4'] = ".true."

    if cice_mode == 'prescribed':
        config['sstice_stream'] = case.get_value("SSTICE_STREAM")

    if "DNTRAERO=0" in case.get_value("CICE_CPPDEFS"):
        config['ntraero'] = "0"

    if "DNTRISO=0" in case.get_value("CICE_CPPDEFS"):
        config['ntriso'] = "0"

    # Note - xml ICE_NCAT, CICE_DECOMPSETTING, CICE_DECOMPTYPE are used 
    # in setting the cice namelist and are set in buildlib: 

    #----------------------------------------------------
    # Initialize namelist defaults
    #----------------------------------------------------
    nmlgen.init_defaults(infile, config)

    #----------------------------------------------------
    # Set values not obtained in the default settings
    #----------------------------------------------------
    if nmlgen.get_value('gridcpl_file') == 'UNSET':
        nmlgen.set_value('gridcpl_file', value="unknown_gridcpl_file")

    # note that CICE_DECOMPSETTING is set in call to buildcpp
    if case.get_value('CICE_DECOMPSETTING') == 'null':
        config['cice_decomp_setting'] = 'null'
        processor_shape = nmlgen.get_default('processor_shape', config=config)
    else:
        processor_shape = case.get_value("CICE_DECOMPSETTING")
    nmlgen.set_value('processor_shape', value=processor_shape)

    # set initial conditions for branch of hybrid runs 
    # TODO - need to implement multi-instance for these files - the following assumes single instance
    run_type = case.get_value("RUN_TYPE")
    if run_type == 'branch' or run_type == 'hybrid':
        run_refcase = case.get_value("RUN_REFCASE")
        run_refdate = case.get_value("RUN_REFDATE")
        run_tod     = case.get_value("RUN_REFTOD")
	ice_ic = "%s.cice.r.%s-%s.nc" %(run_refcase, run_refdate, run_tod)
        nmlgen.add_default("ice_ic", value=ice_ic, ignore_abs_path=True)
    else: 
        nmlgen.add_default("ice_ic")
        if nmlgen.get_value('ice_ic') == 'UNSET':
            nmlgen.set_value('ice_ic', value="default")

    # error checks for prescribed ice mode
    if cice_mode == 'prescribed':
        sstice_grid_filename = case.get_value('SSTICE_GRID_FILENAME')
        sstice_data_filename = case.get_value('SSTICE_DATA_FILENAME')
        sstice_year_align = case.get_value('SSTICE_YEAR_ALIGN')
        sstice_year_start = case.get_value('SSTICE_YEAR_START')
        sstice_year_end = case.get_value('SSTICE_YEAR_END')
        if sstice_grid_filename == 'UNSET':
            expect(False,  "%s must be set for cice prescribed mode" %sstice_grid_filename)
        if sstice_data_filename == 'UNSET':
            expect(False,  "%s must be set for cice prescribed mode" %sstice_data_filename)
        if sstice_year_align == 'UNSET':
            expect(False,  "%s must be set for cice prescribed mode" %sstice_year_align)
        if sstice_year_start== 'UNSET':
            expect(False,  "%s must be set for cice prescribed mode" %sstice_year_start)
        if sstice_year_end== 'UNSET':
            expect(False,  "%s must be set for cice prescribed mode" %sstice_year_end)

    #----------------------------------------------------
    # Write out namelist groups
    #----------------------------------------------------
    groups=['setup_nml',
            'grid_nml',
            'tracer_nml',
            'thermo_nml',
            'dynamics_nml',
            'shortwave_nml',
            'ponds_nml',
            'forcing_nml',
            'domain_nml',
            'zbgc_nml',
            'icefields_bgc_nml',
            'icefields_drag_nml',
            'icefields_mechred_nml',
            'icefields_pond_nml',
            'icefields_nml']
    if cice_mode == 'prescribed':
        groups.append('ice_prescribed_nml')

    namelist_file = os.path.join(confdir, "ice_in")
    nmlgen.write_output_file(namelist_file, data_list_path, groups=groups, sorted_groups=False)

    logger.debug("cice: grid is %s" %(hgrid))
    logger.debug("cice: physics is %s "%phys)

###############################################################################
def buildnml(case, caseroot, compname):
###############################################################################
    """Build the cice namelist """

    # Build the component namelist 
    if compname != "cice":
        raise AttributeError

    srcroot = case.get_value("SRCROOT") 
    rundir = case.get_value("RUNDIR")
    ninst = case.get_value("NINST_ICE")

    # call buildcpp to obtain cppdefs 
    call_buildcpp = False
    if not os.path.exists(os.path.join(caseroot,"LockedFiles","env_build.xml")):
        call_buildcpp = True
    else:
        file1 = os.path.join(caseroot,"env_build.xml")  
        file2 = os.path.join(caseroot,"LockedFiles","env_build.xml")
        if not filecmp.cmp(file1, file2):
            call_buildcpp = True
    if call_buildcpp:
        cmd = os.path.join(os.path.join(srcroot,"components","cice","cime_config","buildcpp"))
        logger.info("     ...calling cice buildcpp to set build time options")
        try:
            mod = imp.load_source("buildcpp", cmd)
            mod.buildcpp(case)
        except:
            raise

    # determine the confdir directory
    confdir = os.path.join(caseroot,"Buildconf","ciceconf")
    if not os.path.isdir(confdir):
        os.makedirs(confdir)

    #----------------------------------------------------
    # Construct the namelist generator 
    #----------------------------------------------------
    # determine directory for user modified namelist_definitions.xml and namelist_defaults.xml
    user_xml_dir = os.path.join(caseroot, "SourceMods", "src.cice")
    expect (os.path.isdir(user_xml_dir),
            "user_xml_dir %s does not exist " %user_xml_dir)

    # user definition *replaces* existing definition.
    namelist_xml_dir = os.path.join(srcroot, "components", "cice", "cime_config")
    definition_file = [os.path.join(namelist_xml_dir, "namelist_definition_cice.xml")]
    user_definition = os.path.join(user_xml_dir, "namelist_definition_cice.xml")
    if os.path.isfile(user_definition):
        definition_file = [user_definition]
    for file_ in definition_file:
        expect(os.path.isfile(file_), "Namelist XML file %s not found!" % file_)

    # Create the namelist generator object - independent of instance
    nmlgen = NamelistGenerator(case, definition_file)

    #----------------------------------------------------
    # Loop over instances
    #----------------------------------------------------
    for inst_counter in range(1, ninst+1):

        # determine instance string
        inst_string = ""
        if ninst > 1:
            inst_string = '_' + '%04d' % inst_counter

        # If multi-instance case does not have restart file, use
        # single-case restart for each instance
        rpointer = "rpointer.ice" 
        if (os.path.isfile(os.path.join(rundir,rpointer)) and
            (not os.path.isfile(os.path.join(rundir,rpointer + inst_string)))):
            shutil.copy(os.path.join(rundir, rpointer),
                        os.path.join(rundir, rpointer + inst_string))

        inst_string_label = inst_string
        if not inst_string_label:
            inst_string_label = "\"\""

        # create namelist_infile using user_nl_file as input
        user_nl_file = os.path.join(caseroot, "user_nl_cice" + inst_string)
        expect(os.path.isfile(user_nl_file),
               "Missing required user_nl_file %s " %(user_nl_file))
        infile = os.path.join(confdir, "namelist_infile")
        create_namelist_infile(case, user_nl_file, infile)
        namelist_infile = [infile]

        # create namelist 
        _create_namelists(case, confdir, namelist_infile, nmlgen)

        # copy namelist files to rundir
        if os.path.isdir(rundir):
            file1  = os.path.join(confdir, "ice_in")
            file2 = os.path.join(rundir, "ice_in")
            if inst_string:
                file2 += inst_string
            logger.debug("CICE namelist copy: file1 %s file2 %s " %(file1, file2))
            shutil.copy2(file1, file2)

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

    caseroot = parse_input(sys.argv)
    with Case(caseroot) as case:
        buildnml(case, caseroot, "cice")

if __name__ == "__main__":
    _main_func()
