import os
Import('env')

# 
# Need to make a copy because SCons uses the environment
# at it's final state, so StGermain ends up depending on
# StgDomain, etc. 
#

env = env.Clone()
env['CURR_PROJECT'] = "Solvers"

#
# Inside each project we will be accessing headers without the
# project name as a prefix, so we need to let SCons know how to
# find those headers.
#

env.Append(CPPPATH=env['build_dir'] + '/include/Solvers')

#
# Need to include the Solvers library for binaries/plugins.
#

libs = ['Solvers'] + env.get('LIBS', [])

#
# Keep a list of all the objects we build so we can make a library
# afterwards.
#

objs = []
suites = []
tst_exp = []
tst_input = []


#
# Process each directory uniformly.
#

dirs = Split('Assembly SLE KSPSolvers libSolvers')                        
for d in dirs:

    # Need the module name, which is just the directory.
    mod_name = env['ESCAPE']('"' + ''.join(d.split('/')) + '"')
    cpp_defs = [('CURR_MODULE_NAME', mod_name)] + env.get('CPPDEFINES', [])

    # Setup where to look for files.
    src_dir = d + '/src'
    inc_dir = 'include/Solvers/' + d
    tst_dir = d + '/tests'
    tst_exp_dir = tst_dir + '/expected'
    tst_input_dir = tst_dir + '/input'
    tst_install_dir = 'tests/Solvers/' + d

    # Install the headers and '.def' files.
    hdrs = env.Install(os.path.join(env['build_dir'],inc_dir), Glob(src_dir + '/*.h'))

    # Build our source files.
    srcs = Glob(src_dir + '/*.c')
    srcs = [s for s in srcs if s.path.find('-meta.c') == -1]
    for src in srcs:
        stg_cpp_defs = cpp_defs + [('SOURCE_FILE', '"\\"' + src.name + '\\""')]
        objs += env.SharedObject(src, CPPDEFINES=stg_cpp_defs)

    # Build any test suites we might find.
    # suites += env.Object(Glob(tst_dir + '/*Suite.c'))

    # Install any test expected and input files
    # tst_exp += env.Install(os.path.join(env['build_dir'],tst_install_dir,'/expected'), Glob(tst_exp_dir + '/*'))
    # tst_input += env.Install(os.path.join(env['build_dir'],tst_install_dir,'/input'), Glob(tst_input_dir + '/*'))
#
# Process each directories of chosen dirs.
#
#
# Will return list of directory names that reside in given 'dir'
# 'dir' is a relative directory to this repository (e.g. relative to Solvers)
# If one of these dirs is = "archive" then it is left out
def getsubdirs(dir):
    subdirs=[]
    #cwd=os.getcwd() # gets cwd for build dir, not source dir here
    cwd=Dir('#').abspath + '/Solvers'
    fullpath=cwd+'/'+dir # absolute path
    tmp=os.listdir(fullpath)
    for x in tmp:
        if os.path.isdir(fullpath+'/'+x):
            if 'archive'!=x.lower(): # convert to lowercase. So Archive, ARChive etc get ignored
                subdirs.append(x)
    return subdirs
     
import glob

dirstr='KSPSolvers'
topdirs = dirstr.split()
for dir in topdirs:
    subdirs=getsubdirs(dir+'/src') # it appears we cannot use scons' Glob to get a list of directories?
    for d in subdirs:
        # Need the module name, which is just the directory.
        subdir = d
        d = dirstr + '/' + subdir # setting d here to e.g. KSPSolvers/BSSCR
        mod_name = env['ESCAPE']('"' + ''.join(d.split('/')) + '"')
        cpp_defs = [('CURR_MODULE_NAME', mod_name)] + env.get('CPPDEFINES', []) 

        # Setup where to look for files.
        src_dir = dirstr + '/src/' + subdir   # e.g. KSPSolvers/src/BSSCR

        inc_dir = 'include/Solvers/' + d # e.g. KSPSolvers/BSSCR
        tst_dir = d + '/tests'
        tst_exp_dir = tst_dir + '/expected'
        tst_input_dir = tst_dir + '/input'
        tst_install_dir = 'tests/Solvers/' + d
        
        # Glob returns a list of Nodes that represent the absolute locations of files
        # Install the headers and '.def' files.
        hdrs = env.Install(os.path.join(env['build_dir'],inc_dir), Glob(src_dir + '/*.h'))

        # Build our source files.
        srcs = Glob(src_dir + '/*.c')
        srcs = [s for s in srcs if s.path.find('-meta.c') == -1]
        objs += env.SharedObject(srcs, CPPDEFINES=cpp_defs)

        # Build any test suites we might find.
        suites += env.Object(Glob(tst_dir + '/*Suite.c'))
        
        # Install any test expected and input files
        tst_exp += env.Install(os.path.join(env['build_dir'],tst_install_dir,'/expected'), Glob(tst_exp_dir + '/*'))
        tst_input += env.Install(os.path.join(env['build_dir'],tst_install_dir,'/input'), Glob(tst_input_dir + '/*'))

# Need to install headers from libSolvers.
env.Install(os.path.join(env['build_dir'],'include/Solvers'), Glob('libSolvers/src/*.h'))

#
# Build Toolbox.
#

dirs = ['libSolvers/Toolbox']
pl_objs = []
pl_regs = []
for d in dirs:

    name = 'Solvers_' + d.split('/')[-1] + 'module'
    mod_name = env['ESCAPE']('"' + ''.join(d.split('/')) + '"')
    cpp_defs = [('CURR_MODULE_NAME', mod_name)] + env.get('CPPDEFINES', [])

    env.Install(os.path.join(env['build_dir'],'include/Solvers/',d.split('/')[-1]), Glob(d + '/*.h'))

    srcs = Glob(d + '/*.c')
    srcs = [s for s in srcs if s.path.find('-meta.c') == -1]
    cur_objs = env.SharedObject(srcs, CPPDEFINES=cpp_defs)

    # If we have shared libraries, build the dynamic plugin.
    if env['shared_libs']:
        lib_pre = env['LIBPREFIXES']
        if not isinstance(lib_pre, list):
            lib_pre = [lib_pre]
        env.SharedLibrary('lib/' + name, cur_objs,
                          SHLIBPREFIX='',
                          LIBPREFIXES=lib_pre + [''],
                          LIBS=libs)

    # If we are building static libs we need to construct a C file
    # mapping the plugin's name to its register function.
    if env['static_libs']:
        pl_regs += [name]

    # Keep track of all the plugin objects.
    pl_objs += cur_objs


#
# Build shared library.
#

if env['shared_libs']:
    env.SharedLibrary('lib/Solvers', objs)
    env.SharedLibrary(env['prefix'] + '/lib/Solvers', objs)

