macro(cmcs_error_message)
    if(DEFINED CMAKE_CURRENT_FUNCTION)
        message(${CMakeCS_MSG_ERROR_TYPE} "[${CMAKE_CURRENT_FUNCTION}]: ${ARGN}")
    else()
        message(${CMakeCS_MSG_ERROR_TYPE} "[${CMAKE_CURRENT_LIST_FILE} (${CMAKE_CURRENT_LIST_LINE})]: ${ARGN}")
    endif()
endmacro()

macro(cmcs_trace_variables)
    if(DEFINED CMAKE_CURRENT_FUNCTION)
        message(TRACE "Variables in function: ${CMAKE_CURRENT_FUNCTION}")
    else()
        message(TRACE "Variables in ${CMAKE_CURRENT_LIST_FILE} at line ${CMAKE_CURRENT_LIST_LINE}")
    endif()
    foreach(arg IN ITEMS ${ARGN})
        message(TRACE "${arg}: ${${arg}}")
    endforeach()
endmacro()

macro(cmcs_return_variables)
    foreach(arg IN ITEMS ${ARGN})
        set(${arg} ${${arg}} PARENT_SCOPE)
        message(TRACE "${arg}: ${${arg}} | Returned to parent scope!")
    endforeach()
endmacro()

macro(cmcs_create_function_variable_prefix)
    string(REGEX REPLACE  "_([a-zA-Z])[^_]+" "\\1" ${ARGV0} "${CMAKE_CURRENT_FUNCTION}")
    string(REPLACE "cmcs" "_cmcs_" ${ARGV0} "${${ARGV0}}")
endmacro()

function(cmcs_define_global_property)
    cmcs_create_function_variable_prefix(_VAR_PREFIX)
    cmake_parse_arguments(PARSE_ARGV 0 "${_VAR_PREFIX}" "" "PROPERTY" "")
    cmcs_variable_exists_or_error(PREFIX "${_VAR_PREFIX}" VARIABLE_NAMES "PROPERTY")
    #cmake_print_variables(${_VAR_PREFIX}_UNPARSED_ARGUMENTS)
    define_property(GLOBAL PROPERTY _CMakeCS_${${_VAR_PREFIX}_PROPERTY} INHERITED ${${_VAR_PREFIX}_UNPARSED_ARGUMENTS})
endfunction()

function(cmcs_set_global_property)
    cmcs_create_function_variable_prefix(_VAR_PREFIX)
    cmake_parse_arguments(PARSE_ARGV 0 "${_VAR_PREFIX}" "" "APPEND_OPTION;PREFIX;PROPERTY;VARIABLE" "")
    cmcs_variable_exists_or_error(PREFIX "${_VAR_PREFIX}" VARIABLE_NAMES "PROPERTY;VARIABLE")
    if(${_VAR_PREFIX}_PREFIX)
        if(NOT ${_VAR_PREFIX}_UNPARSED_ARGUMENTS)
            set_property(GLOBAL ${${_VAR_PREFIX}_APPEND_OPTION} PROPERTY _CMakeCS_${${_VAR_PREFIX}_PROPERTY} ${${${_VAR_PREFIX}_PREFIX}_${${_VAR_PREFIX}_PROPERTY}})
        else()
            set_property(GLOBAL ${${_VAR_PREFIX}_APPEND_OPTION} PROPERTY _CMakeCS_${${_VAR_PREFIX}_PROPERTY} ${${_VAR_PREFIX}_UNPARSED_ARGUMENTS})
        endif()
    else()
        if(NOT ${_VAR_PREFIX}_UNPARSED_ARGUMENTS)
            set_property(GLOBAL ${${_VAR_PREFIX}_APPEND_OPTION} PROPERTY _CMakeCS_${${_VAR_PREFIX}_PROPERTY} ${${${_VAR_PREFIX}_PROPERTY}})
        else()
            set_property(GLOBAL ${${_VAR_PREFIX}_APPEND_OPTION} PROPERTY _CMakeCS_${${_VAR_PREFIX}_PROPERTY} ${${_VAR_PREFIX}_UNPARSED_ARGUMENTS})
        endif()
    endif()
endfunction()

function(cmcs_get_global_property)
    cmcs_create_function_variable_prefix(_VAR_PREFIX)
    cmake_parse_arguments(PARSE_ARGV 0 "${_VAR_PREFIX}" "" "PREFIX;PROPERTY;VARIABLE" "")
    cmcs_variable_exists_or_error(PREFIX "${_VAR_PREFIX}" VARIABLE_NAMES "PROPERTY;VARIABLE")
    if(${_VAR_PREFIX}_PREFIX)
        get_property(${${_VAR_PREFIX}_PREFIX}_${${_VAR_PREFIX}_PROPERTY} GLOBAL PROPERTY _CMakeCS_${${_VAR_PREFIX}_PROPERTY} ${${_VAR_PREFIX}_UNPARSED_ARGUMENTS})
        cmcs_return_variables(${${_VAR_PREFIX}_PREFIX}_${${_VAR_PREFIX}_PROPERTY})
    else()
        get_property(${${_VAR_PREFIX}_PROPERTY} GLOBAL PROPERTY _CMakeCS_${${_VAR_PREFIX}_PROPERTY} ${${_VAR_PREFIX}_UNPARSED_ARGUMENTS})
        cmcs_return_variables(${${_VAR_PREFIX}_PROPERTY})
    endif()
endfunction()