#!/usr/bin/env python

"""Namelist creator for CDEPS data ocn model.
"""

# 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, sys, re

_CDEPS_CONFIG = os.path.join(os.path.dirname(os.path.abspath(__file__)), os.pardir,os.pardir,"cime_config")
_CIMEROOT = os.environ.get("CIMEROOT")
if _CIMEROOT is None:
    raise SystemExit("ERROR: must set CIMEROOT environment variable")
_LIBDIR = os.path.join(_CIMEROOT, "scripts", "Tools")
sys.path.append(_LIBDIR)
sys.path.append(os.path.join(_CDEPS_CONFIG))

from standard_script_setup import *
from CIME.case import Case
from CIME.XML.files import Files
from CIME.nmlgen import NamelistGenerator
from CIME.utils import expect, safe_copy
from CIME.buildnml import create_namelist_infile, parse_input, copy_inputs_to_rundir
from stream_cdeps import StreamCDEPS

logger = logging.getLogger(__name__)

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

    Most arguments are the same as those for `NamelistGenerator`. The
    `inst_string` argument is used as a suffix to distinguish files for
    different instances. The `confdir` argument is used to specify the directory
    in which output files will be placed.
    """
    #----------------------------------------------------
    # Write out docn_in and docn.streams.xml
    #----------------------------------------------------

    caseroot = case.get_value("CASEROOT")
    docn_mode = case.get_value("DOCN_MODE")
    ocn_grid = case.get_value("OCN_GRID")
    ocn_nx = case.get_value("OCN_NX")
    ocn_ny = case.get_value("OCN_NY")
    atm_nx = case.get_value("ATM_NX")
    atm_ny = case.get_value("ATM_NY")
    model_grid = case.get_value("GRID")

    # Check for incompatible options.
    expect(ocn_grid != "null",
           "OCN_GRID cannot be null")

    # Log some settings.
    logger.debug("DOCN mode is {}".format(docn_mode))
    logger.debug("DOCN grid is {}".format(ocn_grid))

    # Initialize namelist defaults
    config = {}
    config['model_grid'] = model_grid
    config['ocn_grid'] = ocn_grid
    config['docn_mode'] = docn_mode
    config['create_mesh'] = 'true' if case.get_value("OCN_DOMAIN_MESH") == 'create_mesh' else 'false'
    aquaplanet_mode = True if 'AQ' in case.get_value('COMPSET') else False
    scol_mode = True if case.get_value('PTS_MODE') else False
    config['set_model_maskfile'] = 'true' if scol_mode or (ocn_nx==atm_nx and ocn_ny==atm_ny and not aquaplanet_mode) else 'false'

    nmlgen.init_defaults(infile, config)

    # Generate docn_in
    namelist_file = os.path.join(confdir, "docn_in")
    nmlgen.write_output_file(namelist_file, data_list_path, groups=['docn_nml'])

    # Generate docn.streams.xml if needed
    if (re.search(r'sst_aquap[0-9]+',docn_mode) is not None) or (docn_mode == 'sst_aquap_constant'):
        generate_stream_file = False
    else:
        generate_stream_file = True
    #endif
    if generate_stream_file:
        streamlist = nmlgen.get_streams()
        print "DEBUG: streamlist is ",streamlist
        stream_file = os.path.join(_CDEPS_CONFIG,os.pardir, "docn","cime_config","stream_definition_docn.xml")
        schema_file = os.path.join(_CDEPS_CONFIG,"streams_v2.0.xsd")
        streams = StreamCDEPS(stream_file, schema_file)
        outfile = os.path.join(confdir, "docn.streams"+inst_string+".xml" )
        streams.create_stream_xml(streamlist, case, outfile, data_list_path)
    #endif

###############################################################################
def buildnml(case, caseroot, compname):
###############################################################################

    # Build the component namelist and required stream xml files
    if compname != "docn":
        raise AttributeError

    rundir = case.get_value("RUNDIR")
    ninst = case.get_value("NINST_OCN")
    if ninst is None:
        ninst = case.get_value("NINST")

    # Determine configuration directory
    confdir = os.path.join(caseroot,"Buildconf",compname + "conf")
    if not os.path.isdir(confdir):
        os.makedirs(confdir)

    #----------------------------------------------------
    # Construct the namelist generator
    #----------------------------------------------------
    # determine directory for user modified namelist_definitions.xml
    user_xml_dir = os.path.join(caseroot, "SourceMods", "src." + compname)
    expect (os.path.isdir(user_xml_dir),
            "user_xml_dir {} does not exist ".format(user_xml_dir))

    # NOTE: User definition *replaces* existing definition.
    files = Files(comp_interface="nuopc")
    definition_file = [files.get_value("NAMELIST_DEFINITION_FILE", {"component":"docn"})]

    user_definition = os.path.join(user_xml_dir, "namelist_definition_docn.xml")
    if os.path.isfile(user_definition):
        definition_file = [user_definition]
    for file_ in definition_file:
        expect(os.path.isfile(file_), "Namelist XML file {} not found!".format(file_))

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

    #----------------------------------------------------
    # Clear out old data.
    #----------------------------------------------------
    data_list_path = os.path.join(case.get_case_root(), "Buildconf", "docn.input_data_list")
    if os.path.exists(data_list_path):
        os.remove(data_list_path)

    #----------------------------------------------------
    # Loop over instances
    #----------------------------------------------------
    for inst_counter in range(1, ninst+1):
        # determine instance string
        inst_string = ""
        if ninst > 1:
            inst_string = '_' + "{:04d}".format(inst_counter)

        # If multi-instance case does not have restart file, use
        # single-case restart for each instance
        rpointer = "rpointer." + compname
        if (os.path.isfile(os.path.join(rundir,rpointer)) and
            (not os.path.isfile(os.path.join(rundir,rpointer + inst_string)))):
            safe_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 output infile using user_nl_file as input
        user_nl_file = os.path.join(caseroot, "user_nl_" + compname + inst_string)
        expect(os.path.isfile(user_nl_file),
               "Missing required user_nl_file {} ".format(user_nl_file))
        infile = os.path.join(confdir, "namelist_infile")
        create_namelist_infile(case, user_nl_file, infile)
        namelist_infile = [infile]

        # create namelist and stream file(s) data component
        _create_namelists(case, confdir, inst_string, namelist_infile, nmlgen, data_list_path)

        copy_inputs_to_rundir(caseroot, compname, confdir, rundir, inst_string)

###############################################################################
def _main_func():
    # Build the component namelist and required stream xml files
    caseroot = parse_input(sys.argv)
    with Case(caseroot) as case:
        buildnml(case, caseroot, "docn")

if __name__ == "__main__":
    _main_func()
