# Code which generates the <package-name>Config.cmake file. 

function(cmakejson_generate_project_config)
    list(APPEND CMAKE_MESSAGE_CONTEXT "generate_config")

    cmakejson_get_project_property(PROPERTY PACKAGE_NAME)
    cmakejson_get_project_property(PROPERTY EXPORT_NAME)
    cmakejson_get_project_property(PROPERTY PUBLIC_CMAKE_MODULE_PATH)
    cmakejson_get_project_property(PROPERTY CMAKE_CONFIG_INSTALL_DESTINATION)
    cmakejson_get_project_property(PROPERTY OPTIONS) # Check if the option is exported

    if(IS_ABSOLUTE "${CMAKE_CONFIG_INSTALL_DESTINATION}")
        message(${CMakeJSON_MSG_ERROR_TYPE} "Member 'cmake_config_install_destination' destination needs to be relative! Value:'${CMAKE_CONFIG_INSTALL_DESTINATION}'")
    endif()

    set(EXPORTED_CONFIG_VARS)
    set(EXPORTED_CONFIG_PATH_VARS)

    if(NOT DEFINED CMakeJSON_PARSE_PROJECT_CMAKE_CONFIG_INPUT)
        set(_config_contents)
        string(APPEND _config_contents "#This file was automatically generated by CMakeCS!\n")
        string(APPEND _config_contents "@PACKAGE_INIT@\n")
        string(APPEND _config_contents "cmake_policy (PUSH)\n")
        string(APPEND _config_contents "cmake_minimum_required (VERSION 3.19)\n\n")

        # Force case correct calling of in find_package
        string(APPEND _config_contents "get_filename_component(_current_file_name \"\${CMAKE_CURRENT_LIST_FILE}\" NAME_WE)\n")
        string(APPEND _config_contents "string(REGEX REPLACE \"-?[Cc][Oo][Nn][Ff][Ii][Gg]$\" \"\" _package_name \"\${_current_file_name}\")\n")
        string(APPEND _config_contents "if(NOT _package_name STREQUAL CMAKE_FIND_PACKAGE_NAME)\n")
        string(APPEND _config_contents "\tmessage(FATAL_ERROR \"CMAKE_FIND_PACKAGE_NAME='\${CMAKE_FIND_PACKAGE_NAME}' does not agree in case with <Name>Config.cmake (Name='\${_package_name}')\n To be crossplatform compatible the names need to agree in case!\")\n")
        string(APPEND _config_contents "endif()\n")

        # string(APPEND _config_contents "include(FindPackageHandleStandardArgs)\n\n")
        list(APPEND ${PROJECT_NAME}_CONFIG_VARS CMAKE_CURRENT_LIST_FILE)
        if(PUBLIC_CMAKE_MODULE_PATH)
            list(APPEND ${PROJECT_NAME}_CONFIG_VARS \${CMAKE_FIND_PACKAGE_NAME}_CMAKE_MODULE_PATH)
            string(APPEND _config_contents "set(\${CMAKE_FIND_PACKAGE_NAME}_CMAKE_MODULE_PATH \"\${CMAKE_CURRENT_LIST_DIR}/cmake\")\n")
            string(APPEND _config_contents "set(\${CMAKE_FIND_PACKAGE_NAME}_CMAKE_MODULE_PATH_BACKUP \${CMAKE_MODULE_PATH})\n")
            string(APPEND _config_contents "list(PREPEND CMAKE_MODULE_PATH \"\${CMAKE_CURRENT_LIST_DIR}/cmake\")\n") # Prepending makes sure we get the correct modules
            string(APPEND _config_contents "list(REMOVE_DUPLICATES CMAKE_MODULE_PATH)\n")
            string(APPEND _config_contents "list(REMOVE_DUPLICATES \${CMAKE_FIND_PACKAGE_NAME}_CMAKE_MODULE_PATH)\n")
            string(APPEND _config_contents "set(\${CMAKE_FIND_PACKAGE_NAME}_CMAKE_MODULE_PATH \"\${\${CMAKE_FIND_PACKAGE_NAME}_CMAKE_MODULE_PATH}\" CACHE INTERNAL \"\")\n\n")   
        endif()

        string(APPEND _config_contents "set(\${CMAKE_FIND_PACKAGE_NAME}_BUILD_AS_SHARED @BUILD_SHARED_LIBS@ CACHE INTERNAL \"\")\n")

        foreach(_opt IN LISTS OPTIONS)
            cmakejson_get_project_property(PROPERTY OPTION_${_opt}_TYPE)
            cmakejson_get_project_property(PROPERTY OPTION_${_opt}_VARIABLE)
            cmakejson_get_project_property(PROPERTY OPTION_${_opt}_EXPORT)
            set(_var "${OPTION_${_opt}_VARIABLE}")
            set(_set_var "set")
            set(_var_package)
            if(OPTION_${_opt}_TYPE STREQUAL "PATH")
                set(_set_var set_and_check)
                set(_var_package PACKAGE_)
                if(OPTION_${_opt}_EXPORT)
                    list(APPEND EXPORTED_CONFIG_PATH_VARS \${CMAKE_FIND_PACKAGE_NAME}_${_var})
                endif()
            endif()
            if(OPTION_${_opt}_EXPORT)
                string(APPEND _config_contents "${_set_var}(\${CMAKE_FIND_PACKAGE_NAME}_${_var} @${_var_package}${_var}@ CACHE INTERNAL \"\")\n")
                list(APPEND EXPORTED_CONFIG_VARS \${CMAKE_FIND_PACKAGE_NAME}_${_var})
            else()
                string(APPEND _config_contents "${_set_var}(\${CMAKE_FIND_PACKAGE_NAME}_${_var} @${_var_package}${_var}@)\n")
            endif()
            unset(_var)
            unset(_set_var)
            unset(_var_package)
            unset(OPTION_${_opt}_VARIABLE)
            unset(OPTION_${_opt}_EXPORT)
            unset(OPTION_${_opt}_TYPE)
        endforeach()

        cmakejson_get_project_property(PROPERTY CONFIG_MODULES)
        if(CONFIG_MODULES)
            string(APPEND _config_contents "\n # Deal with modules to include\n")
            foreach(_module IN LISTS CONFIG_MODULES)
                string(APPEND _config_contents "include(${_module})\n")
            endforeach()
        endif()

        # Deal with dependencies
        cmakejson_get_project_property(PROPERTY DEPENDENCIES)
        cmakejson_get_project_property(PROPERTY CHILD_PROJECTS)
        if(DEPENDENCIES OR CHILD_PROJECTS)
            string(APPEND _config_contents "\n # Deal with dependencies \n")
            string(APPEND _config_contents "include(CMakeFindDependencyMacro)\n")
        endif()
        if(DEPENDENCIES)
            string(APPEND _config_contents "\n # Dependencies \n")
            # Write find_dependency calls fo required packages
            foreach(_dep IN LISTS DEPENDENCIES)
                cmakejson_get_project_property(PROPERTY DEPENDENCY_${_dep}_FIND_PACKAGE)
                cmakejson_get_project_property(PROPERTY DEPENDENCY_${_dep}_OPTION)
                if(DEPENDENCY_${_dep}_OPTION)
                    cmakejson_get_project_property(PROPERTY OPTION_${DEPENDENCY_${_dep}_OPTION}_VARIABLE)
                    string(APPEND _config_contents "if(\${CMAKE_FIND_PACKAGE_NAME}_${OPTION_${DEPENDENCY_${_dep}_OPTION}_VARIABLE})\n")
                endif()
                list(REMOVE_ITEM DEPENDENCY_${_dep}_FIND_PACKAGE REQUIRED)
                string(APPEND _config_contents "find_dependency(")
                string(APPEND _config_contents "${DEPENDENCY_${_dep}_FIND_PACKAGE}")
                string(APPEND _config_contents ")\n")
                if(DEPENDENCY_${_dep}_OPTION)
                    string(APPEND _config_contents "endif(\${CMAKE_FIND_PACKAGE_NAME}_${OPTION_${DEPENDENCY_${_dep}_OPTION}_VARIABLE})\n")
                    unset(OPTION_${DEPENDENCY_${_dep}_OPTION})
                    unset(OPTION_${DEPENDENCY_${_dep}_OPTION}_VARIABLE)
                endif()
                unset(DEPENDENCY_${_dep}_FIND_PACKAGE)
            endforeach()
        endif()
        string(APPEND _config_contents "set(\${CMAKE_FIND_PACKAGE_NAME}_FOUND TRUE)\n")
        # Deal with components/childs
        if(CHILD_PROJECTS)
            set(_available_components )
            string(APPEND _config_contents "\n # Deal with components \n")
            foreach(_child IN LISTS CHILD_PROJECTS)
                cmakejson_get_project_property(PROPERTY CHILD_${_child}_COMPONENT_NAME)
                set(_component "${CHILD_${_child}_COMPONENT_NAME}")
                list(APPEND _available_components ${_component})
                string(APPEND _config_contents "find_dependency(${PACKAGE_NAME}_${_component}\n")
                string(APPEND _config_contents "                HINTS \${CMAKE_CURRENT_LIST_DIR}\n")
                string(APPEND _config_contents "                )\n\n")
                unset(CHILD_${_child}_PACKAGE_NAME)
            endforeach() 
            string(APPEND _config_contents "set(\${CMAKE_FIND_PACKAGE_NAME}_AVAILABLE_COMPONENTS ${_available_components})\n")
            string(APPEND _config_contents "check_required_components(\${CMAKE_FIND_PACKAGE_NAME})\n")
            unset(_available_components)
            unset(CHILD_PROJECTS)
        else()
            set(COMPONENT_OPTION NO_CHECK_REQUIRED_COMPONENTS_MACRO)
        endif(CHILD_PROJECTS)

        string(APPEND _config_contents "\n # Finish up \n")
        cmakejson_get_project_property(PROPERTY EXPORTED_TARGETS)
        if(EXPORTED_TARGETS)
            string(APPEND _config_contents "include(\${CMAKE_CURRENT_LIST_DIR}/${PACKAGE_NAME}Targets.cmake)\n")
        endif()

        if(PUBLIC_CMAKE_MODULE_PATH)
            string(APPEND _config_contents "set(CMAKE_MODULE_PATH \${\${CMAKE_FIND_PACKAGE_NAME}_CMAKE_MODULE_PATH_BACKUP})\n") # Restoring old module path
        endif()
        string(APPEND _config_contents "cmake_policy (POP)\n")

        if(CMakeJSON_PARSE_PROJECT_DESCRIPTION)
            string(APPEND _config_contents "set_package_properties(\${CMAKE_FIND_PACKAGE_NAME} PROPERTIES\n"
                                           "                       DESCRIPTION \"${CMakeJSON_PARSE_PROJECT_DESCRIPTION}\")\n")
        endif()
        if(CMakeJSON_PARSE_PROJECT_HOMEPAGE)
            string(APPEND _config_contents "set_package_properties(\${CMAKE_FIND_PACKAGE_NAME} PROPERTIES\n"
                                           "                       URL \"${CMakeJSON_PARSE_PROJECT_HOMEPAGE}\")\n")
        endif()

        file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/${PACKAGE_NAME}Config.in.cmake" "${_config_contents}")
        set(CMAKE_INPUT_FILE "${CMAKE_CURRENT_BINARY_DIR}/${PACKAGE_NAME}Config.in.cmake")
    else()
        set(CMAKE_INPUT_FILE "${CMakeJSON_PARSE_PROJECT_CMAKE_CONFIG_INPUT}")
        foreach(_opt IN LISTS OPTIONS)
            cmakejson_get_project_property(PROPERTY ${_opt}_TYPE)
            cmakejson_get_project_property(PROPERTY ${_opt}_VARIABLE)
            cmakejson_get_project_property(PROPERTY ${_opt}_EXPORT)
            set(_var ${${_opt}_VARIABLE})
            if(${_opt}_TYPE STREQUAL "PATH" AND ${_opt}_EXPORT)
                list(APPEND EXPORTED_CONFIG_PATH_VARS \${CMAKE_FIND_PACKAGE_NAME}_${_var})
            elseif(${_opt}_EXPORT)
                list(APPEND EXPORTED_CONFIG_VARS \${CMAKE_FIND_PACKAGE_NAME}_${_var})
            endif()
            unset(_var)
            unset(${_opt}_VARIABLE)
            unset(${_opt}_EXPORT)
            unset(${_opt}_TYPE)
        endforeach()
    endif(NOT DEFINED CMakeJSON_PARSE_PROJECT_CMAKE_CONFIG_INPUT)

    file(RELATIVE_PATH REL_CONFIG_PATH  "${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_CURRENT_BINARY_DIR}")

    set(NO_SET_CHECK)
    if(NOT EXPORTED_CONFIG_PATH_VARS)
        set(NO_SET_CHECK NO_SET_AND_CHECK_MACRO)
    endif()
    set(PATH_VARS)
    if(EXPORTED_CONFIG_PATH_VARS)
        set(PATH_VARS PATH_VARS ${EXPORTED_CONFIG_PATH_VARS})
    endif()
    # Write install config file 
    configure_package_config_file(
            "${CMAKE_INPUT_FILE}"
            "${CMAKE_CONFIG_INSTALL_DESTINATION}/${PACKAGE_NAME}Config.install.cmake"
            INSTALL_DESTINATION "$<INSTALL_INTERFACE:${CMAKE_CONFIG_INSTALL_DESTINATION}>"
            ${PATH_VARS}
            ${COMPONENT_OPTION}
            ${NO_SET_CHECK}
            )
    if(PUBLIC_CMAKE_MODULE_PATH)
        install(DIRECTORY "${PUBLIC_CMAKE_MODULE_PATH}" DESTINATION "${CMAKE_CONFIG_INSTALL_DESTINATION}/cmake" )
    endif()

    cmakejson_get_project_property(PROPERTY VERSION)
    cmakejson_get_project_property(PROPERTY VERSION_COMPATIBILITY)

    if(VERSION AND VERSION_COMPATIBILITY)
        write_basic_package_version_file("${CMAKE_CONFIG_INSTALL_DESTINATION}/${PACKAGE_NAME}ConfigVersion.cmake"
                                        VERSION ${VERSION} 
                                        COMPATIBILITY ${VERSION_COMPATIBILITY})
        install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CONFIG_INSTALL_DESTINATION}/${PACKAGE_NAME}ConfigVersion.cmake"
                                        DESTINATION "${CMAKE_CONFIG_INSTALL_DESTINATION}" )
    elseif(VERSION OR VERSION_COMPATIBILITY)
        message(${CMakeJSON_MSG_ERROR_TYPE} "Cannot define VERSION or VERSION_COMPATIBILITY without setting both!")
    endif()

    install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CONFIG_INSTALL_DESTINATION}/${PACKAGE_NAME}Config.install.cmake"
            DESTINATION "${CMAKE_CONFIG_INSTALL_DESTINATION}"
            RENAME "${PACKAGE_NAME}Config.cmake")

    list(POP_BACK CMAKE_MESSAGE_CONTEXT)
endfunction()