find_package (Haskell)

set (GHC_MIN_VERSION "8.0.0")

if (HASKELL_FOUND)
	if (NOT GHC_VERSION VERSION_LESS ${GHC_MIN_VERSION})
		if (NOT BUILD_STATIC)
			add_binding (haskell)

			set (CABAL_INCLUDE_DIRS "\"${CMAKE_SOURCE_DIR}/src/include\", \"${CMAKE_BINARY_DIR}/src/include\"")

			set (BINDING_HASKELL_NAME "${CMAKE_CURRENT_BINARY_DIR}/libHSlibelektra-haskell")
			if (BUILD_SHARED OR BUILD_FULL)
				set (GHC_DYNAMIC_SUFFIX "-ghc${GHC_VERSION}")
				set (BINDING_HASKELL_NAME "${BINDING_HASKELL_NAME}${CMAKE_SHARED_LIBRARY_SUFFIX}${GHC_DYNAMIC_ENDING}")
				set (CABAL_OPTS "--enable-shared")
				if (BUILD_SHARED)
					set (ELEKTRA_DEPENDENCY "elektra;elektra-kdb;elektra-ease;")
				elseif (BUILD_FULL)
					set (ELEKTRA_DEPENDENCY "elektra-full;")
				endif ()
			elseif (BUILD_STATIC)
				set (BINDING_HASKELL_NAME "${BINDING_HASKELL_NAME}.a")
				set (CABAL_OPTS "--disable-shared")
				set (ELEKTRA_DEPENDENCY "elektra-static;")
			endif ()
			string (REPLACE ";" " " CABAL_ELEKTRA_DEPENDENCY "${ELEKTRA_DEPENDENCY}")

			# configure include paths
			configure_file ("${CMAKE_CURRENT_SOURCE_DIR}/libelektra-haskell.cabal.in"
					"${CMAKE_CURRENT_BINARY_DIR}/libelektra-haskell.cabal"
					@ONLY)

			# Use the post-build logic to glue the bindings together with cmake as its done for plugins
			configure_file ("${CMAKE_SOURCE_DIR}/src/plugins/haskell/Setup.hs.in" "${CMAKE_CURRENT_BINARY_DIR}/Setup.hs" @ONLY)
			set (BINDING_HASKELL_DEPENDENCIES
			     "${CMAKE_CURRENT_SOURCE_DIR}/libelektra-haskell.cabal.in"
			     "${CMAKE_CURRENT_SOURCE_DIR}/src/Elektra/Key.chs"
			     "${CMAKE_CURRENT_SOURCE_DIR}/src/Elektra/KeySet.chs"
			     "${CMAKE_CURRENT_SOURCE_DIR}/src/Elektra/Plugin.chs"
			     "${CMAKE_CURRENT_SOURCE_DIR}/src/Elektra/KDB.chs"
			     "${CMAKE_CURRENT_SOURCE_DIR}/src/Elektra/Ease.chs"
			     "${CMAKE_CURRENT_SOURCE_DIR}/test/Elektra.hs"
			     "${CMAKE_CURRENT_SOURCE_DIR}/test/ElektraRealWorld.hs"
			     "${CMAKE_SOURCE_DIR}/src/plugins/haskell/Setup.hs.in")
			execute_process (COMMAND ${CABAL_EXECUTABLE} sandbox init --sandbox ${CMAKE_BINARY_DIR}/.cabal-sandbox -v0
					 WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
					 OUTPUT_QUIET)

			# Sometimes building fails reporting an outdated package file. In this case we need to configure the
			# package again.
			add_custom_command (OUTPUT ${BINDING_HASKELL_NAME}
					    COMMAND ${CABAL_EXECUTABLE} update -v0
					    COMMAND ${CABAL_EXECUTABLE} install ${CABAL_OPTS} --only-dependencies -v0 || true
					    COMMAND ${CABAL_EXECUTABLE} configure ${CABAL_OPTS} -v0
					    COMMAND ${CABAL_EXECUTABLE} build -v0 || ${CABAL_EXECUTABLE} configure ${CABAL_OPTS} -v0 &&
						    ${CABAL_EXECUTABLE} build -v0
					    WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
					    DEPENDS ${BINDING_HASKELL_DEPENDENCIES}
						    ${ELEKTRA_DEPENDENCY})
			add_custom_target (c2hs_haskell ALL DEPENDS "${BINDING_HASKELL_NAME}")
			if (BUILD_SHARED OR BUILD_FULL)

				# build and install it to the global db
				install (
					CODE
					"execute_process (COMMAND ${CABAL_EXECUTABLE} --ignore-sandbox install -v0 WORKING_DIRECTORY \"${CMAKE_CURRENT_BINARY_DIR}\")"
					)
			endif (BUILD_SHARED OR BUILD_FULL)

			if (BUILD_TESTING)

				# recompile with tests enabled, to get the dependency graph for the static versions correct
				# the tests need the elektra library already built - while for the haskell plugins it doesn't matter
				# as a static build depends on the plugins but not on the bindings, this is the way we can resolve the
				# circular dependency by treating the tests separately
				set (
					HASKELL_TESTS
					"${CMAKE_CURRENT_BINARY_DIR}/dist/build/testhaskell_basic/testhaskell_basic"
					"${CMAKE_CURRENT_BINARY_DIR}/dist/build/testhaskell_basic_optimized/testhaskell_basic_optimized"
					"${CMAKE_CURRENT_BINARY_DIR}/dist/build/testhaskell_realworld/testhaskell_realworld"
					"${CMAKE_CURRENT_BINARY_DIR}/dist/build/testhaskell_realworld_optimized/testhaskell_realworld_optimized"
					)

				# Sometimes building fails reporting an outdated package file. In this case we need to configure the
				# package again.
				add_custom_command (OUTPUT ${HASKELL_TESTS}
						    COMMAND ${CABAL_EXECUTABLE} install ${CABAL_OPTS} --enable-tests
							    --only-dependencies -v0 || true
						    COMMAND ${CABAL_EXECUTABLE} configure ${CABAL_OPTS} --enable-tests -v0
						    COMMAND ${CABAL_EXECUTABLE} build -v0 || ${CABAL_EXECUTABLE} configure ${CABAL_OPTS}
							    --enable-tests -v0 && ${CABAL_EXECUTABLE} build -v0
						    WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
						    DEPENDS ${BINDING_HASKELL_DEPENDENCIES}
							    ${ELEKTRA_DEPENDENCY}
							    c2hs_haskell)
				add_custom_target (c2hs_haskell_tests ALL DEPENDS ${HASKELL_TESTS})
				if (INSTALL_TESTING)

					# as those are not controlled by cmake really, adjust the rpath manually
					# install rpath is enough, we don't depend on any cabal libraries anymore
					# tests are statically compiled
					foreach (HASKELL_TEST ${HASKELL_TESTS})
						install (
							CODE
							"execute_process (COMMAND ${CMAKE_INSTALL_NAME_TOOL} -add_rpath \"${CMAKE_INSTALL_RPATH}\" \"${HASKELL_TEST}\" OUTPUT_QUIET ERROR_QUIET)"
							)
					endforeach (HASKELL_TEST ${HASKELL_TESTS})
					install (FILES ${HASKELL_TESTS}
						       DESTINATION
						       ${TARGET_TOOL_EXEC_FOLDER}
						       PERMISSIONS
						       OWNER_READ
						       OWNER_WRITE
						       OWNER_EXECUTE
						       GROUP_READ
						       GROUP_EXECUTE
						       WORLD_READ
						       WORLD_EXECUTE)
				endif (INSTALL_TESTING)

				add_test (testhaskell_basic "${CMAKE_CURRENT_BINARY_DIR}/dist/build/testhaskell_basic/testhaskell_basic")
				set_property (TEST testhaskell_basic PROPERTY LABELS bindings)
				set_property (TEST testhaskell_basic APPEND PROPERTY LABELS memleak)
				set_property (TEST testhaskell_basic PROPERTY ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/lib")

				add_test (testhaskell_basic_optimized
					  "${CMAKE_CURRENT_BINARY_DIR}/dist/build/testhaskell_basic_optimized/testhaskell_basic_optimized")
				set_property (TEST testhaskell_basic_optimized PROPERTY LABELS bindings)
				set_property (TEST testhaskell_basic_optimized APPEND PROPERTY LABELS memleak)
				set_property (TEST testhaskell_basic_optimized
					      PROPERTY ENVIRONMENT
						       "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/lib")

				if (ENABLE_KDB_TESTING)
					add_test (testhaskell_realworld
						  "${CMAKE_CURRENT_BINARY_DIR}/dist/build/testhaskell_realworld/testhaskell_realworld")
					set_property (TEST testhaskell_realworld PROPERTY LABELS bindings)
					set_property (TEST testhaskell_realworld APPEND PROPERTY LABELS kdbtests)
					set_property (TEST testhaskell_realworld PROPERTY RUN_SERIAL TRUE)
					set_property (TEST testhaskell_realworld APPEND PROPERTY LABELS memleak)
					set_property (TEST testhaskell_realworld
						      PROPERTY ENVIRONMENT
							       "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/lib")

					add_test (
						testhaskell_realworld_optimized
						"${CMAKE_CURRENT_BINARY_DIR}/dist/build/testhaskell_realworld_optimized/testhaskell_realworld_optimized"
						)
					set_property (TEST testhaskell_realworld_optimized PROPERTY LABELS bindings)
					set_property (TEST testhaskell_realworld_optimized APPEND PROPERTY LABELS kdbtests)
					set_property (TEST testhaskell_realworld_optimized PROPERTY RUN_SERIAL TRUE)
					set_property (TEST testhaskell_realworld_optimized APPEND PROPERTY LABELS memleak)
					set_property (TEST testhaskell_realworld_optimized
						      PROPERTY ENVIRONMENT
							       "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/lib")
				endif (ENABLE_KDB_TESTING)
			endif (BUILD_TESTING)
		else (NOT BUILD_STATIC)
			exclude_binding (haskell "BUILD_STATIC is currently not compatible with the haskell bindings")
		endif (NOT BUILD_STATIC)
	else (NOT GHC_VERSION VERSION_LESS ${GHC_MIN_VERSION})
		exclude_binding (haskell "ghc: ${GHC_VERSION} found, but ${GHC_MIN_VERSION} required")
	endif (NOT GHC_VERSION VERSION_LESS ${GHC_MIN_VERSION})
else (HASKELL_FOUND)
	exclude_binding (haskell ${HASKELL_NOTFOUND_INFO})
endif (HASKELL_FOUND)
