# vim: set filetype=python :

import os, sys
import glob

try:
    sys.path = [GetBuildPath('#galsim')] + sys.path
    from _version import __version__ as version
    from _version import __version_info__ as version_info
    sys.path.nada()
except:
    # If SCons is using an old python (2.4 is relatively common still), then the above may fail.
    # In this case, we need to be a little trickier.
    execfile(os.path.join(GetBuildPath('#galsim'),'_version.py'))
    version = __version__
    version_info = __version_info__


Import('env')
ReadFileList = env['_ReadFileList']

env1 = env.Clone()

# TODO: This won't work on Windows machines...
env1['OBJPREFIX'] = '.obj/'

env1.Prepend(CPPPATH=[os.path.join('#include','galsim')])

lib_dir = 'lib'
header_dir = 'include'
lib_install_dir = os.path.join(env1['INSTALL_PREFIX'], lib_dir)
header_install_dir = os.path.join(env1['INSTALL_PREFIX'], header_dir)

subdirs = ['.','hsm']

lib_files = []
for d in subdirs:
    # This file is typicall created by:
    # ls *.cpp > files.txt
    # in each subdirectory.  But after that, it allows you to remove a file from
    # being included in the library by just deleting it from files.txt, rather
    # than having to delete the .cpp file.
    lib_files1 = ReadFileList(os.path.join(d,'files.txt'))
    for f in lib_files1:
        lib_files += [os.path.join(d,f)]

if env1['MEM_TEST']:
    print 'Using mmgr.cpp'
    # put mmgr.cpp first, so its static variable is the first one registered.
    # otherwise the memory leak reports a bunch of static variables being leaks.
    lib_files.insert(0, 'mmgr.cpp')

# Library file containing generic code
obj_lib = env1.SharedObject(lib_files)

print 'GalSim version ',version

# Make sure the version tuple has 3 elements.
if len(version_info) == 2:
    version_info += (0,)
else:
    assert len(version_info) == 3

compat_version = version_info[:2]

lib_final_dir = os.path.join(env['FINAL_PREFIX'],'lib')

if sys.platform == 'darwin':
    # Some stuff to get it to set the right compatibility version and library name:
    lib_final_name = os.path.join(lib_final_dir,'libgalsim.%s.%s.dylib'%compat_version)
    lib_full_name = os.path.join(GetBuildPath('#lib'),'libgalsim.%s.%s.dylib'%compat_version)
    link_name = os.path.join(GetBuildPath('#lib'),'libgalsim.dylib')
    # TODO: If we have more than one lib, we need a different SHLINKFLAGS for each one.
    # The easiest way to do this is to have multiple environments that differ in their
    # SHLINKFLAGS values.  For now we just have the one, so this is fine.
    env1.AppendUnique( SHLINKFLAGS=[
        '-dynamic',
        '-Wl,-install_name,%s'%lib_final_name,
        '-Wl,-compatibility_version,%s.%s'%compat_version,
        '-Wl,-current_version,%s.%s.%s'%version_info ] )
    env1.Replace(SHLIBSUFFIX = '.%s.%s.dylib'%compat_version)

elif sys.platform.startswith('linux'):  # Should work for both linux2 and linux3
    # On linux, we don't need to include the other libraries here.  They need to be 
    # linked for compiling any executable, but not for building the library.
    # However, if any of the other libraries are static, it causes an error on some 
    # systems to include them here with the usual -llib_name.  But we do need to
    # include the static libraries here, since python won't be able to load them
    # dynamically at run time and we need the resolve the symbols from them that 
    # we use.  Otherwise we get undefined symbol errors when importing galsim.
    # To do this, we need the full path name to the library file.  So we loop 
    # through the library search path looking for each library.  If there is a 
    # shared library, we're fine, but if not and we find a static library, then 
    # we need to include it explicitly in the linking step for libgalsim.so. 
    # This may fail if the static libraries were not compiled if -fPIC, but I 
    # don't currently know a way to check for this.  
    # Update: Some linux systems do require the shared libraries to be linked here,
    # and it doesn't seem to be a problem for the ones that don't require it.
    # Still need the static libraries to be special though.

    libs = env1['LIBS']
    lib_path = ['/usr/local/lib']
    lib_path += env1['LIBPATH']
    new_libs = []
    #print 'libs = ',libs
    for lib in libs:
        #print 'Looking for lib = ',lib
        found = False
        for dir in lib_path:
            shared_lib_name = os.path.join(dir,'lib' + lib + '.so')
            if os.path.isfile(shared_lib_name) and os.access(shared_lib_name, os.R_OK):
                #print 'Found shared library: ',shared_lib_name
                new_libs += [ lib ]
                found = True
                break

            static_lib_name = os.path.join(dir,'lib' + lib + '.a')
            if os.path.isfile(static_lib_name) and os.access(static_lib_name, os.R_OK):
                print 'Found static library: ',static_lib_name
                new_libs += [ File(static_lib_name) ]
                found = True
                break
        if not found:
            #print lib,'does not match either shared or static name.  Assuming shared.'
            new_libs += [ lib ]

    # Removes all -l lib flags, and add the explicit static library files.
    env1.Replace(LIBS=new_libs)

    lib_final_name = 'libgalsim.so.%s.%s'%compat_version
    lib_full_name = os.path.join(GetBuildPath('#lib'),'libgalsim.so.%s.%s'%compat_version)
    link_name = os.path.join(GetBuildPath('#lib'),'libgalsim.so')
    env1.AppendUnique(SHLINKFLAGS=['-Wl,-soname,%s'%lib_final_name ])
    env1.Replace(SHLIBSUFFIX = '.so.%s.%s'%compat_version)

elif sys.platform == 'win32':
    raise ValueError('Sorry, building on windows is not supported yet...')

else:
    raise ValueError('Sorry, building on platform ',sys.platform,' is not supported yet.')

lib = env1.SharedLibrary(os.path.join('#lib','galsim'), obj_lib)

def SymLink(target, source, env):
    t = os.path.abspath(str(target[0]))
    if os.path.lexists(t): os.remove(t)
    os.symlink(env['LibName'], t)

# This just makes a link in the #lib directory.  Need to redo this in the install directory.
link = env1.Command( link_name , lib , SymLink, LibName=lib_full_name)
Default(link)

lib_targets = [lib]
Default(lib_targets)

tools = [ 'sizeof_SIFD' ]
tool_targets = [ env1.Program(os.path.join('#bin/',tool), tool + '.cpp') for tool in tools ]

# These don't need to be installed.  Leave them in the GalSim/bin directory.
Default(tool_targets)

if 'install' in COMMAND_LINE_TARGETS:

    installed_lib = env1.Install(dir=lib_install_dir, source=lib_targets)

    installed_link_name = os.path.join(lib_install_dir, os.path.basename(link_name))
    installed_link = env1.Command( installed_link_name, installed_lib, SymLink,
        LibName=lib_final_name)

    env1.Alias(target='install', source=[installed_lib, installed_link])
    env['all_builds'] += installed_lib
    env['all_builds'] += installed_link

    #hfiles1 = os.listdir(GetBuildPath('#include'))
    #hfiles = []
    #for f in hfiles1:
        #hfiles += [os.path.join('#include',f)]
    #installed_h = env1.Install(dir=header_install_dir, source=hfiles)
    #env1.Alias(target='install', source=installed_h)
else:
    env['all_builds'] += lib
    env['all_builds'] += link


if 'uninstall' in COMMAND_LINE_TARGETS:
    # There is no env.Uninstall method, we must build our own
    # MJ: The scons delete function doesn't actually delete directories a la rm -rf
    # I think this is a feature they will add someday, so maybe not worth worrying about it.
    # but if we really want the galsim directory to be deleted on an uninstall, we
    # should change this.  Proabaly roll our own Delete function.
    deltarget = Delete("$TARGET")

    #hfiles = os.listdir(GetBuildPath('#include'))
    #for f in hfiles:
        #env1.Alias('uninstall', env1.Command(os.path.join(header_install_dir,f), None, deltarget))

    libfiles = [os.path.join(lib_install_dir, os.path.basename(str(f[0]))) for f in lib_targets]

    for f in libfiles:
        env1.Alias('uninstall', env1.Command(f, None, deltarget))


