IF(DEFINED CMAKE_CROSSCOMPILING)
  # subsequent toolchain loading is not really needed
  RETURN()
ENDIF()

# Standard settings
SET(CMAKE_SYSTEM_NAME Linux)
SET(CMAKE_SYSTEM_VERSION 1) # TODO: determine target Linux version
SET(UNIX ON)
SET(LINUX ON)
SET(ANDROID ON)

IF(NOT NDK_ROOT)
  SET(NDK_ROOT $ENV{NDK_ROOT})

  IF(CMAKE_HOST_WIN32)
    FILE(TO_CMAKE_PATH ${NDK_ROOT} NDK_ROOT)
  ENDIF()
ENDIF()

IF(NOT TARGET_CPU)
  SET(TARGET_CPU "armv7")
ENDIF()

IF(TARGET_CPU STREQUAL "armv7")
  SET(LIBRARY_ARCHITECTURE "armeabi-v7a")
  SET(CMAKE_SYSTEM_PROCESSOR "armv7")
  SET(TOOLCHAIN_ARCH "arm")
  SET(GCC_TOOLCHAIN_PREFIX "arm-linux-androideabi")
  SET(TOOLCHAIN_BIN_PREFIX "arm-linux-androideabi")
  SET(MINIMUM_NDK_TARGET 4)
ELSEIF(TARGET_CPU STREQUAL "armv5")
  SET(LIBRARY_ARCHITECTURE "armeabi")
  SET(CMAKE_SYSTEM_PROCESSOR "armv5")
  SET(TOOLCHAIN_ARCH "arm")
  SET(GCC_TOOLCHAIN_PREFIX "arm-linux-androideabi")
  SET(TOOLCHAIN_BIN_PREFIX "arm-linux-androideabi")
  SET(MINIMUM_NDK_TARGET 4)
ELSEIF(TARGET_CPU STREQUAL "arm64")
  SET(LIBRARY_ARCHITECTURE "arm64-v8a")
  SET(CMAKE_SYSTEM_PROCESSOR "arm64")
  SET(TOOLCHAIN_ARCH "arm64")
  SET(GCC_TOOLCHAIN_PREFIX "aarch64-linux-android")
  SET(TOOLCHAIN_BIN_PREFIX "aarch64-linux-android")
  SET(MINIMUM_NDK_TARGET 21)
ELSEIF(TARGET_CPU STREQUAL "x86")
  SET(LIBRARY_ARCHITECTURE "x86")
  SET(CMAKE_SYSTEM_PROCESSOR "x86")
  SET(TOOLCHAIN_ARCH "x86")
  SET(GCC_TOOLCHAIN_PREFIX "x86")
  SET(TOOLCHAIN_BIN_PREFIX "i686-linux-android")
  SET(MINIMUM_NDK_TARGET 9)
ELSEIF(TARGET_CPU STREQUAL "x86_64")
  SET(LIBRARY_ARCHITECTURE "x86_64")
  SET(CMAKE_SYSTEM_PROCESSOR "x86_64")
  SET(TOOLCHAIN_ARCH "x86_64")
  SET(GCC_TOOLCHAIN_PREFIX "x86_64")
  SET(TOOLCHAIN_BIN_PREFIX "x86_64-linux-android")
  SET(MINIMUM_NDK_TARGET 21)
ELSEIF(TARGET_CPU STREQUAL "mips")
  SET(LIBRARY_ARCHITECTURE "mips")
  SET(CMAKE_SYSTEM_PROCESSOR "mips")
  SET(TOOLCHAIN_ARCH "mips")
  SET(GCC_TOOLCHAIN_PREFIX "mipsel-linux-android")
  SET(TOOLCHAIN_BIN_PREFIX "mipsel-linux-android")
  SET(MINIMUM_NDK_TARGET 9)
ELSEIF(TARGET_CPU STREQUAL "mips64")
  SET(LIBRARY_ARCHITECTURE "mips64")
  SET(CMAKE_SYSTEM_PROCESSOR "mips64")
  SET(TOOLCHAIN_ARCH "mips64")
  SET(GCC_TOOLCHAIN_PREFIX "mips64el-linux-android")
  SET(TOOLCHAIN_BIN_PREFIX "mips64el-linux-android")
  SET(MINIMUM_NDK_TARGET 21)
ELSE()
  MESSAGE(FATAL_ERROR "Unable to process TARGET_CPU ${TARGET_CPU}")
ENDIF()

SET(CLANG_TOOLCHAIN_PREFIX "llvm")
SET(ANDROID_COMPILER "GCC")

IF(NDK_TOOLCHAIN_VERSION STREQUAL "clang")
  SET(ANDROID_COMPILER "clang")
  SET(CLANG ON)
ELSE()
  SET(GCC_TOOLCHAIN_VERSION ${NDK_TOOLCHAIN_VERSION})
ENDIF()

IF(NOT NDK_TARGET)
  SET(NDK_TARGET ${MINIMUM_NDK_TARGET})
ELSE()
  IF(NDK_TARGET LESS MINIMUM_NDK_TARGET)
    SET(NDK_TARGET ${MINIMUM_NDK_TARGET})
  ENDIF()
ENDIF()

IF(CMAKE_HOST_WIN32)
  SET(TOOLCHAIN_HOST "windows")
  SET(TOOLCHAIN_BIN_SUFFIX ".exe")
ELSEIF(CMAKE_HOST_APPLE)
  SET(TOOLCHAIN_HOST "apple")
  SET(TOOLCHAIN_BIN_SUFFIX "")
ELSEIF(CMAKE_HOST_UNIX)
  SET(TOOLCHAIN_HOST "linux")
  SET(TOOLCHAIN_BIN_SUFFIX "")
ENDIF()

MACRO(SEARCH_TOOLCHAIN _COMPILER)
  SET(${_COMPILER}_TOOLCHAIN_VERSIONS)
  FILE(GLOB _TOOLCHAIN_VERSIONS "${NDK_ROOT}/toolchains/${${_COMPILER}_TOOLCHAIN_PREFIX}-*")
  IF(_TOOLCHAIN_VERSIONS)
    LIST(SORT _TOOLCHAIN_VERSIONS)
    LIST(REVERSE _TOOLCHAIN_VERSIONS)
    FOREACH(_TOOLCHAIN_VERSION ${_TOOLCHAIN_VERSIONS})
      STRING(REGEX REPLACE ".+${_PREFIX}-([0-9.]+)" "\\1" _TOOLCHAIN_VERSION "${_TOOLCHAIN_VERSION}")
      IF(_TOOLCHAIN_VERSION MATCHES "^([0-9.]+)$")
        LIST(APPEND ${_COMPILER}_TOOLCHAIN_VERSIONS ${_TOOLCHAIN_VERSION})
      ENDIF()
    ENDFOREACH()
  ENDIF()

  # try prefixes without version
  SET(_TOOLCHAIN_WITHOUT_VERSION "${NDK_ROOT}/toolchains/${${_COMPILER}_TOOLCHAIN_PREFIX}")
  IF(EXISTS ${_TOOLCHAIN_WITHOUT_VERSION})
    LIST(APPEND ${_COMPILER}_TOOLCHAIN_VERSIONS "default")
  ENDIF()

  IF(NOT ${_COMPILER}_TOOLCHAIN_VERSIONS)
    MESSAGE(FATAL_ERROR "No Android ${_COMPILER} toolchain found in default search path ${NDK_ROOT}/toolchains")
  ENDIF()

  IF(${_COMPILER}_TOOLCHAIN_VERSIONS)
    LIST(FIND ${_COMPILER}_TOOLCHAIN_VERSIONS "${${_COMPILER}_TOOLCHAIN_VERSION}" _INDEX)
    IF(_INDEX EQUAL -1)
      LIST(GET ${_COMPILER}_TOOLCHAIN_VERSIONS 0 ${_COMPILER}_TOOLCHAIN_VERSION)
    ENDIF()
  ELSE()
    LIST(GET ${_COMPILER}_TOOLCHAIN_VERSIONS 0 ${_COMPILER}_TOOLCHAIN_VERSION)
  ENDIF()

  MESSAGE(STATUS "TOOLCHAIN_PREFIX = ${${_COMPILER}_TOOLCHAIN_VERSION}")

  IF("${${_COMPILER}_TOOLCHAIN_VERSION}" STREQUAL "default")
    MESSAGE(STATUS "default")
    SET(${_COMPILER}_TOOLCHAIN_ROOT "${NDK_ROOT}/toolchains/${${_COMPILER}_TOOLCHAIN_PREFIX}/prebuilt/${TOOLCHAIN_HOST}")
  ELSE()
    MESSAGE(STATUS "not default")
    SET(${_COMPILER}_TOOLCHAIN_ROOT "${NDK_ROOT}/toolchains/${${_COMPILER}_TOOLCHAIN_PREFIX}-${${_COMPILER}_TOOLCHAIN_VERSION}/prebuilt/${TOOLCHAIN_HOST}")
  ENDIF()

  IF(NOT EXISTS "${${_COMPILER}_TOOLCHAIN_ROOT}")
    FILE(GLOB _TOOLCHAIN_PREFIXES "${${_COMPILER}_TOOLCHAIN_ROOT}*")
    IF(_TOOLCHAIN_PREFIXES)
      LIST(GET _TOOLCHAIN_PREFIXES 0 ${_COMPILER}_TOOLCHAIN_ROOT)
    ENDIF()
  ENDIF()
ENDMACRO()

IF(CLANG)
  SEARCH_TOOLCHAIN(CLANG)

  MESSAGE(STATUS "Target Android NDK ${NDK_TARGET} and use clang ${CLANG_TOOLCHAIN_VERSION}")
ENDIF()

SEARCH_TOOLCHAIN(GCC)

MESSAGE(STATUS "Target Android NDK ${NDK_TARGET} and use GCC ${GCC_TOOLCHAIN_VERSION}")

IF(CLANG_TOOLCHAIN_ROOT)
  MESSAGE(STATUS "Found Android LLVM toolchain in ${CLANG_TOOLCHAIN_ROOT}")
ENDIF()

IF(GCC_TOOLCHAIN_ROOT)
  MESSAGE(STATUS "Found Android GCC toolchain in ${GCC_TOOLCHAIN_ROOT}")
ENDIF()

SET(PLATFORM_ROOT "${NDK_ROOT}/platforms/android-${NDK_TARGET}/arch-${TOOLCHAIN_ARCH}")

MESSAGE(STATUS "Found Android platform in ${PLATFORM_ROOT}")

# include dirs
SET(PLATFORM_INCLUDE_DIR "${PLATFORM_ROOT}/usr/include")
SET(STL_DIR "${NDK_ROOT}/sources/cxx-stl/gnu-libstdc++")

IF(EXISTS "${STL_DIR}/${GCC_TOOLCHAIN_VERSION}")
  # NDK version >= 8b
  SET(STL_DIR "${STL_DIR}/${GCC_TOOLCHAIN_VERSION}")
ENDIF()

SET(STL_INCLUDE_DIR "${STL_DIR}/include")
SET(STL_LIBRARY_DIR "${STL_DIR}/libs/${LIBRARY_ARCHITECTURE}")
SET(STL_INCLUDE_CPU_DIR "${STL_LIBRARY_DIR}/include")
SET(STL_LIBRARY "${STL_LIBRARY_DIR}/libgnustl_static.a")

MESSAGE(STATUS "STL include dir: ${STL_INCLUDE_DIR}")
MESSAGE(STATUS "STL library dir: ${STL_LIBRARY_DIR}")

SET(CMAKE_FIND_ROOT_PATH ${CLANG_TOOLCHAIN_ROOT} ${GCC_TOOLCHAIN_ROOT} ${PLATFORM_ROOT}/usr ${CMAKE_PREFIX_PATH} ${CMAKE_INSTALL_PREFIX} $ENV{EXTERNAL_ANDROID_PATH} CACHE string  "Android find search path root")

SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM ONLY)
SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)

MACRO(SET_TOOLCHAIN_BINARY_LLVM _NAME _BINARY)
  SET(${_NAME} ${CLANG_TOOLCHAIN_ROOT}/bin/${_BINARY}${TOOLCHAIN_BIN_SUFFIX} CACHE PATH "" FORCE)
ENDMACRO()

MACRO(SET_TOOLCHAIN_BINARY_GCC _NAME _BINARY)
  SET(${_NAME} ${GCC_TOOLCHAIN_ROOT}/bin/${TOOLCHAIN_BIN_PREFIX}-${_BINARY}${TOOLCHAIN_BIN_SUFFIX} CACHE PATH "" FORCE)
ENDMACRO()

# Force the compilers to GCC for Android
include (CMakeForceCompiler)

IF(CLANG)
  MESSAGE(STATUS "Using clang compiler")

  SET_TOOLCHAIN_BINARY_LLVM(CMAKE_C_COMPILER clang)
  SET_TOOLCHAIN_BINARY_LLVM(CMAKE_CXX_COMPILER clang++)

  CMAKE_FORCE_C_COMPILER(${CMAKE_C_COMPILER} clang)
  CMAKE_FORCE_CXX_COMPILER(${CMAKE_CXX_COMPILER} clang)

  SET_TOOLCHAIN_BINARY_LLVM(CMAKE_ASM_COMPILER llvm-as)
  SET_TOOLCHAIN_BINARY_LLVM(CMAKE_AR llvm-ar)
  SET_TOOLCHAIN_BINARY_LLVM(CMAKE_LINKER clang++)

  IF(NOT EXISTS "${CMAKE_ASM_COMPILER}")
    SET_TOOLCHAIN_BINARY_GCC(CMAKE_ASM_COMPILER as)
  ENDIF()

  IF(NOT EXISTS "${CMAKE_AR}")
    SET_TOOLCHAIN_BINARY_GCC(CMAKE_AR ar)
  ENDIF()
ELSE()
  MESSAGE(STATUS "Using GCC compiler")

  SET_TOOLCHAIN_BINARY_GCC(CMAKE_C_COMPILER gcc)
  SET_TOOLCHAIN_BINARY_GCC(CMAKE_CXX_COMPILER g++)

  CMAKE_FORCE_C_COMPILER(${CMAKE_C_COMPILER} GNU)
  CMAKE_FORCE_CXX_COMPILER(${CMAKE_CXX_COMPILER} GNU)

  SET_TOOLCHAIN_BINARY_GCC(CMAKE_ASM_COMPILER as)
  SET_TOOLCHAIN_BINARY_GCC(CMAKE_AR ar)
  SET_TOOLCHAIN_BINARY_GCC(CMAKE_LINKER ld)
ENDIF()

SET_TOOLCHAIN_BINARY_GCC(CMAKE_STRIP strip)
SET_TOOLCHAIN_BINARY_GCC(CMAKE_NM nm)
SET_TOOLCHAIN_BINARY_GCC(CMAKE_OBJCOPY objcopy)
SET_TOOLCHAIN_BINARY_GCC(CMAKE_OBJDUMP objdump)
SET_TOOLCHAIN_BINARY_GCC(CMAKE_RANLIB ranlib)