"""Build DAOS components"""

import os

HEADERS = ['daos_api.h', 'daos_types.h', 'daos_errno.h', 'daos_kv.h',
           'daos_event.h', 'daos_mgmt.h', 'daos_types.h', 'daos_array.h',
           'daos_task.h', 'daos_fs.h', 'daos_uns.h', 'daos_security.h',
           'daos_prop.h', 'daos_obj_class.h', 'daos_obj.h', 'daos_pool.h',
           'daos_cont.h', 'daos_version.h', 'daos_fs_sys.h', 'daos_s3.h', 'daos_pipeline.h']
HEADERS_SRV = ['vos.h', 'vos_types.h']
HEADERS_GURT = ['dlog.h', 'debug.h', 'common.h', 'hash.h', 'list.h',
                'heap.h', 'fault_inject.h', 'debug_setup.h',
                'types.h', 'atomic.h', 'slab.h',
                'telemetry_consumer.h', 'telemetry_common.h']
HEADERS_CART = ['api.h', 'iv.h', 'types.h', 'swim.h']


# Keep versioned libs for now to avoid any conflict with 1.0
CART_VERSION = "4.9.0"

API_VERSION_MAJOR = "2"
API_VERSION_MINOR = "7"
API_VERSION_FIX = "0"
API_VERSION = f'{API_VERSION_MAJOR}.{API_VERSION_MINOR}.{API_VERSION_FIX}'


def read_and_save_version(env):
    """Read version from VERSION file and update daos_version.h"""

    env.Append(CCFLAGS=['-DAPI_VERSION=\\"' + API_VERSION + '\\"'])

    with open(os.path.join(Dir('#').abspath, "VERSION"), "r") as version_file:
        version = version_file.read().rstrip()

        (major, minor, fix) = version.split('.')

        env.Append(CCFLAGS=['-DDAOS_VERSION=\\"' + version + '\\"'])

        if GetOption('help'):
            return version

        tmpl_hdr_in = os.path.join('include', 'daos_version.h.in')
        subst_dict = {'@TMPL_MAJOR@': API_VERSION_MAJOR,
                      '@TMPL_MINOR@': API_VERSION_MINOR,
                      '@TMPL_FIX@': API_VERSION_FIX,
                      '@TMPL_PKG_MAJOR@': major,
                      '@TMPL_PKG_MINOR@': minor,
                      '@TMPL_PKG_FIX@': fix,
                      '@Template for @': ''}

        out = env.Substfile(tmpl_hdr_in, SUBST_DICT=subst_dict)
        print(f'generated daos version header file: {out[0].abspath}')

        return version


def check_install_header(env, header):
    """Runs a builder to ensure the header can standalone compile and installs it"""
    result = env.CheckHeader(header)
    # Ensure the target, actually gets built since none of these targets
    # get installed.
    Default(result)
    env.Install(os.path.join('$PREFIX', os.path.dirname(header)), header)


def scons():
    """Execute build"""
    Import('env', 'base_env', 'base_env_mpi', 'prereqs')

    daos_version = read_and_save_version(env)

    Export('daos_version', 'API_VERSION')

    # For Common library and headers.
    env.Install(os.path.join('$PREFIX', 'include/daos'), 'include/daos/tse.h')

    # Generic DAOS includes
    env.AppendUnique(CPPPATH=[Dir('include').srcnode()])
    env.AppendUnique(CPPPATH=[Dir('include')])
    base_env.AppendUnique(CPPPATH=[Dir('include').srcnode()])
    base_env.AppendUnique(CPPPATH=[Dir('include')])
    if base_env_mpi:
        base_env_mpi.AppendUnique(CPPPATH=[Dir('include').srcnode()])
        base_env_mpi.AppendUnique(CPPPATH=[Dir('include')])

    if not env.GetOption('clean') and not env.GetOption('help'):
        conf = env.Clone().Configure()
        # Detect if we have explicit_bzero
        if not conf.CheckFunc('explicit_bzero'):
            env.Append(CCFLAGS=['-DNEED_EXPLICIT_BZERO'])
            base_env.Append(CCFLAGS=['-DNEED_EXPLICIT_BZERO'])
        conf.Finish()

    for header in HEADERS:
        header_file = os.path.join('include', header)
        env.Install(os.path.join('$PREFIX', 'include'), header_file)
    if prereqs.server_requested():
        for header in HEADERS_SRV:
            header_file = os.path.join('include', 'daos_srv', header)
            env.Install(os.path.join('$PREFIX', 'include', 'daos_srv'), header_file)
    for header in HEADERS_GURT:
        check_install_header(env, os.path.join('include', 'gurt', header))
    for header in HEADERS_CART:
        check_install_header(env, os.path.join('include', 'cart', header))
    check_install_header(env, 'include/daos.h')

    env.Append(CCFLAGS=['-DCART_VERSION=\\"' + CART_VERSION + '\\"'])
    libdaos_tgts = []
    Export('env', 'CART_VERSION', 'libdaos_tgts')

    # Generate common libraries used by multiple components
    SConscript('gurt/SConscript')
    SConscript('cart/SConscript')
    SConscript('common/SConscript')
    SConscript('bio/SConscript')
    SConscript('vea/SConscript')
    SConscript('vos/SConscript')

    # Build each DAOS component
    SConscript('rsvc/SConscript')
    SConscript('mgmt/SConscript')
    SConscript('pool/SConscript')
    SConscript('container/SConscript')
    SConscript('placement/SConscript')
    SConscript('dtx/SConscript')
    SConscript('object/SConscript')
    SConscript('rebuild/SConscript')
    SConscript('security/SConscript')
    SConscript('pipeline/SConscript')

    # Build DAOS client libraries
    SConscript('client/SConscript')

    # rdb unit test rdbt depends on libdaos
    SConscript('rdb/SConscript')

    # Then the DAOS I/O Engine executable
    SConscript('engine/SConscript')

    # Build utilities
    SConscript('utils/SConscript')

    # Build the control plane components
    SConscript('control/SConscript')

    # Build test
    SConscript('placement/tests/SConscript')
    SConscript('tests/SConscript')

    if prereqs.client_requested():
        api_version = env.Command('API_VERSION', "SConscript", f"echo {API_VERSION} > $TARGET")
        env.Install("$PREFIX/lib64/daos", api_version)


if __name__ == "SCons.Script":
    scons()
