
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
	set(CMAKE_BUILD_TYPE "Debug" CACHE STRING
		"Choose the type of build, options are: Debug Release RelWithDebInfo MinSizeRel."
	FORCE)
	set(CMAKE_BUILD_TYPE_Strings "Debug;Release;RelWithDebInfo;MinSizeRel")
	set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS ${CMAKE_BUILD_TYPE_Strings})
endif()

if ("${CMAKE_SOURCE_DIR}" STREQUAL "${CMAKE_BINARY_DIR}")
  message(FATAL_ERROR "In-source builds are not allowed.")
endif()

if(CMAKE_CXX_FLAGS_DEBUG)
	set(CMAKE_CXX_FLAGS_DEBUG "") #To override the default and have a finer control
	message(STATUS "CMAKE_CXX_FLAGS: ${CMAKE_CXX_FLAGS_DEBUG}") 
endif()

macro (show_function_invocation FUNCTION_NAME OUTVAR PREFIX)
	set(${OUTVAR} "${FUNCTION_NAME}(\n")
	set(ARGS "${multiValueArgs};${oneValueArgs}")
	list(SORT ARGS )
#	message(WARNING "ARGS: ${ARGS}")
	foreach(ARG ${ARGS})
		if(${PREFIX}${ARG})
			set(${OUTVAR} "${${OUTVAR}}   ${ARG} ${${PREFIX}${ARG}}\n")
#			message(WARNING "${OUTVAR}: ${${OUTVAR}}")
		endif()
	endforeach()
	if(options)
		set(${OUTVAR} "${${OUTVAR}}   ")
		foreach(ARG ${options})
			if(${${PREFIX}${ARG}})
				set(${OUTVAR} "${${OUTVAR}}${ARG} ")
			endif()
		endforeach()
	endif()
	if(${PREFIX}UNPARSED_ARGUMENTS)
		set(${OUTVAR} "${${OUTVAR}}\n   ${${PREFIX}UNPARSED_ARGUMENTS}")
	endif()
	set(${OUTVAR} "${${OUTVAR}}\n)")

endmacro()

function (file_patch)
	set(options )
	set(oneValueArgs PATCH_PATH TARGET_PATH ORIGINAL_TARGET_HASH NAME)
	set(multiValueArgs)

	cmake_parse_arguments(PATCH "${options}" "${oneValueArgs}" "${multiValueArgs}" "${ARGN}")

	set(unparsed ${PATCH_UNPARSED_ARGUMENTS})
	if(unparsed)
		message(WARNING "macro apply_patch: unparsed arguments: ${unparsed}")
	endif()
	
	if(NOT EXISTS ${PATCH_TARGET_PATH})
		message(FATAL_ERROR "Cannot find the target file: ${PATCH_TARGET_PATH}")
	endif()
	
	
	get_filename_component(PATCH_TARGET_DIR "${PATCH_TARGET_PATH}" DIRECTORY)
	get_filename_component(PATCH_TARGET_FILE "${PATCH_TARGET_PATH}" NAME)
	
	if( "${PATCH_NAME}" STREQUAL "")
		set(PATCH_NAME "${PATCH_TARGET_DIR}")
	endif()

	file(SHA256 ${PATCH_TARGET_PATH} PATCH_ACTUAL_TARGET_HASH)
	
#	message(WARNING "Attempt to patch ${PATCH_TARGET_PATH} with hash ${PATCH_ACTUAL_TARGET_HASH}.")

	
	if( "${PATCH_ORIGINAL_TARGET_HASH}" STREQUAL "${PATCH_ACTUAL_TARGET_HASH}")
		message(STATUS "Patching ${PATCH_TARGET_FILE} in ${PATCH_NAME}")
		execute_process(COMMAND patch -i "${PATCH_PATCH_PATH}"
		                WORKING_DIRECTORY "${PATCH_TARGET_DIR}")
	else()
		message(STATUS "${PATCH_TARGET_FILE} in ${PATCH_NAME} already patched.")
	endif()
endfunction()

function(get_cpp_version)
	set(options )
	set(oneValueArgs TARGET)
	set(multiValueArgs)

	cmake_parse_arguments(CPPV "${options}" "${oneValueArgs}" "${multiValueArgs}" "${ARGN}")

	set(unparsed ${CPPV_UNPARSED_ARGUMENTS})
	if(unparsed)
		message(FATAL_ERROR "function get_cpp_version: unparsed arguments: ${unparsed}")
	endif()
	get_target_property(PROPS ${CPPV_TARGET} COMPILE_OPTIONS)
	set(CPP98 0)
	set(CPP03 0)
	set(CPP11 0)
	set(CPP14 0)
	set(CPP17 0)
	set(CPP2A 0)
	set(CPP20 0)
	foreach(OPT ${COMPILE_OPTIONS})
		if("${OPT}" STREQUAL "-std=c++98" OR "${OPT}" STREQUAL "-std=gnu++98")
			set(CPP98 1)
		endif()
		if("${OPT}" STREQUAL "-std=c++03" OR "${OPT}" STREQUAL "-std=gnu++03")
			set(CPP03 1)
		endif()
		if("${OPT}" STREQUAL "-std=c++11" OR "${OPT}" STREQUAL "-std=gnu++11")
			set(CPP11 1)
		endif()
		if("${OPT}" STREQUAL "-std=c++14" OR "${OPT}" STREQUAL "-std=gnu++14")
			set(CPP14 1)
		endif()
		if("${OPT}" STREQUAL "-std=c++17" OR "${OPT}" STREQUAL "-std=gnu++17")
			set(CPP17 1)
		endif()
		if("${OPT}" STREQUAL "-std=c++2a" OR "${OPT}" STREQUAL "-std=gnu++2a")
			set(CPP2A 1)
		endif()
		if("${OPT}" STREQUAL "-std=c++20" OR "${OPT}" STREQUAL "-std=gnu++20")
			set(CPP20 1)
		endif()
	endforeach()
	math(EXPR SUMOPT "${CPP98} + ${CPP03} + ${CPP11} + ${CPP14} + ${CPP17} + ${CPP2A} + ${CPP20}")
	if (${SUMOPT} GREATER 1)
		message(FATAL_ERROR "Target ${TARGET} has conflicting CPP standard flags: C++98: ${CPP98}, C++03: ${CPP03}, C++11: ${CPP11}, C++14: ${CPP14}, C++17: ${CPP17}, C++2a: ${CPP2A} and C++20: ${CPP20}.")
	endif()
	if(CPP98) 
		set(CPP_VERSION "98")
	endif()
	if(CPP03) 
		set(CPP_VERSION "03")
	endif()
	if(CPP11) 
		set(CPP_VERSION "11")
	endif()
	if(CPP14) 
		set(CPP_VERSION "14")
	endif()
	if(CPP17) 
		set(CPP_VERSION "17")
	endif()
	if(CPP2A) 
		set(CPP_VERSION "2a")
	endif()
	if(CPP20) 
		set(CPP_VERSION "20")
	endif()
	set(CPP_VERSION ${CPP_VERSION} PARENT_SCOPE)
endfunction()

#Function assumes all targets require exactly the same C++ version. This may not be your case, so use it carefully.
function(get_cpp_version2)
	set(options )
	set(oneValueArgs )
	set(multiValueArgs TARGETS)

	cmake_parse_arguments(CPPV "${options}" "${oneValueArgs}" "${multiValueArgs}" "${ARGN}")

	set(unparsed ${CPPV_UNPARSED_ARGUMENTS})
	if(unparsed)
		message(FATAL_ERROR "function get_cpp_version: unparsed arguments: ${unparsed}")
	endif()
	set(MY_CPP_VERSION "")
	set(LAST_TARGET "")
	foreach(TARGET ${TARGETS})
		get_cpp_version(${TARGET})
		if("${CPP_VERSION}" STREQUAL "")
			message(FATAL_ERRPR "Target ${TARGET} does not specify C++ version.")
		endif()
		if("${MY_CPP_VERSION}" STREQUAL "")
			set(MY_CPP_VERSION ${CPP_VERSION})
			set(LAST_TARGET "${TARGET}")
		else()
			if( NOT "${MY_CPP_VERSION}" STREQUAL "${CPP_VERSION}")
				message(FATAL_ERROR "Target ${TARGET} requires C++ version C++${CPP_VERSION} which is different than target ${LAST_TARGET} with version C++${MY_CPP_VERSION}." )
			endif()
		endif()
	endforeach()
	set(CPP_VERSION ${MY_CPP_VERSION} PARENT_SCOPE)
endfunction()

