include(CheckIncludeFiles)
include(CheckIncludeFile)
include(CheckSymbolExists)
include(CheckTypeSize)
include(CheckTypeSizeN)
include(CheckFunctionKeywords)
include(CheckLFS)

## Checks for header files ##
check_include_file("inttypes.h" HAVE_INTTYPES_H)
check_include_file("memory.h" HAVE_MEMORY_H)
check_include_file("stddef.h" HAVE_STDDEF_H)
check_include_file("stdint.h" HAVE_STDINT_H)
check_include_file("stdlib.h" HAVE_STDLIB_H)
check_include_file("string.h" HAVE_STRING_H)
check_include_file("strings.h" HAVE_STRINGS_H)
check_include_file("sys/types.h" HAVE_SYS_TYPES_H)
if(HAVE_INTTYPES_H)
  set(INCFILE "#include <inttypes.h>")
elseif(HAVE_STDINT_H)
  set(INCFILE "#include <stdint.h>")
else(HAVE_INTTYPES_H)
  set(INCFILE "")
endif(HAVE_INTTYPES_H)

if(BUILD_EXAMPLES)
  ## Checks for WinIO ##
  if(WIN32)
    check_include_file("io.h" HAVE_IO_H)
    check_include_file("fcntl.h" HAVE_FCNTL_H)
    check_symbol_exists("_setmode" "io.h;fcntl.h" HAVE__SETMODE)
    if(NOT HAVE__SETMODE)
      check_symbol_exists("setmode" "io.h;fcntl.h" HAVE_SETMODE)
    endif(NOT HAVE__SETMODE)
    check_symbol_exists("_fileno" "stdio.h" HAVE__FILENO)
    check_symbol_exists("fopen_s" "stdio.h" HAVE_FOPEN_S)
    check_symbol_exists("_O_BINARY" "fcntl.h" HAVE__O_BINARY)
  endif(WIN32)

  ## Checks for large file support ##
  check_lfs(WITH_LFS)
  configure_file("${CMAKE_CURRENT_SOURCE_DIR}/lfs.h.cmake" "${CMAKE_CURRENT_BINARY_DIR}/lfs.h" @ONLY)
endif(BUILD_EXAMPLES)

## Checks for keywords ##
check_function_keywords("inline;__inline;__inline__;__declspec(dllexport);__declspec(dllimport)")
if(HAVE_INLINE)
  set(INLINE "inline")
elseif(HAVE___INLINE)
  set(INLINE "__inline")
elseif(HAVE___INLINE__)
  set(INLINE "__inline__")
else(HAVE_INLINE)
  set(INLINE "")
endif(HAVE_INLINE)
set(DLL_IMPORT "")
set(DLL_EXPORT "")
if(BUILD_SHARED_LIBS)
  if(HAVE___DECLSPEC_DLLIMPORT_)
    set(DLL_IMPORT "__declspec(dllimport)")
  endif(HAVE___DECLSPEC_DLLIMPORT_)
  if(HAVE___DECLSPEC_DLLEXPORT_)
    set(DLL_EXPORT "__declspec(dllexport)")
  endif(HAVE___DECLSPEC_DLLEXPORT_)
endif(BUILD_SHARED_LIBS)

## Checks for types ##
# unsigned 8-bit integer type
check_type_size_n("uint8_t;unsigned char;unsigned __int8" 1 U8_TYPE)
if(NOT HAVE_U8_TYPE)
  message(FATAL_ERROR "Could not find unsigned 8-bit integer type")
endif(NOT HAVE_U8_TYPE)
# unsigned 16-bit integer type
check_type_size_n("uint16_t;unsigned short int;unsigned __int16;unsigned int" 2 U16_TYPE)
if(NOT HAVE_U16_TYPE)
  message(FATAL_ERROR "Could not find unsigned 16-bit integer type")
endif(NOT HAVE_U16_TYPE)
# signed 32-bit integer type
check_type_size_n("int32_t;signed int;signed long int;signed short int;signed __int32" 4 I32_TYPE)
if(NOT HAVE_I32_TYPE)
  message(FATAL_ERROR "Could not find signed 32-bit integer type")
endif(NOT HAVE_I32_TYPE)
set(PRIdINT32 "\"d\"")
set(SA_INT32_C "val")
set(SA_UINT32_C "val##u")
if("${I32_TYPE}" STREQUAL "int32_t")
  check_symbol_exists("PRId32" "inttypes.h" HAVE_PRID32)
  if(HAVE_PRID32)
    set(PRIdINT32 "PRId32")
  endif(HAVE_PRID32)
  check_symbol_exists("INT32_C" "stdint.h" HAVE_INT32_C)
  if(HAVE_INT32_C)
    set(SA_INT32_C "INT32_C(val)")
  endif(HAVE_INT32_C)
  check_symbol_exists("UINT32_C" "stdint.h" HAVE_UINT32_C)
  if(HAVE_UINT32_C)
    set(SA_UINT32_C "UINT32_C(val)")
  endif(HAVE_UINT32_C)
elseif("${I32_TYPE}" STREQUAL "signed long int")
  set(PRIdINT32 "\"ld\"")
  set(SA_INT32_C "val##L")
  set(SA_UINT32_C "val##UL")
elseif("${I32_TYPE}" STREQUAL "signed __int32")
  set(PRIdINT32 "\"I32d\"")
  set(SA_INT32_C "val##i32")
  set(SA_UINT32_C "val##ui32")
endif("${I32_TYPE}" STREQUAL "int32_t")

if(BUILD_SAIS64)
  # unsigned 32-bit integer type
  check_type_size_n("uint32_t;unsigned int;unsigned long int;unsigned short int;unsigned __int32" 4 U32_TYPE)
  if(NOT HAVE_U32_TYPE)
    message(FATAL_ERROR "Could not find unsigned 32-bit integer type")
  endif(NOT HAVE_U32_TYPE)
  # signed 64-bit integer type
  check_type_size_n("int64_t;signed long long int;signed __int64;signed long int;signed int" 8 I64_TYPE)
  if(NOT HAVE_I64_TYPE)
    message(SEND_ERROR "Could not find signed 64-bit integer type")
    set(BUILD_SAIS64 OFF)
  endif(NOT HAVE_I64_TYPE)
  set(PRIdINT64 "\"lld\"")
  set(SA_INT64_C "val##LL")
  if("${I64_TYPE}" STREQUAL "int64_t")
    check_symbol_exists("PRId64" "inttypes.h" HAVE_PRID64)
    if(HAVE_PRID64)
      set(PRIdINT64 "PRId64")
    endif(HAVE_PRID64)
    check_symbol_exists("INT64_C" "stdint.h" HAVE_INT64_C)
    if(HAVE_INT64_C)
      set(SA_INT64_C "INT64_C(val)")
    endif(HAVE_INT64_C)
  elseif("${I64_TYPE}" STREQUAL "signed __int64")
    set(PRIdINT64 "\"I64d\"")
    set(SA_INT64_C "val##i64")
  elseif("${I64_TYPE}" STREQUAL "signed long int")
    set(PRIdINT64 "\"ld\"")
    set(SA_INT64_C "val##L")
  elseif("${I64_TYPE}" STREQUAL "signed int")
    set(PRIdINT64 "\"d\"")
    set(SA_INT64_C "val")
  endif("${I64_TYPE}" STREQUAL "int64_t")
endif(BUILD_SAIS64)

## generate config.h ##
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/sais_config.h.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/sais_config.h")

## generate sais.h ##
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/sais.h.in"
               "${CMAKE_CURRENT_BINARY_DIR}/sais.h" @ONLY)
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/sais.h" DESTINATION include)
if(BUILD_SAIS64)
  configure_file("${CMAKE_CURRENT_SOURCE_DIR}/sais64.h.in"
                 "${CMAKE_CURRENT_BINARY_DIR}/sais64.h" @ONLY)
  install(FILES "${CMAKE_CURRENT_BINARY_DIR}/sais64.h" DESTINATION include)
endif(BUILD_SAIS64)
install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/sais.hxx" DESTINATION include)
