###############################################
# NOTE: This file was changed for the FreeSpace Open version, the source code is unchanged
###############################################


# Notes:
#
# Author: Paul Harris, June 2012
# Additions: Joakim Soderberg, Febuary 2013
#
# Supports: building static/shared, release/debug/etc, can also build html docs
# and some of the tests.
# Note that its designed for out-of-tree builds, so it will not pollute your
# source tree.
#
# TODO 1: Finish implementing tests. api tests are working, but the valgrind
# variants are not flagging problems.
#
# TODO 2: There is a check_exports script that would try and incorporate.
#
# TODO 3: Consolidate version numbers, currently the version number is written
# into: * cmake (here) * autotools (the configure) * source code header files.
# Should not be written directly into header files, autotools/cmake can do
# that job.
#
# Brief intro on how to use cmake:
# > mkdir build (somewhere - we do out-of-tree builds)
# > use cmake, ccmake, or cmake-gui to configure the project. for linux, you
# can only choose one variant: release,debug,etc... and static or shared.
# >> example:
# >> cd build
# >> ccmake -i ../path_to_jansson_dir
# >>  inside, configure your options. press C until there are no lines
#     with * next to them.
# >>  note, I like to configure the 'install' path to ../install, so I get
#     self-contained clean installs I can point other projects to.
# >>  press G to 'generate' the project files.
# >> make (to build the project)
# >> make install
# >> make test (to run the tests, if you enabled them)
#
# Brief description on how it works:
# There is a small heirachy of CMakeLists.txt files which define how the
# project is built.
# Header file detection etc is done, and the results are written into config.h
# and jansson_config.h, which are generated from the corresponding
# config.h.cmake and jansson_config.h.cmake template files.
# The generated header files end up in the build directory - not in
# the source directory.
# The rest is down to the usual make process.

IF(NOT FSO_BUILD_INCLUDED_LIBS AND UNIX)
	find_package(PkgConfig)

	if (PKG_CONFIG_FOUND)
		pkg_check_modules(JANSSON jansson>=2.2)

		IF(JANSSON_FOUND)
			INCLUDE(util)
			PKG_CONFIG_LIB_RESOLVE(JANSSON JANSSON_LIBS)

			ADD_IMPORTED_LIB(jansson "${JANSSON_INCLUDEDIR}" "${JANSSON_LIBS}")

			SET(JANSSON_LIBS jansson CACHE INTERNAL "jansson library" FORCE)
		ENDIF(JANSSON_FOUND)
	endif()
ENDIF()

IF(FSO_BUILD_INCLUDED_LIBS OR NOT JANSSON_FOUND)
	MESSAGE(STATUS "Building jansson from source...")
    # Options
    set(USE_URANDOM ON)
    set(USE_WINDOWS_CRYPTOAPI ON)

    # This is how I thought it should go
    # set (JANSSON_VERSION "2.3.1")
    # set (JANSSON_SOVERSION 2)

    set(JANSSON_DISPLAY_VERSION "2.7")

    # This is what is required to match the same numbers as automake's
    set(JANSSON_VERSION "4.7.0")
    set(JANSSON_SOVERSION 4)

    # for CheckFunctionKeywords
    set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")

    include (CheckCSourceCompiles)
    include (CheckFunctionExists)
    include (CheckFunctionKeywords)
    include (CheckIncludeFiles)
    include (CheckTypeSize)
    INCLUDE(CheckSymbolExists)

    check_include_files (endian.h HAVE_ENDIAN_H)
    check_include_files (fcntl.h HAVE_FCNTL_H)
    check_include_files (sched.h HAVE_SCHED_H)
    check_include_files (unistd.h HAVE_UNISTD_H)
    check_include_files (sys/param.h HAVE_SYS_PARAM_H)
    check_include_files (sys/stat.h HAVE_SYS_STAT_H)
    check_include_files (sys/time.h HAVE_SYS_TIME_H)
    check_include_files (sys/time.h HAVE_SYS_TYPES_H)

    check_function_exists (close HAVE_CLOSE)
    check_function_exists (getpid HAVE_GETPID)
    check_function_exists (gettimeofday HAVE_GETTIMEOFDAY)
    check_function_exists (open HAVE_OPEN)
    check_function_exists (read HAVE_READ)
    check_function_exists (sched_yield HAVE_SCHED_YIELD)

    # Check for the int-type includes
    check_include_files (stdint.h HAVE_STDINT_H)

    # Check our 64 bit integer sizes
    check_type_size (__int64 __INT64)
    check_type_size (int64_t INT64_T)
    check_type_size ("long long" LONG_LONG_INT)

    # Check our 32 bit integer sizes
    check_type_size (int32_t INT32_T)
    check_type_size (__int32 __INT32)
    check_type_size ("long" LONG_INT)
    check_type_size ("int" INT)
    if (HAVE_INT32_T)
       set (JSON_INT32 int32_t)
    elseif (HAVE___INT32)
       set (JSON_INT32 __int32)
    elseif (HAVE_LONG_INT AND (${LONG_INT} EQUAL 4))
       set (JSON_INT32 long)
    elseif (HAVE_INT AND (${INT} EQUAL 4))
       set (JSON_INT32 int)
    else ()
       message (FATAL_ERROR "Could not detect a valid 32-bit integer type")
    endif ()

    check_type_size ("unsigned long" UNSIGNED_LONG_INT)
    check_type_size ("unsigned int" UNSIGNED_INT)
    check_type_size ("unsigned short" UNSIGNED_SHORT)

    check_type_size (uint32_t UINT32_T)
    check_type_size (__uint32 __UINT32)
    if (HAVE_UINT32_T)
       set (JSON_UINT32 uint32_t)
    elseif (HAVE___UINT32)
       set (JSON_UINT32 __uint32)
    elseif (HAVE_UNSIGNED_LONG_INT AND (${UNSIGNED_LONG_INT} EQUAL 4))
       set (JSON_UINT32 "unsigned long")
    elseif (HAVE_UNSIGNED_INT AND (${UNSIGNED_INT} EQUAL 4))
       set (JSON_UINT32 "unsigned int")
    else ()
       message (FATAL_ERROR "Could not detect a valid unsigned 32-bit integer type")
    endif ()

    check_type_size (uint16_t UINT16_T)
    check_type_size (__uint16 __UINT16)
    if (HAVE_UINT16_T)
       set (JSON_UINT16 uint16_t)
    elseif (HAVE___UINT16)
       set (JSON_UINT16 __uint16)
    elseif (HAVE_UNSIGNED_INT AND (${UNSIGNED_INT} EQUAL 2))
       set (JSON_UINT16 "unsigned int")
    elseif (HAVE_UNSIGNED_SHORT AND (${UNSIGNED_SHORT} EQUAL 2))
       set (JSON_UINT16 "unsigned short")
    else ()
       message (FATAL_ERROR "Could not detect a valid unsigned 16-bit integer type")
    endif ()

    check_type_size (uint8_t UINT8_T)
    check_type_size (__uint8 __UINT8)
    if (HAVE_UINT8_T)
       set (JSON_UINT8 uint8_t)
    elseif (HAVE___UINT8)
       set (JSON_UINT8 __uint8)
    else ()
       set (JSON_UINT8 "unsigned char")
    endif ()

    # Check for ssize_t and SSIZE_T existance.
    check_type_size(ssize_t SSIZE_T)
    check_type_size(SSIZE_T UPPERCASE_SSIZE_T)
    if(NOT HAVE_SSIZE_T)
       if(HAVE_UPPERCASE_SSIZE_T)
          set(JSON_SSIZE SSIZE_T)
       else()
          set(JSON_SSIZE int)
       endif()
    endif()
    set(CMAKE_EXTRA_INCLUDE_FILES "")

    # Check for all the variants of strtoll
    check_function_exists (strtoll HAVE_STRTOLL)
    check_function_exists (strtoq HAVE_STRTOQ)
    check_function_exists (_strtoi64 HAVE__STRTOI64)

    # Figure out what variant we should use
    if (HAVE_STRTOLL)
       set (JSON_STRTOINT strtoll)
    elseif (HAVE_STRTOQ)
       set (JSON_STRTOINT strtoq)
    elseif (HAVE__STRTOI64)
       set (JSON_STRTOINT _strtoi64)
    else ()
       # fallback to strtol (32 bit)
       # this will set all the required variables
       set (JSON_STRTOINT strtol)
       set (JSON_INT_T long)
       set (JSON_INTEGER_FORMAT "\"ld\"")
    endif ()

    # if we haven't defined JSON_INT_T, then we have a 64 bit conversion function.
    # detect what to use for the 64 bit type.
    # Note: I will prefer long long if I can get it, as that is what the automake system aimed for.
    if (NOT DEFINED JSON_INT_T)
       if (HAVE_LONG_LONG_INT AND (${LONG_LONG_INT} EQUAL 8))
          set (JSON_INT_T "long long")
       elseif (HAVE_INT64_T)
          set (JSON_INT_T int64_t)
       elseif (HAVE___INT64)
          set (JSON_INT_T __int64)
       else ()
          message (FATAL_ERROR "Could not detect 64 bit type, although I detected the strtoll equivalent")
       endif ()

       # Apparently, Borland BCC and MSVC wants I64d,
       # Borland BCC could also accept LD
       # and gcc wants ldd,
       # I am not sure what cygwin will want, so I will assume I64d

       if (WIN32) # matches both msvc and cygwin
          set (JSON_INTEGER_FORMAT "\"I64d\"")
       else ()
          set (JSON_INTEGER_FORMAT "\"lld\"")
       endif ()
    endif ()


    # If locale.h and localeconv() are available, define to 1, otherwise to 0.
    check_include_files (locale.h HAVE_LOCALE_H)
    check_function_exists (localeconv HAVE_LOCALECONV)

    if (HAVE_LOCALECONV AND HAVE_LOCALE_H)
       set (JSON_HAVE_LOCALECONV 1)
    else ()
       set (JSON_HAVE_LOCALECONV 0)
    endif()

    # check if we have setlocale
    check_function_exists(setlocale HAVE_SETLOCALE)

    # Check what the inline keyword is.
    # Note that the original JSON_INLINE was always set to just 'inline', so this goes further.
    check_function_keywords("inline")
    check_function_keywords("__inline")
    check_function_keywords("__inline__")

    if (HAVE_INLINE)
       set(JSON_INLINE inline)
    elseif (HAVE___INLINE)
       set(JSON_INLINE __inline)
    elseif (HAVE___INLINE__)
       set(JSON_INLINE __inline__)
    else()
       # no inline on this platform
       set (JSON_INLINE)
    endif()

    check_c_source_compiles ("int main() { unsigned long val; __sync_bool_compare_and_swap(&val, 0, 1); return 0; } " HAVE_SYNC_BUILTINS)
    check_c_source_compiles ("int main() { char l; unsigned long v; __atomic_test_and_set(&l, __ATOMIC_RELAXED); __atomic_store_n(&v, 1, __ATOMIC_RELEASE); __atomic_load_n(&v, __ATOMIC_ACQUIRE); return 0; }" HAVE_ATOMIC_BUILTINS)

    # configure the public config file
    configure_file (${CMAKE_CURRENT_SOURCE_DIR}/cmake/jansson_config.h.cmake
                    ${CMAKE_CURRENT_BINARY_DIR}/include/jansson_config.h)

    # Copy the jansson.h file to the public include folder
    file (COPY ${CMAKE_CURRENT_SOURCE_DIR}/src/jansson.h
               DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/include/)

    add_definitions(-DJANSSON_USING_CMAKE)

    # configure the private config file
    configure_file (${CMAKE_CURRENT_SOURCE_DIR}/cmake/jansson_private_config.h.cmake
                    ${CMAKE_CURRENT_BINARY_DIR}/private_include/jansson_private_config.h)

    # and tell the source code to include it
    add_definitions(-DHAVE_CONFIG_H)

    # Add the lib sources.
    file(GLOB JANSSON_SRC src/*.c)

    set(JANSSON_HDR_PRIVATE
       ${CMAKE_CURRENT_SOURCE_DIR}/src/hashtable.h
       ${CMAKE_CURRENT_SOURCE_DIR}/src/jansson_private.h
       ${CMAKE_CURRENT_SOURCE_DIR}/src/strbuffer.h
       ${CMAKE_CURRENT_SOURCE_DIR}/src/utf.h
       ${CMAKE_CURRENT_BINARY_DIR}/private_include/jansson_private_config.h)

    set(JANSSON_HDR_PUBLIC
       ${CMAKE_CURRENT_BINARY_DIR}/include/jansson_config.h
       ${CMAKE_CURRENT_SOURCE_DIR}/src/jansson.h)

    source_group("Library Sources" FILES ${JANSSON_SRC})
    source_group("Library Private Headers" FILES ${JANSSON_HDR_PRIVATE})
    source_group("Library Public Headers" FILES ${JANSSON_HDR_PUBLIC})

    add_library(jansson
      ${JANSSON_SRC}
      ${JANSSON_HDR_PRIVATE}
      ${JANSSON_HDR_PUBLIC})
      
    # Disable warnings if building from source
    suppress_warnings(jansson)

    set_target_properties(jansson PROPERTIES FOLDER "3rdparty")

    target_include_directories(jansson SYSTEM PUBLIC ${CMAKE_CURRENT_BINARY_DIR}/include)
    target_include_directories(jansson PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/private_include)
	target_link_libraries(jansson PUBLIC compiler)
endif()
