# -*- cmake -*-

find_program(bim_android_config_bin bim-android-config REQUIRED)
find_program(gradlew_bin gradlew REQUIRED)
find_program(identify identify REQUIRED)
find_program(magick magick REQUIRED)
find_program(paco_info_bin paco-info REQUIRED)

# The directory with the binaries from the host, needed to get axslcc
# in Android builds below.
cmake_path(GET magick PARENT_PATH host_bin)

if(BIM_ANDROID_DEV)
  set(bim_android_app_id "bim.app.dev")
  set(bim_android_app_name "Bim! (dev)")
  set(bim_android_signing_key_alias "bim-dev-release")
else()
  set(bim_android_app_id "bim.app")
  set(bim_android_app_name "Bim!")
  set(bim_android_signing_key_alias "bim-release")
endif()

# These variables will be injected in the Groovy scripts to build the
# Android app.
if(BIM_PURE_FOSS)
  set(bim_pure_foss true)
else()
  set(bim_pure_foss false)
endif()

# Where the static part of the Android project is located (e.g. the
# Java source of the game).
set(bim_app_java_dir "${CMAKE_CURRENT_LIST_DIR}/modules/bim/app/java")
set(android_app_root_dir "${CMAKE_CURRENT_LIST_DIR}/android")

# Where we generate the configured project.
set(generated_project_root "${CMAKE_CURRENT_BINARY_DIR}/android-project")

function(bim_android_config out_var)
  execute_process(
    COMMAND "${bim_android_config_bin}" ${ARGN}
    OUTPUT_VARIABLE output
  )
  string(REGEX REPLACE "\n$" "" output "${output}")
  set(${out_var} "${output}" PARENT_SCOPE)
endfunction()

function(paco_package_version out_var package)
  execute_process(
    COMMAND
      "${paco_info_bin}"
      --prefix "${BIM_TARGET_PREFIX}"
      --name ${package}
    OUTPUT_VARIABLE output
  )

  if("${output}" MATCHES "is not installed")
    message(
      FATAL_ERROR
      "Could not find package '${package}' in ${BIM_TARGET_PREFIX}"
    )
  endif()

  string(REGEX REPLACE "Version:([^\n]+)\n.+" "\\1" output "${output}")
  set(${out_var} "${output}" PARENT_SCOPE)
endfunction()

# Collect some settings from bim-android-config. We need them in this
# CMakeLists.txt but also to inject them in the build.gradle files.
bim_android_config(bim_android_gradle_plugin_version --gradle-plugin-version)
bim_android_config(
  bim_android_local_maven
  --prefix "${BIM_TARGET_PREFIX}" --maven-root
)
bim_android_config(
  bim_android_platform --prefix "${CMAKE_PREFIX_PATH}" --platform
)
bim_android_config(bim_android_ndk_version
    --prefix "${CMAKE_PREFIX_PATH}" --ndk-version
)
bim_android_config(bim_android_sdk_root
    --prefix "${CMAKE_PREFIX_PATH}" --sdk-root
)
bim_android_config(bim_android_stl --stl)
bim_android_config(
  bim_android_target_sdk_version
  --prefix "${CMAKE_PREFIX_PATH}" --target-sdk-version
)
bim_android_config(
  bim_android_min_sdk_version
  --prefix "${CMAKE_PREFIX_PATH}" --min-sdk-version
)
bim_android_config(
  bim_android_toolchain --prefix "${CMAKE_PREFIX_PATH}" --toolchain
)

bim_android_config(bim_android_archs_default --arch)
string(
  REPLACE
  "\n" ";"
  bim_android_archs_default
  "${bim_android_archs_default}"
)

set(
  BIM_ARCHITECTURES
  ${bim_android_archs_default}
  CACHE
  STRING
  "Target architectures for the Android build."
)
message(STATUS "Building for Android architectures ${BIM_ARCHITECTURES}")

# Create a target to build libbim.so for a given Android architecture,
# by invoking the root CMakeLists.txt again but configured with the
# Android toolchain.
function(recursive_android_build)
  cmake_parse_arguments(ARG
    ""
    "AXMOL_SHADERS;ARCH"
    "DEPENDS"
    ${ARGV}
  )

  bim_android_config(bim_android_abi --abi "${ARG_ARCH}")
  set(lib_install_dir "${generated_project_root}/app/libs/${bim_android_abi}")
  set(arch_project_dir "${CMAKE_CURRENT_BINARY_DIR}/${ARG_ARCH}")

  add_custom_command(
    OUTPUT "${arch_project_dir}/CMakeCache.txt"
    COMMAND "${CMAKE_COMMAND}" -E make_directory "${arch_project_dir}"
    COMMAND "${CMAKE_COMMAND}"
      -B "${arch_project_dir}"
      -S "${CMAKE_CURRENT_SOURCE_DIR}"
      -DANDROID_USE_LEGACY_TOOLCHAIN_FILE=OFF
      -DCMAKE_TOOLCHAIN_FILE="${bim_android_toolchain}"
      -DANDROID_ABI="${bim_android_abi}"
      -DANDROID_PLATFORM="${bim_android_platform}"
      -DANDROID_STL="${bim_android_stl}"
      -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}
      -DCMAKE_C_COMPILER_LAUNCHER=${CMAKE_C_COMPILER_LAUNCHER}
      -DCMAKE_CXX_COMPILER_LAUNCHER=${CMAKE_CXX_COMPILER_LAUNCHER}
      -DCMAKE_FIND_ROOT_PATH="${BIM_TARGET_PREFIX}"
      -DCMAKE_INSTALL_PREFIX="${CMAKE_CURRENT_BINARY_DIR}/install-${ARG_ARCH}"
      -DCMAKE_PREFIX_PATH="${BIM_TARGET_PREFIX}"
      -DCMAKE_UNITY_BUILD=${CMAKE_UNITY_BUILD}
      -DCMAKE_UNITY_BUILD_BATCH_SIZE=${CMAKE_UNITY_BUILD_BATCH_SIZE}
      -DBIM_HOST_BIN="${host_bin}"
      -DBIM_ANDROID_DEV=${BIM_ANDROID_DEV}
      -DBIM_BUILDING_FOR_ANDROID=TRUE
      -DBIM_BUILD_TESTS=FALSE
      -DBIM_BUILD_SERVER=FALSE
      -DBIM_ENABLE_TRACY=${BIM_ENABLE_TRACY}
      -DBIM_INSTALL_AXMOL_SHADERS=${ARG_AXMOL_SHADERS}
      -DBIM_PURE_FOSS="${BIM_PURE_FOSS}"
      -DCMAKE_INTERPROCEDURAL_OPTIMIZATION=${CMAKE_INTERPROCEDURAL_OPTIMIZATION}
      -DBIM_GENERATED_ASSETS_DIR="${BIM_GENERATED_ASSETS_DIR}"
    )

  set(bim_targets bim)

  if(ARG_AXMOL_SHADERS)
    set(bim_targets ${bim_targets} shaders)
  endif()

  add_custom_target("${ARG_ARCH}"
    COMMAND
      "${CMAKE_COMMAND}"
      --build "${CMAKE_CURRENT_BINARY_DIR}/${ARG_ARCH}" --target ${bim_targets}
    COMMAND
      "${CMAKE_COMMAND}" -E make_directory "${lib_install_dir}"
    COMMAND
      "${CMAKE_COMMAND}" -E copy
      "${CMAKE_CURRENT_BINARY_DIR}/${ARG_ARCH}/apps/android/libbim.so"
      "${lib_install_dir}"
    DEPENDS "${arch_project_dir}/CMakeCache.txt" ${ARG_DEPENDS}
  )
endfunction()

function(generate_native_library_targets)
  # Create a build of the library for each architecture. Each library is
  # declared as dependent on the previous one to avoid concurrent
  # builds, directory creations, etc.
  set(install_axmol_shaders TRUE)
  set(all_archs)
  foreach(arch ${BIM_ARCHITECTURES})
    recursive_android_build(
      ARCH "${arch}"
      AXMOL_SHADERS ${install_axmol_shaders}
      DEPENDS ${all_archs}
    )
    set(install_axmol_shaders FALSE)
    set(all_archs ${all_archs} ${arch})
  endforeach()
endfunction()

function(generate_assets_target)
  set(assets_project_dir "${CMAKE_CURRENT_BINARY_DIR}/assets")

  # We need to build the assets using the host's tools.
  add_custom_command(
    OUTPUT "${assets_project_dir}/CMakeCache.txt"
    COMMAND
      "${CMAKE_COMMAND}" -E make_directory "${assets_project_dir}"
    COMMAND "${CMAKE_COMMAND}"
      -B "${assets_project_dir}"
      -S "${CMAKE_CURRENT_SOURCE_DIR}"
      -DCMAKE_FIND_ROOT_PATH="${CMAKE_FIND_ROOT_PATH}"
      -DCMAKE_PREFIX_PATH="${CMAKE_PREFIX_PATH}"
      -DBIM_BUILDING_FOR_ANDROID=TRUE
      -DBIM_GENERATED_ASSETS_DIR="${BIM_GENERATED_ASSETS_DIR}"
      -DBIM_ANDROID_GENERATED_RES_DIR="${BIM_ANDROID_GENERATED_RES_DIR}"
      -DBIM_TARGET=assets
  )

  add_custom_target(generated-assets
    COMMAND "${CMAKE_COMMAND}" --build "${assets_project_dir}" --target assets
    DEPENDS "${assets_project_dir}/CMakeCache.txt"
  )
endfunction()

# Finally, set-up the build of the APK.
function(configure_android_project)
  configure_file(
    "${android_app_root_dir}/build.gradle.in"
    "${generated_project_root}/build.gradle" @ONLY
  )

  configure_file(
    "${android_app_root_dir}/settings.gradle"
    "${generated_project_root}/" COPYONLY
  )

  configure_file(
    "${android_app_root_dir}/gradle.properties"
    "${generated_project_root}/" COPYONLY
  )

  # Collect the dependency versions from the installed packages.
  paco_package_version(axmol_version axmol)
  paco_package_version(iscool_core_version iscool-core)

  set(this_file_directory "${android_app_root_dir}/app")
  configure_file(
    "${android_app_root_dir}/app/build.gradle.in"
    "${generated_project_root}/app/build.gradle" @ONLY
  )
  unset(this_file_directory)
endfunction()

set(master_icon "${CMAKE_CURRENT_LIST_DIR}/metadata/en-US/images/icon.png")
execute_process(
  COMMAND "${identify}" -ping -format "%w" "${master_icon}"
  OUTPUT_VARIABLE master_icon_size
  COMMAND_ERROR_IS_FATAL ANY
)

function(generate_legacy_icon output dpi size)
  set(output_dir "${BIM_ANDROID_GENERATED_RES_DIR}/mipmap-${dpi}/")
  set(output_file "${output_dir}/ic_launcher.png")
  set(${output} ${${output}} ${output_file} PARENT_SCOPE)

  # The master icon has extra margins that we are going to remove.
  math(EXPR ref_size "74 * ${master_icon_size} / 100")
  math(EXPR ref_offset "(${master_icon_size} -${ref_size}) / 2")
  # Size for the rounded corners.
  math(EXPR ref_size_20_percents "20 * ${ref_size} / 100")

  if (BIM_ANDROID_DEV)
    set(additional_imagemagick_args -channel RGB -negate)
  else()
    set(additional_imagemagick_args)
  endif()

  add_custom_command(
    OUTPUT "${output_file}"
    COMMAND
      "${CMAKE_COMMAND}" -E make_directory "${output_dir}"
    COMMAND
      "${magick}"
      "${master_icon}"

      ${additional_imagemagick_args}
      # Remove the extra margin.
      -crop "${ref_size}x${ref_size}+${ref_offset}+${ref_offset}"
      # Rounded rectangle mask.
      -alpha set
      "\\\(" -size ${ref_size}x${ref_size}
        xc:none
        -draw
        "roundrectangle \
0,0,${ref_size},${ref_size},${ref_size_20_percents},${ref_size_20_percents}"
      "\\\)"
      -compose DstIn
      -composite
      -resize "${size}"
      -strip
      "${output_file}"
    DEPENDS "${master_icon}"
    )
endfunction()

function(generate_adaptive_icon output dpi size)
  set(output_dir "${BIM_ANDROID_GENERATED_RES_DIR}/mipmap-${dpi}/")
  set(output_file "${output_dir}/ic_launcher_round.png")
  set(${output} ${${output}} ${output_file} PARENT_SCOPE)

  # The master icon has extra margins that we are going to remove.
  math(EXPR ref_size "125 * ${master_icon_size} / 100")

  if (BIM_ANDROID_DEV)
    set(additional_imagemagick_args -channel RGB -negate)
  else()
    set(additional_imagemagick_args)
  endif()

  add_custom_command(
    OUTPUT "${output_file}"
    COMMAND
      "${CMAKE_COMMAND}" -E make_directory "${output_dir}"
    COMMAND
      "${magick}"
      "${master_icon}"
      # Pick the color of the top-left pixel.
      -set background "%[pixel:p{0,0}]"
      -gravity center
      -extent ${ref_size}x${ref_size}
      ${additional_imagemagick_args}
      -strip
      "${output_file}"
    DEPENDS "${master_icon}"
    )
endfunction()

generate_native_library_targets()
generate_assets_target()

set(dpis xxxhdpi xxhdpi xhdpi hdpi mdpi dpi)
set(sizes 432 324 216 162 108 81)

foreach(dpi size IN ZIP_LISTS dpis sizes)
  generate_legacy_icon(icons ${dpi} ${size})
  generate_adaptive_icon(icons ${dpi} ${size})
endforeach()

add_custom_target(generated-icons ALL DEPENDS ${icons})
add_dependencies(generated-assets generated-icons)

configure_android_project()

if ("${CMAKE_BUILD_TYPE}" STREQUAL "Release")
  set(java_build_type Release)
else()
  set(java_build_type Debug)
endif()

add_custom_target(aab ALL
  COMMAND
  ${CMAKE_COMMAND} -E env "ANDROID_HOME=${bim_android_sdk_root}"
  ${gradlew_bin} -p "${generated_project_root}" "bundle${java_build_type}"
  DEPENDS ${BIM_ARCHITECTURES} generated-assets
  USES_TERMINAL
)

add_custom_target(apk ALL
  COMMAND
  ${CMAKE_COMMAND} -E env "ANDROID_HOME=${bim_android_sdk_root}"
  ${gradlew_bin} -p "${generated_project_root}" "assemble${java_build_type}"
  DEPENDS ${BIM_ARCHITECTURES} generated-assets
  USES_TERMINAL
)

add_custom_target(apk-install
  COMMAND
  ${CMAKE_COMMAND} -E env "ANDROID_HOME=${bim_android_sdk_root}"
  ${gradlew_bin} -p "${generated_project_root}" "install${java_build_type}"
  DEPENDS apk
  USES_TERMINAL
)

if (BIM_ANDROID_DEV)
  add_custom_command(
    TARGET aab apk apk-install
    POST_BUILD
    COMMAND
      ${CMAKE_COMMAND} -E echo
      "-------------------------------------------------------"
    COMMAND
      ${CMAKE_COMMAND} -E echo
      "/!\\\\ This is a build for developers. DO NOT PUBLISH. /!\\\\"
    COMMAND
      ${CMAKE_COMMAND} -E echo
      "-------------------------------------------------------"
  )
endif()
