#!/usr/bin/env python
##
# @file
# This file is part of SeisSol.
#
# @section LICENSE
# Copyright (c) SeisSol Group
# All rights reserved.
# 
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
# 
# 1. Redistributions of source code must retain the above copyright notice,
#    this list of conditions and the following disclaimer.
# 
# 2. Redistributions in binary form must reproduce the above copyright notice,
#    this list of conditions and the following disclaimer in the documentation
#    and/or other materials provided with the distribution.
# 
# 3. Neither the name of the copyright holder nor the names of its
#    contributors may be used to endorse or promote products derived from this
#    software without specific prior written permission.
# 
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.

import os, os.path, sys, fnmatch

# option for machine file option
machineinfo = int(raw_input(' \
Choose compiler:\n\
\n\
  (1) x86_64\n\
  (2) SuperMUC\n\
  (3) Shaheen\n\
  (4) TETHYS\n\
  (5) FRAM (CalTech)\n\
  (6) MAC (iwalter)\n\
  (7) Shaheen with HDF5\n\
  (8) Shaheen with OpenMP (Global Time Stepping only) \n\
  (9) x86_64 with OpenMP (Global Time Stepping only) \n\
 (10) x86_64 DEBUG option \n\
 (11) SuperMUC with HDF5\n\
 (12) x86_64 ubuntu laptop\n\
 (13) x86_64 with HDF5\n\
\n\
'))

#
# Functions
#

def Glob(match):
    """Similar to glob.glob, except globs SCons nodes, and thus sees
    generated files and files from build directories.  Basically, it sees
    anything SCons knows about.  A key subtlety is that since this function
    operates on generated nodes as well as source nodes on the filesystem,
    it needs to be called after builders that generate files you want to
    include."""
    def fn_filter(node):
        fn = str(node)
        return fnmatch.fnmatch(os.path.basename(fn), match)

    here = Dir('.')

    children = here.all_children()
    nodes = map(File, filter(fn_filter, children))
    node_srcs = [n.srcnode() for n in nodes]

    src = here.srcnode()
    if src is not here:
        src_children = map(File, filter(fn_filter, src.all_children()))
        for s in src_children:
            if s not in node_srcs:
                nodes.append(File(os.path.basename(str(s))))

    return nodes

#
# Paths
#
subdirs = ['Reader', 'Physics', 'Geometry', 'Numerical_aux', 'Initializer', 'Solver', 'ResultWriter']
modpath = map(lambda d: os.path.join('#/build',d), subdirs)

#
# Environment
#
if machineinfo == 1:
# x86_64

  env = Environment(
    ENV = {'PATH' :  os.environ['PATH']},
	  F90PATH = modpath,
	  F90='mpif90.openmpi',
	  FORTRAN='mpif90.openmpi',
	  LINK = 'mpif90.openmpi',
	  LIBS = 'stdc++',
	  CXX = 'mpicxx.openmpi',
	  CPPFLAGS = '-fast -O2 -ftz -align -fno-alias -DPARALLEL',
	  F90FLAGS = '-no-offload -fpp -r8 -O2 -ftz -align -fno-alias -DPARALLEL')
	  
  env.PrependENVPath( 'OMPI_FC', os.getenv('INTEL_BASE') + '/bin/intel64/ifort')
  env.PrependENVPath( 'OMPI_CXX', os.getenv('INTEL_BASE') + '/bin/intel64/icpc')
  env['ENV']['OMPI_CFLAGS'] = '-I/usr/lib/openmpi/include'
  env['ENV']['OMPI_FFLAGS'] = '-I/usr/lib/openmpi/include'
  env['ENV']['OMPI_LDFLAGS'] = '-I/usr/lib/openmpi/lib -L/usr/lib -L/usr/lib/openmpi/lib -lmpi_f90 -lmpi_f77 -lmpi -ldl -lhwloc'
  env['ENV']['INTEL_LICENSE_FILE'] = os.getenv('INTEL_LICENSE_FILE')

elif machineinfo == 2:
# SuperMUC
#
# load before compiling:
# module unload fortran
# module unload ccomp
# module load ccomp/intel/13.1
# module load fortran/intel/13.1
  print 'ATTENTION 1:  module load ccomp/intel/13.1, module load fortran/intel/13.1  before compiling'
  print 'ATTENTION 2:  add the same module loading also to your batch script'

  env = Environment(
    ENV = {'PATH' :  os.environ['PATH']},
	  F90PATH = modpath,
	  F90='mpif90',
	  FORTRAN='mpif90',
	  LINK = 'mpif90',
      LIBS = 'stdc++',
      CXX = 'mpiCC',
      CPPFLAGS = '-fast -O2 -ftz -align -fno-alias -DPARALLEL',
	  F90FLAGS = '-no-offload -fpp -r8 -O2 -ftz -align -fno-alias -DPARALLEL',)

  env['ENV']['INTEL_LICENSE_FILE'] = '/lrz/sys/intel/licenses'

elif machineinfo == 3:
# Shaheen

  env = Environment(
        ENV = {'PATH' :  os.environ['PATH']},
        F90PATH = modpath,
        F90='mpixlf90_r',
        FORTRAN='mpixlf90_r',
        LINK = 'mpixlf90_r',
        F90FLAGS = '-no-offload -d -qsuffix=cpp=f90 -qrealsize=8 -WF,-DPARALLEL -qstrict -qzerosize  -qfree=f90 -qnosave -O2 -qhot -qtune=auto -qarch=auto',
        FORTRANFLAGS = '-no-offload -qfixed=72 -d -qsuffix=cpp=f90 -qrealsize=8 -WF,-DPARALLEL -qstrict -qnosave -O2 -qhot -qtune=auto -qarch=auto',)

elif machineinfo == 4:
# TETHYS

  env = Environment(
     ENV = {'PATH' :  os.environ['PATH']},
	F90PATH = modpath,
	F90='mpif90.openmpi',
	FORTRAN='mpif90.openmpi',
	LINK = 'mpif90.openmpi',
        LIBS = 'stdc++',
        CXX = 'mpicxx.openmpi',
        CPPFLAGS = '-fast -O2  -ftz -align -fno-alias -DPARALLEL',	
        F90FLAGS = '-no-offload -fpp -r8 -O2 -ftz -align -fno-alias -DPARALLEL',)

  env['ENV']['OMPI_FC'] = '/opt/intel/composer_xe_2013.4.183/bin/intel64/ifort'
  env['ENV']['OMPI_CXX'] = '/opt/intel/composer_xe_2013.4.183/bin/intel64/icpc'

elif machineinfo == 5:
# FRAM

  env = Environment(
     ENV = {'PATH' :  os.environ['PATH']},
        F90PATH = modpath,
        F90='mpiifort',
        FORTRAN='mpiifort',
        LINK = 'mpiifort',
        F90FLAGS = '-fpp -r8 -O2 -ftz -align -fno-alias -DPARALLEL',)

  env['ENV']['LD_LIBRARY_PATH'] = os.environ['LD_LIBRARY_PATH']

elif machineinfo == 6:
# MAC

  env = Environment(
    ENV = {'PATH' :  os.environ['PATH']},
          F90PATH = modpath,
          F90='mpif90',
          FORTRAN='mpif90',
          LINK = 'mpif90',
          F90FLAGS = '-fpp -r8 -O2 -ftz -align -fno-alias -DPARALLEL',)
          #F90FLAGS = '-O2 -xHost -fno-alias -vec-report -ftz -align -fpp -r8 -DPARALLEL',)

elif machineinfo == 7:
# Shaheen with HDF5 support
# load first corresponding modules:
# module load ibm
# module load bluegene hdf5/1.8.9/ibm

  print 'ATTENTION:  load: module load bluegene hdf5/1.8.9/ibm before compiling'

  env  = Environment(
        ENV = {'PATH' :  os.environ['PATH']},
        F90PATH = modpath,
        F90='mpixlf90_r',
        FORTRAN='mpixlf90_r',
        LINK = 'mpixlf90_r',
        LIBPATH=['/opt/share/hdf5/1.8.9/bgp-ibm/lib', '/opt/share/zlib/1.2.5/bgp-ibm/lib'],
        LIBS = ['hdf5_fortran', 'hdf5', 'z'],
        F90FLAGS = '-no-offload -d -qsuffix=cpp=f90 -qrealsize=8 -WF,-DPARALLEL -WF,-DHDF -qstrict -qzerosize  -qfree=f90 -qnosave -O2 -qhot -qtune=auto -qarch=auto -L/opt/share/hdf5/1.8.9/bgp-ibm/lib -L/opt/share/zlib/1.2.5/bgp-ibm/lib  -lhdf5_fortran -lhdf5 -lz -I/opt/share/hdf5/1.8.9/bgp-ibm/include',
        FORTRANFLAGS = '-no-offload -qfixed=72 -d -qsuffix=cpp=f90 -qrealsize=8 -WF,-DPARALLEL -WF,-DHDF -qstrict -qnosave -O2 -qhot -qtune=auto -qarch=auto -L/opt/share/hdf5/1.8.9/bgp-ibm/lib -L/opt/share/zlib/1.2.5/bgp-ibm/lib  -lhdf5_fortran -lhdf5 -lz -I/opt/share/hdf5/1.8.9/bgp-ibm/include',
	HDF5 = 'ON',)
elif machineinfo == 8:
# Shaheen

  env = Environment(
        ENV = {'PATH' :  os.environ['PATH']},
        F90PATH = modpath,
        F90='mpixlf90_r',
        FORTRAN='mpixlf90_r',
        LINK = 'mpixlf90_r -qsmp=omp',
        F90FLAGS = '-no-offload -d -qsuffix=cpp=f90 -qrealsize=8 -WF,-DPARALLEL -WF,-DOMP -qstrict -qzerosize  -qfree=f90 -qnosave -O2 -qhot -qtune=auto -qarch=auto -qsmp=omp',
        FORTRANFLAGS = '-no-offload -qfixed=72 -d -qsuffix=cpp=f90 -qrealsize=8 -WF,-DPARALLEL -WF,-DOMP -qstrict -qnosave -O2 -qhot -qtune=auto -qarch=auto -qsmp=omp',)

  Export('env')

elif machineinfo == 9:
# x86_64 with openMP
# note LINK argument: -openmp
# Specify number of threads N with export OMP_NUM_THREADS=N

  print 'ATTENTION:  Specify number of threads N with export OMP_NUM_THREADS=N before running the job!'

  env = Environment(
    ENV = {'PATH' :  os.environ['PATH']},
	  F90PATH = modpath,
	  F90='mpif90.openmpi',
	  FORTRAN='mpif90.openmpi',
	  LINK = 'mpif90.openmpi -openmp',
	  LIBS = 'stdc++',
	  CXX = 'mpicxx.openmpi',
	  CPPFLAGS = '-fast -O2 -ftz -align -fno-alias -DPARALLEL',
	  F90FLAGS = '-no-offload -fpp -r8 -O2 -ftz -align -fno-alias -DPARALLEL -DOMP -openmp')

  env.PrependENVPath( 'OMPI_FC', os.getenv('INTEL_BASE') + '/bin/intel64/ifort')
  env.PrependENVPath( 'OMPI_CXX', os.getenv('INTEL_BASE') + '/bin/intel64/icpc')
  env['ENV']['OMPI_CFLAGS'] = '-I/usr/lib/openmpi/include'
  env['ENV']['OMPI_FFLAGS'] = '-I/usr/lib/openmpi/include'
  env['ENV']['OMPI_LDFLAGS'] = '-I/usr/lib/openmpi/lib -L/usr/lib -L/usr/lib/openmpi/lib -lmpi_f90 -lmpi_f77 -lmpi -ldl -lhwloc'
  env['ENV']['INTEL_LICENSE_FILE'] = os.getenv('INTEL_LICENSE_FILE')

elif machineinfo == 10:
# x86_64 Debug option

  env = Environment(
    ENV = {'PATH' :  os.environ['PATH']},
	  F90PATH = modpath,
	  F90='mpif90.openmpi',
	  FORTRAN='mpif90.openmpi',
	  LINK = 'mpif90.openmpi',
	  LIBS = 'stdc++',
	  CXX = 'mpicxx.openmpi',
	  CPPFLAGS = '-g -O0 -ftz -align -fno-alias -DPARALLEL',
	  F90FLAGS = '-no-offload -fpp -r8 -O0 -g -traceback -check all -ftz -align -fno-alias -DPARALLEL')
	  
  env.PrependENVPath( 'OMPI_FC', os.getenv('INTEL_BASE') + '/bin/intel64/ifort')
  env.PrependENVPath( 'OMPI_CXX', os.getenv('INTEL_BASE') + '/bin/intel64/icpc')
  env['ENV']['OMPI_CFLAGS'] = '-I/usr/lib/openmpi/include'
  env['ENV']['OMPI_FFLAGS'] = '-I/usr/lib/openmpi/include'
  env['ENV']['OMPI_LDFLAGS'] = '-I/usr/lib/openmpi/lib -L/usr/lib -L/usr/lib/openmpi/lib -lmpi_f90 -lmpi_f77 -lmpi -ldl -lhwloc'
  env['ENV']['INTEL_LICENSE_FILE'] = os.getenv('INTEL_LICENSE_FILE')
  


elif machineinfo == 11:
# SuperMUC with HDF5 support
# first load corresponding modules:
# module load hdf5/mpi

  print 'ATTENTION:  load: module load hdf5/mpi before compiling'
  print '            and add this also in batch script module load hdf5/mpi before execute statement'

  env = Environment(
        ENV = {'PATH' : os.environ['PATH']},
        HDF5_LIB = os.environ['HDF5_SHLIB'],
        HDF5_F90_LIB = os.environ['HDF5_F90_SHLIB'],
        SZIP_LIB = os.environ['SZIP_LIB'],
        HDF5_INC = os.environ['HDF5_INC'],
        F90PATH = modpath,
        F90='mpif90',
        FORTRAN='mpif90',
        LINK = 'mpif90 ${HDF5_F90_LIB} ${HDF5_LIB} $SZIP_LIB -lz',
        LIBS = 'stdc++',
        CXX = 'mpiCC',
        CPPFLAGS = '-fast -O2 -ftz -align -fno-alias -DPARALLEL',
        F90FLAGS = '-no-offload -fpp -r8 -O2 -ftz -align -nbs -fno-alias -DPARALLEL -DHDF ${HDF5_INC}',
        HDF5 = 'ON',)

  env['ENV']['INTEL_LICENSE_FILE'] = '/lrz/sys/intel/licenses'

elif machineinfo == 12:
# x86_64 ubuntu laptop

  env = Environment(
    #ENV = {'PATH' :  os.environ['PATH']})
	  F90PATH = modpath,
	  F90='mpif90',
	  FORTRAN='mpif90',
	  LINK = 'mpif90',
	  LIBS = 'stdc++',
	  CXX = 'mpicxx',
	  CPPFLAGS = '-fast -O2 -ftz -align -fno-alias -DPARALLEL',
	  F90FLAGS = '-no-offload -fpp -r8 -O2 -ftz -align -fno-alias -DPARALLEL')

  env.AppendENVPath('PATH', os.environ['PATH'])

  env['ENV']['I_MPI_F90'] = '/opt/intel/bin/ifort'
  env['ENV']['I_MPI_CXX'] = '/opt/intel/bin/icc'
  env['ENV']['MPI_FC'] = '/opt/intel/impi/4.1.0.030/intel64/bin/mpif90'
  env['ENV']['MPI_CXX'] = '/opt/intel/impi/4.1.0.030/intel64/bin/mpicxx'
  env['ENV']['OMPI_FC'] = '/work/intel/composerxe/bin/ifort'
  env['ENV']['OMPI_CXX'] = '/work/intel/composerxe/bin/icpc'

elif machineinfo == 13:
# x86_64 with HDF5

  env = Environment(
    ENV = {'PATH' :  os.environ['PATH']},
      HDF5_LIB = '-L' + os.environ['HOME'] + '/lib -lhdf5 -lhdf5_fortran',
      HDF5_INC = '-I' + os.environ['HOME'] + '/include',
      F90PATH = modpath,
      F90='mpiifort ${HDF5_INC}',
      FORTRAN='mpiifort ${HDF5_INC}',
      LINK = 'mpiifort ${HDF5_LIB}',
      LIBS = 'stdc++',
      CXX = 'mpiicpc',
      CPPFLAGS = '-fast -O2 -ftz -align -fno-alias -DPARALLEL',
	  F90FLAGS = '-no-offload -fpp -r8 -O2 -ftz -align -fno-alias -DPARALLEL -DHDF',
#       CPPFLAGS = '-g -O0 -ftz -align -fno-alias -DPARALLEL',
#       F90FLAGS = '-g -debug -fpe0 -fp-stack-check -traceback -debug extended -debug-parameters all -fpp -r8 -O0 -check all -ftz -align -fno-alias -DPARALLEL -DHDF',
      HDF5 = 'ON',)

#elif machineinfo == 14:
 # add new options if necessary...

else:

  print 'SConstruct: compiler option not found!'
  sys.exit(1)

# if end

# default 'info'-log level
if machineinfo == 7:
  env.Append(F90FLAGS=' -WF,-DLOGLEVEL=2')
else :
  env.Append(F90FLAGS=' -DLOGLEVEL=2')

# Add src and submodules directory to search path for includes
env.Append(CPPPATH=['#/', '#../submodules'])

#
# Build dependency tree
#
allobjs = []
for sd in subdirs:
    buildDir = os.path.join('build',sd)
    consFile = os.path.join(buildDir,'SConscript')
    env.VariantDir(buildDir, sd)
    allobjs = allobjs + env.SConscript(consFile, exports=['env','Glob'])



#
# Remove any mod files. These should not be passed to the linker.
#
objs = filter(lambda o: str(o)[-4:] != '.mod', allobjs)


#
# Add an action to move any module files
#
def moveModFiles(target=None, source=None, env=None):
    import glob, os, os.path
    targetdir = target[0].dir
    for t in target:
        if t.name[-4:] == '.mod':
            os.rename(t.name,os.path.join(str(targetdir),t.name))

env.AddPostAction(objs, moveModFiles)

#
# Build program
#
env.Program('seissolxx', ['seissolxx.f90', 'SeisSol.cpp'] + objs )
