#!/usr/bin/env python
import optparse, os, subprocess, sys
from sys import stdout

chplenv_dir = os.path.dirname(__file__)
sys.path.insert(0, os.path.abspath(chplenv_dir))

from chplenv import *

def print_mode(mode='list'):
    print_var.first_time = True
    # `m` is a 'simplified' version of `mode` that merges some cases that can
    # be treated the same by print_mode, but need to be dealt with separately
    # in print_var
    m = mode
    if 'shell' in mode:
        #cshell and shell are the same up until we print
        m = 'shell'
    elif mode == 'simple' or mode == 'debug':
        # make and simple are almost the same barring a few cases and when they
        # are printed
        m = 'make'

    chpl_home = os.environ.get('CHPL_HOME', '')
    chpl_module_home = os.environ.get('CHPL_MODULE_HOME', '')

    if m == 'list' or mode == 'debug':
        stdout.write("machine info: {0} {1} {2} {3} {4}\n".format(*os.uname()))
        stdout.write("CHPL_HOME: {0} *\n".format(chpl_home))
        this_dir = os.path.realpath(os.path.dirname(__file__))
        stdout.write("script location: {0}\n".format(this_dir))
    elif chpl_home and m == 'shell':
        print_var('CHPL_HOME', chpl_home, mode)

    if m != 'runtime' and m != 'list':
        host_platform = chpl_platform.get('host')
        host_compiler = chpl_compiler.get('host')
        #host_arch = arch.get('host')

        print_var('CHPL_HOST_PLATFORM', host_platform, mode)
        print_var('CHPL_HOST_COMPILER', host_compiler, mode)
        # print_var('CHPL_HOST_ARCH', host_arch, mode, 'arch')

    if m != 'compiler' and m != 'launcher':
        target_platform = chpl_platform.get('target')
        target_compiler = chpl_compiler.get('target')

        print_var('CHPL_TARGET_PLATFORM', target_platform, mode)
        print_var('CHPL_TARGET_COMPILER', target_compiler, mode)

    get_module_lcd = ( utils.using_chapel_module() and
                     (mode == 'runtime' or mode == 'make') )
    if m != 'compiler' and m != 'launcher':
        target_arch = chpl_arch.get('target', mode == 'make', get_module_lcd)
        print_var('CHPL_TARGET_ARCH', target_arch, mode, 'arch')

    if m != 'compiler':
        locale_model = chpl_locale_model.get()
        print_var('CHPL_LOCALE_MODEL', locale_model, mode, 'loc')

    comm = chpl_comm.get()
    print_var('CHPL_COMM', comm, mode, 'comm', ('runtime', 'launcher'))
    if m == 'make' or (comm != 'none' and comm != 'ugni'):
        comm_substrate = chpl_comm_substrate.get()
        print_var('  CHPL_COMM_SUBSTRATE', comm_substrate, mode, filters=('runtime',))
        if m == 'make' or comm == 'gasnet':
            comm_segment = chpl_comm_segment.get()
            print_var('  CHPL_GASNET_SEGMENT', comm_segment, mode, filters=('runtime',))

    tasks = chpl_tasks.get()
    print_var('CHPL_TASKS', tasks, mode, 'tasks', ('runtime', 'launcher'))

    launcher = chpl_launcher.get()
    print_var('CHPL_LAUNCHER', launcher, mode, 'launch', ('launcher',))

    timers = chpl_timers.get()
    print_var('CHPL_TIMERS', timers, mode, 'tmr', ('runtime', 'launcher'))

    target_mem = chpl_mem.get('target')
    if mode == 'make':
        host_mem = chpl_mem.get('host')
        print_var('CHPL_HOST_MEM', host_mem, mode, 'hostmem', ('runtime', 'launcher'))
        print_var('CHPL_TARGET_MEM', target_mem, mode, 'tgtmem', ('runtime', 'launcher'))
    else:
        print_var('CHPL_MEM', target_mem, mode, 'mem', ('runtime', 'launcher'))

    if m == 'list' or m == 'make' or m == 'shell':
        make = chpl_make.get()
        print_var('CHPL_MAKE', make, mode, 'make')

    atomics = chpl_atomics.get()
    print_var('CHPL_ATOMICS', atomics, mode, 'atomics', ('runtime', 'launcher'))
    if (mode != 'runtime' and mode != 'make' and mode != 'launcher') and comm != 'none' or mode == 'simple':
        net_atomics = chpl_atomics.get('network')
        print_var('  CHPL_NETWORK_ATOMICS', net_atomics, mode, filters=('runtime', 'launcher'))

    gmp = chpl_gmp.get()
    print_var('CHPL_GMP', gmp, mode, 'gmp', ('runtime',))

    hwloc = chpl_hwloc.get()
    print_var('CHPL_HWLOC', hwloc, mode, 'hwloc', ('runtime',))

    regexp = chpl_regexp.get()
    print_var('CHPL_REGEXP', regexp, mode, 're', ('runtime',))

    wide_pointers = chpl_wide_pointers.get()
    print_var('CHPL_WIDE_POINTERS', wide_pointers, mode, 'wide')
    if mode == 'make':
        wide_pointer_defines = chpl_wide_pointers.get('define')
        print_var('CHPL_WIDE_POINTERS_DEFINES', wide_pointer_defines, mode, 'widedef')

    if mode != 'list':
        llvm = chpl_llvm.get()
        print_var('CHPL_LLVM', llvm, mode, 'llvm', ('compiler',))

    aux_filesys = chpl_aux_filesys.get()
    if mode == 'make' or mode == 'runtime':
        tmp = aux_filesys.split(' ')
        tmp.sort()
        aux_filesys = "_".join(tmp)
    print_var('CHPL_AUX_FILESYS', aux_filesys, mode, 'fs', ('runtime',))

    # NOT using `m` here, 'simple' does not need these values
    if mode == 'make':
        stdout.write('CHPL_MAKE_COMPILER_SUBDIR=')
        print_mode('compiler')
        stdout.write('CHPL_MAKE_RUNTIME_SUBDIR=')
        print_mode('runtime')
        stdout.write('CHPL_MAKE_LAUNCHER_SUBDIR=')
        print_mode('launcher')

        link_args_3p = []

        print_var('  CHPL_GMP_UNIQ_CFG_PATH',
                  chpl_3p_gmp_configs.get_uniq_cfg_path(),
                  mode, filters=('runtime',))
        link_args_3p.extend(chpl_3p_gmp_configs.get_link_args(gmp))

        print_var('  CHPL_HWLOC_UNIQ_CFG_PATH',
                  chpl_3p_hwloc_configs.get_uniq_cfg_path(),
                  mode, filters=('runtime',))
        if hwloc == 'hwloc':
            link_args_3p.extend(chpl_3p_hwloc_configs.get_link_args())

        print_var('  CHPL_JEMALLOC_UNIQ_CFG_PATH',
                  chpl_3p_jemalloc_configs.get_uniq_cfg_path(),
                  mode, filters=('runtime',))
        if target_mem == 'jemalloc':
            link_args_3p.extend(chpl_3p_jemalloc_configs.get_link_args())

        print_var('  CHPL_MASSIVETHREADS_UNIQ_CFG_PATH',
                  chpl_3p_massivethreads_configs.get_uniq_cfg_path(),
                  mode, filters=('runtime',))
        if tasks == 'massivethreads':
            link_args_3p.extend(chpl_3p_massivethreads_configs.get_link_args())

        print_var('  CHPL_QTHREAD_UNIQ_CFG_PATH',
                  chpl_3p_qthreads_configs.get_uniq_cfg_path(),
                  mode, filters=('runtime',))
        if tasks == 'qthreads':
            link_args_3p.extend(chpl_3p_qthreads_configs.get_link_args())

        print_var('  CHPL_RE2_UNIQ_CFG_PATH',
                  chpl_3p_re2_configs.get_uniq_cfg_path(),
                  mode, filters=('runtime',))
        if regexp == 're2':
            link_args_3p.extend(chpl_3p_re2_configs.get_link_args())

        link_args_3p_dedup=[]
        for arg in reversed(link_args_3p):
            if arg not in link_args_3p_dedup:
                link_args_3p_dedup.append(arg)
        print_var('  CHPL_THIRD_PARTY_LINK_ARGS',
                  ' '.join(reversed(link_args_3p_dedup)),
                  mode, filters=('runtime',))

    elif m == 'compiler' or m == 'runtime' or m == 'launcher':
        stdout.write('\n')


def print_var(env_var, value, mode, short_name='', filters=None):
    if mode == 'list' or mode == 'debug':
        user_set = os.environ.get(env_var.strip(), '')
        if user_set:
          user_set = ' *'
        stdout.write("{1}: {2}{0}\n".format(user_set, env_var, value))
    elif mode == 'make':
        make_env_var = env_var.replace("CHPL_", "CHPL_MAKE_", 1).lstrip()
        stdout.write("{0}={1}\n".format(make_env_var, value))
    elif mode == 'simple':
        stdout.write("{0}={1}\n".format(env_var.strip(), value))
    elif mode == 'compiler' or mode == 'runtime' or mode == 'launcher':
        if not filters or mode in filters:
            if not print_var.first_time:
                stdout.write(".")
            else:
                print_var.first_time = False

            if not short_name or value.startswith(short_name):
                stdout.write(value)
            else:
                stdout.write("{0}-{1}".format(short_name, value))
    elif mode == 'shell':
        stdout.write("export {0}='{1}'\n".format(env_var, value))
    elif mode == 'cshell':
        stdout.write("setenv {0} '{1}'\n".format(env_var, value))
    else:
        raise ValueError("Invalid mode '{0}'".format(mode))


def _main():
    parser = optparse.OptionParser(
        usage='usage: %prog [--list|--make|--simple|--compiler|--runtime|--launcher|--sh|--csh|--debug]')

    parser.add_option('--list', action='store_const', dest='mode', default='list',
                      const='list',
                      help="print out a listing of the environment indicating "
                           "which options are user supplied with a * (default)")
    parser.add_option('--make', action='store_const', dest='mode', const='make',
                      help="print out a listing of the environment that is "
                           "used in the build process")
    parser.add_option('--simple', action='store_const', dest='mode', const='simple',
                      help="print out a listing of the environment that is "
                           "meant to be used in the compiler")
    parser.add_option('--compiler', action='store_const', dest='mode', const='compiler',
                      help="print out path component for compiler objects")
    parser.add_option('--runtime', action='store_const', dest='mode', const='runtime',
                      help="print out path component for runtime objects")
    parser.add_option('--launcher', action='store_const', dest='mode', const='launcher',
                      help="print out path component for launcher objects")
    parser.add_option('--sh', action='store_const', dest='mode', const='shell',
                      help="print out a sh/bash script to reproduce the environment")
    parser.add_option('--csh', action='store_const', dest='mode', const='cshell',
                      help="print out a csh/tcsh script to reproduce the environment")
    parser.add_option('--debug', action='store_const', dest='mode', const='debug',
                      help="print out a listing of the environment indicating "
                           "which options are user supplied with a *")

    (options, args) = parser.parse_args()

    print_mode(options.mode)


if __name__ == '__main__':
    _main()
