cmake_minimum_required(VERSION 2.8)

project(simiconductor)
set(VERSION 1.1.0)

include(${PROJECT_SOURCE_DIR}/cmake/Macros.cmake)
get_install_directory(LIBRARY_INSTALL_DIR)

include(CheckCXXCompilerFlag)
include(CheckIncludeFile)
include(CheckIncludeFileCXX)
include(CheckCXXSourceCompiles)

find_package(Shellp REQUIRED)
find_package(SerUt REQUIRED)
find_package(MOGAL REQUIRED)
find_package(OpenMP)
find_package(MPI)

set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${PROJECT_SOURCE_DIR}/cmake")

find_package(Qt4)
if (QT4_FOUND)
	set(SIMICONDUCTOR_CONFIG_QT4 "#define SIMICONDUCTOR_CONFIG_QT4")
	include(${QT_USE_FILE})
endif (QT4_FOUND)

find_package(GSL)
message(STATUS ${GSL_INCLUDE_DIR})
if (GSL_FOUND)
	set(TMP ON)
else ()
	set(TMP OFF)
endif (GSL_FOUND)
option(SIMICONDUCTOR_GSL "Enable GSL support" ${TMP})
if (SIMICONDUCTOR_GSL)
	add_definitions(-DSIMICONDUCTOR_HAVE_GSL)
	if (GSL_FOUND)
		include_directories(${GSL_INCLUDE_DIR})
	endif ()
endif (SIMICONDUCTOR_GSL)

find_package(OpenCL)
if (OPENCL_FOUND)
	set(SIMICONDUCTOR_CONFIG_OPENCL "#define SIMICONDUCTOR_CONFIG_OPENCL")
	include_directories(${OPENCL_INCLUDE_DIRS})
	check_include_file(OpenCL/cl.h SIMICONDUCTOR_FOUND_OPENCLCL_H)
	if (NOT SIMICONDUCTOR_FOUND_OPENCLCL_H)
		check_include_file(CL/cl.h SIMICONDUCTOR_FOUND_CLCL_H)
		if (NOT SIMICONDUCTOR_FOUND_CLCL_H)
			message(WARNING "OpenCL detected but neither OpenCL/cl.h nor CL/cl.h were found")
		endif (NOT SIMICONDUCTOR_FOUND_CLCL_H)
	else (NOT SIMICONDUCTOR_FOUND_OPENCLCL_H)
		add_definitions(-DOPENCL_OPENCL_CL_H)
	endif (NOT SIMICONDUCTOR_FOUND_OPENCLCL_H)
endif (OPENCL_FOUND)

add_additional_stuff(EXTRA_INCLUDES EXTRA_LIBS)

include_directories(${PROJECT_SOURCE_DIR}/SuiteSparse/KLU)
include_directories(${PROJECT_SOURCE_DIR}/SuiteSparse/AMD)
include_directories(${PROJECT_SOURCE_DIR}/SuiteSparse/UFconfig)
include_directories(${PROJECT_SOURCE_DIR}/SuiteSparse/COLAMD)
include_directories(${PROJECT_SOURCE_DIR}/SuiteSparse/BTF)

set(COMMONSOURCES 
	src/simulationstate.cpp
	src/cmdsimulation1dnew.cpp
	src/cmdsimulation2dnew.cpp
	src/simulation1d.cpp
	src/simulation1ddouble.cpp
	src/simulation1dnr.cpp
	src/simulation1dave.cpp
	src/simulation2d.cpp
	src/simulation2ddouble.cpp
	src/simulation2ddoublerel.cpp
	src/simulation2dnr2.cpp
	src/newtonraphsonsearch.cpp
	${PROJECT_SOURCE_DIR}/SuiteSparse/KLU/klu.c
	${PROJECT_SOURCE_DIR}/SuiteSparse/KLU/klu_analyze.c
	${PROJECT_SOURCE_DIR}/SuiteSparse/KLU/klu_analyze_given.c
	${PROJECT_SOURCE_DIR}/SuiteSparse/KLU/klu_defaults.c
	${PROJECT_SOURCE_DIR}/SuiteSparse/KLU/klu_diagnostics.c
	${PROJECT_SOURCE_DIR}/SuiteSparse/KLU/klu_dump.c
	${PROJECT_SOURCE_DIR}/SuiteSparse/KLU/klu_extract.c
	${PROJECT_SOURCE_DIR}/SuiteSparse/KLU/klu_factor.c
	${PROJECT_SOURCE_DIR}/SuiteSparse/KLU/klu_free_numeric.c
	${PROJECT_SOURCE_DIR}/SuiteSparse/KLU/klu_free_symbolic.c
	${PROJECT_SOURCE_DIR}/SuiteSparse/KLU/klu_kernel.c
	${PROJECT_SOURCE_DIR}/SuiteSparse/KLU/klu_memory.c
	${PROJECT_SOURCE_DIR}/SuiteSparse/KLU/klu_refactor.c
	${PROJECT_SOURCE_DIR}/SuiteSparse/KLU/klu_scale.c
	${PROJECT_SOURCE_DIR}/SuiteSparse/KLU/klu_solve.c
	${PROJECT_SOURCE_DIR}/SuiteSparse/KLU/klu_sort.c
	${PROJECT_SOURCE_DIR}/SuiteSparse/KLU/klu_tsolve.c
	${PROJECT_SOURCE_DIR}/SuiteSparse/BTF/btf_maxtrans.c
	${PROJECT_SOURCE_DIR}/SuiteSparse/BTF/btf_order.c
	${PROJECT_SOURCE_DIR}/SuiteSparse/BTF/btf_strongcomp.c
	${PROJECT_SOURCE_DIR}/SuiteSparse/COLAMD/colamd.c
	${PROJECT_SOURCE_DIR}/SuiteSparse/COLAMD/colamd_global.c
	${PROJECT_SOURCE_DIR}/SuiteSparse/AMD/amd_1.c
	${PROJECT_SOURCE_DIR}/SuiteSparse/AMD/amd_2.c
	${PROJECT_SOURCE_DIR}/SuiteSparse/AMD/amd_aat.c
	${PROJECT_SOURCE_DIR}/SuiteSparse/AMD/amd_control.c
	${PROJECT_SOURCE_DIR}/SuiteSparse/AMD/amd_defaults.c
	${PROJECT_SOURCE_DIR}/SuiteSparse/AMD/amd_dump.c
	${PROJECT_SOURCE_DIR}/SuiteSparse/AMD/amd_global.c
	${PROJECT_SOURCE_DIR}/SuiteSparse/AMD/amd_info.c
	${PROJECT_SOURCE_DIR}/SuiteSparse/AMD/amd_order.c
	${PROJECT_SOURCE_DIR}/SuiteSparse/AMD/amd_post_tree.c
	${PROJECT_SOURCE_DIR}/SuiteSparse/AMD/amd_postorder.c
	${PROJECT_SOURCE_DIR}/SuiteSparse/AMD/amd_preprocess.c
	${PROJECT_SOURCE_DIR}/SuiteSparse/AMD/amd_valid.c
	src/cmdevalmu.cpp
	src/cmdregion1d.cpp
	src/cmdregion2d.cpp
	src/cmdrestart.cpp
	src/debugnew.cpp
	src/simiconductorinstance.cpp
	src/maincommands.cpp
	src/simiconductorregion1d.cpp
	src/simiconductorregion2d.cpp
	src/binimage.cpp
	newfit/amoeba.cpp
	newfit/extprogsearchfunction.cpp
	newfit/extproggenome.cpp
	newfit/extproggafactory.cpp
	newfit/extprogmogafactory.cpp
	src/cmdoptimize.cpp
	src/simimpiga.cpp
	src/simimpimoga.cpp
	src/timeutil.cpp
	src/dissociationprobability.cpp
	src/inversematrixpoissonsolver2d.cpp
	src/inversematrixpoissonsolver1d.cpp
	)

set(LIBSOURCES 
	src/simulationstate.cpp
	src/simulation1d.cpp
	src/simulation1ddouble.cpp
	src/simulation1dnr.cpp
	src/simulation1dave.cpp
	src/simulation2d.cpp
	src/simulation2ddouble.cpp
	src/simulation2ddoublerel.cpp
	src/simulation2dnr2.cpp
	src/newtonraphsonsearch.cpp
	${PROJECT_SOURCE_DIR}/SuiteSparse/KLU/klu.c
	${PROJECT_SOURCE_DIR}/SuiteSparse/KLU/klu_analyze.c
	${PROJECT_SOURCE_DIR}/SuiteSparse/KLU/klu_analyze_given.c
	${PROJECT_SOURCE_DIR}/SuiteSparse/KLU/klu_defaults.c
	${PROJECT_SOURCE_DIR}/SuiteSparse/KLU/klu_diagnostics.c
	${PROJECT_SOURCE_DIR}/SuiteSparse/KLU/klu_dump.c
	${PROJECT_SOURCE_DIR}/SuiteSparse/KLU/klu_extract.c
	${PROJECT_SOURCE_DIR}/SuiteSparse/KLU/klu_factor.c
	${PROJECT_SOURCE_DIR}/SuiteSparse/KLU/klu_free_numeric.c
	${PROJECT_SOURCE_DIR}/SuiteSparse/KLU/klu_free_symbolic.c
	${PROJECT_SOURCE_DIR}/SuiteSparse/KLU/klu_kernel.c
	${PROJECT_SOURCE_DIR}/SuiteSparse/KLU/klu_memory.c
	${PROJECT_SOURCE_DIR}/SuiteSparse/KLU/klu_refactor.c
	${PROJECT_SOURCE_DIR}/SuiteSparse/KLU/klu_scale.c
	${PROJECT_SOURCE_DIR}/SuiteSparse/KLU/klu_solve.c
	${PROJECT_SOURCE_DIR}/SuiteSparse/KLU/klu_sort.c
	${PROJECT_SOURCE_DIR}/SuiteSparse/KLU/klu_tsolve.c
	${PROJECT_SOURCE_DIR}/SuiteSparse/BTF/btf_maxtrans.c
	${PROJECT_SOURCE_DIR}/SuiteSparse/BTF/btf_order.c
	${PROJECT_SOURCE_DIR}/SuiteSparse/BTF/btf_strongcomp.c
	${PROJECT_SOURCE_DIR}/SuiteSparse/COLAMD/colamd.c
	${PROJECT_SOURCE_DIR}/SuiteSparse/COLAMD/colamd_global.c
	${PROJECT_SOURCE_DIR}/SuiteSparse/AMD/amd_1.c
	${PROJECT_SOURCE_DIR}/SuiteSparse/AMD/amd_2.c
	${PROJECT_SOURCE_DIR}/SuiteSparse/AMD/amd_aat.c
	${PROJECT_SOURCE_DIR}/SuiteSparse/AMD/amd_control.c
	${PROJECT_SOURCE_DIR}/SuiteSparse/AMD/amd_defaults.c
	${PROJECT_SOURCE_DIR}/SuiteSparse/AMD/amd_dump.c
	${PROJECT_SOURCE_DIR}/SuiteSparse/AMD/amd_global.c
	${PROJECT_SOURCE_DIR}/SuiteSparse/AMD/amd_info.c
	${PROJECT_SOURCE_DIR}/SuiteSparse/AMD/amd_order.c
	${PROJECT_SOURCE_DIR}/SuiteSparse/AMD/amd_post_tree.c
	${PROJECT_SOURCE_DIR}/SuiteSparse/AMD/amd_postorder.c
	${PROJECT_SOURCE_DIR}/SuiteSparse/AMD/amd_preprocess.c
	${PROJECT_SOURCE_DIR}/SuiteSparse/AMD/amd_valid.c
	src/dissociationprobability.cpp
	src/inversematrixpoissonsolver2d.cpp
	src/inversematrixpoissonsolver1d.cpp
	)

if (SIMICONDUCTOR_CONFIG_OPENCL)
	set(COMMONSOURCES ${COMMONSOURCES} 
		src/simulation2ddoublegpurel.cpp 
		src/openclkernel.cpp )
endif (SIMICONDUCTOR_CONFIG_OPENCL)

add_executable(simiconductor src/main.cpp ${COMMONSOURCES} ${SIMIQTHEADERS_MOC})
add_library(sim ${LIBSOURCES})
add_executable(testje src/potentialfindertestje.cpp)

if (MPI_FOUND)
	include_directories("${MPI_INCLUDE_PATH}")
	add_executable(simiconductormpi src/mainmpi.cpp src/cmdoptimizempi.cpp ${COMMONSOURCES} ${SIMIQTHEADERS_MOC})

	get_target_property(TMP simiconductormpi COMPILE_FLAGS)
	if (TMP)
		list(APPEND TMP "${MPI_COMPILE_FLAGS}")
	else()
		set(TMP "${MPI_COMPILE_FLAGS}")
	endif ()
	set_target_properties(simiconductormpi PROPERTIES COMPILE_FLAGS "${TMP}")

	get_target_property(TMP simiconductormpi LINK_FLAGS)
	if (TMP)
		list(APPEND TMP "${MPI_LINK_FLAGS}")
	else()
		set(TMP "${MPI_LINK_FLAGS}")
	endif ()
	set_target_properties(simiconductormpi PROPERTIES LINK_FLAGS "${TMP}")
endif (MPI_FOUND)

add_library(extprogga SHARED newfit/extproggafactorymain.cpp newfit/extproggafactory.cpp newfit/extproggenome.cpp)
install(TARGETS extprogga DESTINATION ${LIBRARY_INSTALL_DIR})
add_library(extprogmoga SHARED newfit/extprogmogafactorymain.cpp newfit/extprogmogafactory.cpp newfit/extproggenome.cpp)
install(TARGETS extprogmoga DESTINATION ${LIBRARY_INSTALL_DIR})

# TODO: for testing
#add_executable(opencltest 
#	       ${PROJECT_SOURCE_DIR}/shell/opencltest.cpp
#	       ${PROJECT_SOURCE_DIR}/sim/openclkernel.cpp
#	       ${PROJECT_SOURCE_DIR}/sim/simulation.cpp
#	       ${PROJECT_SOURCE_DIR}/sim/simulationdouble.cpp
#	       ${PROJECT_SOURCE_DIR}/sim/simulationfloat.cpp
#	       ${PROJECT_SOURCE_DIR}/sim/simulationfloatgpu.cpp 
#	serut/dummyserializer.cpp
#	serut/fileserializer.cpp
#	serut/memoryserializer.cpp
#	serut/serializationinterface.cpp
#	)

# change the "NOT-FOUND" content

if (NOT QT_LIBRARIES)
	set(QT_LIBRARIES "")
endif (NOT QT_LIBRARIES)
if (NOT OPENCL_LIBRARIES)
	set(OPENCL_LIBRARIES "")
endif (NOT OPENCL_LIBRARIES)
if (NOT GSL_LIBRARIES)
	set(GSL_LIBRARIES "")
endif (NOT GSL_LIBRARIES)
if (NOT GSLCBLAS_LIBRARIES)
	set(GSLCBLAS_LIBRARIES "")
endif (NOT GSLCBLAS_LIBRARIES)
if (NOT MPI_LIBRARIES)
	set(MPI_LIBRARIES "")
endif (NOT MPI_LIBRARIES)

target_link_libraries(simiconductor ${SHELLP_LIBRARIES} ${OPENCL_LIBRARIES} ${EXTRA_LIBS} ${GSL_LIBRARIES} ${GSLCBLAS_LIBRARIES} ${QT_LIBRARIES} ${SERUT_LIBRARIES} ${MOGAL_LIBRARIES})
target_link_libraries(testje sim ${SHELLP_LIBRARIES} ${OPENCL_LIBRARIES} ${EXTRA_LIBS} ${GSL_LIBRARIES} ${GSLCBLAS_LIBRARIES} ${QT_LIBRARIES} ${SERUT_LIBRARIES} ${MOGAL_LIBRARIES})

if (OPENMP_FOUND)
	get_target_property(TMP simiconductor COMPILE_FLAGS)
	if (NOT TMP)
		set(TMP "${OpenMP_CXX_FLAGS}")
	else()
		list(APPEND TMP "${OpenMP_CXX_FLAGS}")
	endif()
	set_target_properties(simiconductor PROPERTIES COMPILE_FLAGS "${TMP}")
	get_target_property(TMP simiconductor LINK_FLAGS)
	if (NOT TMP)
		set(TMP "${OpenMP_CXX_FLAGS}")
	else()
		list(APPEND TMP "${OpenMP_CXX_FLAGS}")
	endif()
	set_target_properties(simiconductor PROPERTIES LINK_FLAGS "${TMP}")
endif(OPENMP_FOUND)
install(TARGETS simiconductor DESTINATION "${CMAKE_INSTALL_PREFIX}/bin")

if (MPI_FOUND)
	target_link_libraries(simiconductormpi ${SHELLP_LIBRARIES} ${OPENCL_LIBRARIES} ${EXTRA_LIBS} ${GSL_LIBRARIES} ${GSLCBLAS_LIBRARIES} ${QT_LIBRARIES} ${SERUT_LIBRARIES} ${MOGAL_LIBRARIES} ${MPI_LIBRARIES})
	if(OPENMP_FOUND)
		get_target_property(TMP simiconductormpi COMPILE_FLAGS)
		if (NOT TMP)
			set(TMP "${OpenMP_CXX_FLAGS}")
		else()
			list(APPEND TMP "${OpenMP_CXX_FLAGS}")
		endif()
		set_target_properties(simiconductormpi PROPERTIES COMPILE_FLAGS "${TMP}")

		get_target_property(TMP simiconductormpi LINK_FLAGS)
		if (NOT TMP)
			set(TMP "${OpenMP_CXX_FLAGS}")
		else()
			set(TMP "${TMP} ${OpenMP_CXX_FLAGS}")
		endif()
		set_target_properties(simiconductormpi PROPERTIES LINK_FLAGS "${TMP}")
	endif(OPENMP_FOUND)
	install(TARGETS simiconductormpi DESTINATION "${CMAKE_INSTALL_PREFIX}/bin")
endif ()

# TODO: depends on GSL
target_link_libraries(extprogga ${MOGAL_LIBRARIES} ${GSL_LIBRARIES}) 
target_link_libraries(extprogmoga ${MOGAL_LIBRARIES} ${GSL_LIBRARIES}) 

# TODO: for testing!!
#target_link_libraries(opencltest ${OPENCL_LIBRARIES})

include_directories(${PROJECT_SOURCE_DIR}/src ${EXTRA_INCLUDES})
include_directories(${PROJECT_BINARY_DIR}/src)
include_directories(${PROJECT_SOURCE_DIR}/newfit)
include_directories(${SHELLP_INCLUDE_DIRS})
include_directories(${SERUT_INCLUDE_DIRS})

add_definitions(${QT_DEFINITIONS})

if (NOT SIMICONDUCTOR_CONFIG_QT4)
	set(SIMICONDUCTOR_CONFIG_QT4 "// Qt4 not available")
endif (NOT SIMICONDUCTOR_CONFIG_QT4)
if (NOT SIMICONDUCTOR_CONFIG_OPENCL)
	set(SIMICONDUCTOR_CONFIG_OPENCL "// OpenCL not available")
endif (NOT SIMICONDUCTOR_CONFIG_OPENCL)

configure_file("${PROJECT_SOURCE_DIR}/src/simiconductorconfig.h.in" "${PROJECT_BINARY_DIR}/src/simiconductorconfig.h")

