cmake_minimum_required(VERSION 3.10)
project(libqt6sql6-sqlcipher)

set(CMAKE_MODULE_PATH "${CMAKE_MODULE_PATH};${PROJECT_SOURCE_DIR}/cmake/")
set(QT_NO_PRIVATE_MODULE_WARNING ON)

SET(QSQLCIPHER_CMAKE_SEARCH_PATH "C:/Qt/6.10.0/msvc2022_64" CACHE PATH "Additional Qt6 search path" )

message(STATUS "QSQLCIPHER_CMAKE_SEARCH_PATH: ${QSQLCIPHER_CMAKE_SEARCH_PATH}")
SET(CMAKE_PREFIX_PATH "${CMAKE_PREFIX_PATH};${QSQLCIPHER_CMAKE_SEARCH_PATH}/lib/cmake/")

find_package(QT NAMES Qt6 REQUIRED COMPONENTS Core Sql SqlPrivate)
find_package(Qt6 REQUIRED COMPONENTS Core Sql SqlPrivate)

if (NOT WIN32)
	find_package(PkgConfig REQUIRED)
	pkg_check_modules(SQLCIPHER REQUIRED sqlcipher)
	if (DEFINED SQLCIPHER_LIBRARY_DIRS)
		link_directories(${SQLCIPHER_LIBRARY_DIRS})
		message(STATUS "Added ${SQLCIPHER_LIBRARY_DIRS} to link directories...")
	endif()
else()
	find_package(Libsqlcipher REQUIRED)
endif()

set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(CMAKE_AUTOMOC ON)

# Arrange output paths so that the plugin is found in the default search path
# relative to the test binary.
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
if (NOT WIN32)
	set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/sqldrivers)
else()
	set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_DEBUG ${CMAKE_BINARY_DIR}/Debug/sqldrivers)
	set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_RELEASE ${CMAKE_BINARY_DIR}/Release/sqldrivers)
endif()

option(QSQLCIPHER_STATIC "Build plugin as a static library" OFF)
option(QSQLCIPHER_BUILD_TESTS "Build the test binary" ON)
option(QSQLCIPHER_INSTALL_INTO_QT_PLUGIN_DIRECTORY "Find the Qt plugin directory and install the driver there" OFF)
set(QSQLCIPHER_COPYTO_DIR "" CACHE PATH "If set, the build artifact of the library will be copied there")

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
if(CMAKE_COMPILER_IS_GNUCC)
	# Set standard flags for GCC
	set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17")
endif()

if(QSQLCIPHER_STATIC)
	set(LIBTYPE STATIC)
	add_definitions(-DQT_STATICPLUGIN)
	set(TEST_DIR test-static)
else()
	if (APPLE)
		set(LIBTYPE SHARED)
	else()
		set(LIBTYPE MODULE)
	endif()
	add_definitions(-DQT_PLUGIN)
	set(TEST_DIR test-shared)
endif()

if (Qt6Sql_FOUND)
	message(STATUS "Found Qt6 version ${Qt6Sql_VERSION}.")
	
	set(_PRIVATE_SOURCES_DIRECTORY "")
	if (EXISTS "${PROJECT_SOURCE_DIR}/qt-file-cache/${Qt6Sql_VERSION}")
		message(STATUS "Using cached/shipped versions of required header/source files.")
		set(_PRIVATE_SOURCES_DIRECTORY "${PROJECT_SOURCE_DIR}/qt-file-cache/${Qt6Sql_VERSION}")
		include_directories("${PROJECT_SOURCE_DIR}/qt-file-cache/${Qt6Sql_VERSION}")
	elseif (CMAKE_BUILD_TYPE MATCHES "^Gentoo")
		# No network access during Gentoo package build
		message(SEND_ERROR "Header/source files for Qt6 version ${Qt6Sql_VERSION} not found. Please report this error!")
	else()
		set(DOWNLOAD_PATH "src/plugins/sqldrivers/sqlite")

		set(URL_HEADER "https://raw.githubusercontent.com/qt/qtbase/v${Qt6Sql_VERSION}/${DOWNLOAD_PATH}/qsql_sqlite_p.h")
		set(URL_CPP "https://raw.githubusercontent.com/qt/qtbase/v${Qt6Sql_VERSION}/${DOWNLOAD_PATH}/qsql_sqlite.cpp")
		message(STATUS "URL = ${URL_HEADER}")

		file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/qt-private-from-git-version-${Qt6Sql_VERSION}")
		set(_PRIVATE_SOURCES_DIRECTORY "${CMAKE_BINARY_DIR}/qt-private-from-git-version-${Qt6Sql_VERSION}")
		include_directories("${CMAKE_BINARY_DIR}/qt-private-from-git-version-${Qt6Sql_VERSION}")

		file(DOWNLOAD "${URL_HEADER}" "${CMAKE_BINARY_DIR}/qt-private-from-git-version-${Qt6Sql_VERSION}/qsql_sqlite_p.h" STATUS STATUS_HEADER_LIST TLS_VERIFY on LOG LOG_HEADER)
		file(DOWNLOAD "${URL_CPP}" "${CMAKE_BINARY_DIR}/qt-private-from-git-version-${Qt6Sql_VERSION}/qsql_sqlite.cpp" STATUS STATUS_CPP_LIST TLS_VERIFY on LOG LOG_CPP)

		list(GET STATUS_HEADER_LIST 0 STATUS_HEADER)
		list(GET STATUS_CPP_LIST 0 STATUS_CPP)
		if ((NOT "${STATUS_HEADER}" STREQUAL "0") OR (NOT "${STATUS_CPP}" STREQUAL "0"))
			list(GET STATUS_HEADER_LIST 1 STATUS_HEADER_ERROR)
			list(GET STATUS_CPP_LIST 1 STATUS_CPP_ERROR)
			message(SEND_ERROR "Could not download required Qt6 private header/source files. Please report this error! Qt Version: ${Qt6Sql_VERSION}. Result Header: ${STATUS_HEADER}. Error: ${STATUS_HEADER_ERROR}. Result Source: ${STATUS_CPP}. Error: ${STATUS_CPP_ERROR}. Log Header: ${LOG_HEADER}. Log Source: ${LOG_CPP}.")
		else()
			message(STATUS "Downloaded required header/source files for your Qt6 version.")
		endif()
	endif()
endif()

#
# Determine Qt Plugin Location for Linux/Mac to allow installer generation to work
#
if (NOT WIN32)
	try_run(QSQLCIPHER_PLUGIN_DIR_TEST_RUN_RESULT QSQLCIPHER_PLUGIN_DIR_TEST_COMPILE_RESULT "${PROJECT_BINARY_DIR}/testPluginLocation" "${CMAKE_CURRENT_SOURCE_DIR}/cmake/getPluginFolder.cpp" LINK_LIBRARIES Qt6::Core COMPILE_OUTPUT_VARIABLE QSQLCIPHER_PLUGIN_DIR_TEST_COMPILE_OUTPUT RUN_OUTPUT_VARIABLE QSQLCIPHER_PLUGIN_DIR_TEST_RUN_OUTPUT)
	if (NOT ${QSQLCIPHER_PLUGIN_DIR_TEST_COMPILE_RESULT})
		message(FATAL_ERROR "Failed to compile plugin location testing program, please contact a developer! Extended Information: ${QSQLCIPHER_PLUGIN_DIR_TEST_COMPILE_OUTPUT}") 
	elseif(NOT "${QSQLCIPHER_PLUGIN_DIR_TEST_RUN_RESULT}" STREQUAL "0")
		message(FATAL_ERROR "Failed to run plugin location testing program, please contact a developer! Extended Information: ${QSQLCIPHER_PLUGIN_DIR_TEST_RUN_OUTPUT}") 
	else()
		set(QSQLCIPHER_QT_PLUGIN_DIR "${QSQLCIPHER_PLUGIN_DIR_TEST_RUN_OUTPUT}")
		message(STATUS "Determined plugin folder: ${QSQLCIPHER_QT_PLUGIN_DIR}/sqldrivers")
	endif()
endif()

if(QSQLCIPHER_INSTALL_INTO_QT_PLUGIN_DIRECTORY)
	if (NOT WIN32)
		try_run(QSQLCIPHER_PLUGIN_DIR_TEST_RUN_RESULT QSQLCIPHER_PLUGIN_DIR_TEST_COMPILE_RESULT "${PROJECT_BINARY_DIR}/testPluginLocation" "${CMAKE_CURRENT_SOURCE_DIR}/cmake/getPluginFolder.cpp" LINK_LIBRARIES Qt6::Core COMPILE_OUTPUT_VARIABLE QSQLCIPHER_PLUGIN_DIR_TEST_COMPILE_OUTPUT RUN_OUTPUT_VARIABLE QSQLCIPHER_PLUGIN_DIR_TEST_RUN_OUTPUT)
		if (NOT ${QSQLCIPHER_PLUGIN_DIR_TEST_COMPILE_RESULT})
			message(FATAL_ERROR "Failed to compile plugin location testing program, please contact a developer! Extended Information: ${QSQLCIPHER_PLUGIN_DIR_TEST_COMPILE_OUTPUT}") 
		elseif(NOT "${QSQLCIPHER_PLUGIN_DIR_TEST_RUN_RESULT}" STREQUAL "0")
			message(FATAL_ERROR "Failed to run plugin location testing program, please contact a developer! Extended Information: ${QSQLCIPHER_PLUGIN_DIR_TEST_RUN_OUTPUT}") 
		else()
			set(QSQLCIPHER_PLUGIN_DIR "${QSQLCIPHER_PLUGIN_DIR_TEST_RUN_OUTPUT}")
			message(STATUS "QSQLCIPHER_INSTALL_INTO_QT_PLUGIN_DIRECTORY is set, will install plugin to folder ${QSQLCIPHER_PLUGIN_DIR}/sqldrivers")
		endif()
	else()
		string(REPLACE "\\" "/" Qt6Core_DIR "${Qt6Core_DIR}")
		if ("${Qt6Core_DIR}" STREQUAL "")
			message(SEND_ERROR "Qt6Core_DIR is not set and can not be used to derive the location of the Qt installation.")
		elseif(NOT "${Qt6Core_DIR}" MATCHES "^(.*)/lib/cmake/Qt6Core")
			message(SEND_ERROR "Qt6Core_DIR does not end in lib/cmake/Qt6Core, which is unexpected and therefore can not be used to derive the location of the Qt installation.")
		else()
			string(REGEX REPLACE "^(.*)/lib/cmake/Qt6Core" "\\1" QT6_BASE_DIR "${Qt6Core_DIR}")
			set(QSQLCIPHER_PLUGIN_DIR "${QT6_BASE_DIR}/plugins")
			message(STATUS "QSQLCIPHER_INSTALL_INTO_QT_PLUGIN_DIRECTORY is set, will install plugin to folder ${QSQLCIPHER_PLUGIN_DIR}/sqldrivers")
		endif()
	endif()
endif()

add_library(qsqlcipher ${LIBTYPE}
    smain.cpp
    "${_PRIVATE_SOURCES_DIRECTORY}/qsql_sqlite.cpp"
)

# We need QStringView -> QString conversions to happen
target_compile_definitions(qsqlcipher PRIVATE QT_USE_QSTRINGBUILDER)
target_compile_definitions(qsqlcipher PRIVATE QT_RESTRICTED_CAST_FROM_ASCII)
target_compile_definitions(qsqlcipher PRIVATE QT_NO_CAST_TO_ASCII)

target_include_directories(qsqlcipher PRIVATE
    ${Qt6Sql_PRIVATE_INCLUDE_DIRS}
    ${SQLCIPHER_INCLUDE_DIRS} ${Libsqlcipher_INCLUDE_DIRS}/sqlcipher
)

target_link_libraries(qsqlcipher
    Qt6::Sql Qt6::SqlPrivate
    ${SQLCIPHER_LIBRARIES} ${Libsqlcipher_LIBRARIES}
)

#include(CTest)
if(QSQLCIPHER_BUILD_TESTS)
    add_subdirectory(${TEST_DIR})
endif()

if (NOT ("${QSQLCIPHER_COPYTO_DIR}" STREQUAL ""))
	add_custom_command(TARGET qsqlcipher POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:qsqlcipher> ${QSQLCIPHER_COPYTO_DIR}/$<TARGET_FILE_NAME:qsqlcipher>)
endif()

if (NOT ("${QSQLCIPHER_PLUGIN_DIR}" STREQUAL ""))
	add_custom_command(TARGET qsqlcipher POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:qsqlcipher> ${QSQLCIPHER_PLUGIN_DIR}/sqldrivers/$<TARGET_FILE_NAME:qsqlcipher>)
endif()

find_program(DPKG_PROGRAM dpkg DOC "dpkg program of Debian-based systems")
if (NOT WIN32)
	if (DPKG_PROGRAM)
		if (NOT QSQLCIPHER_QT_PLUGIN_DIR)
			if(CMAKE_SIZEOF_VOID_P EQUAL 8)
				INSTALL(TARGETS qsqlcipher DESTINATION lib/x86_64-linux-gnu/qt6/plugins/sqldrivers)
			else()
				INSTALL(TARGETS qsqlcipher DESTINATION lib/i386-linux-gnu/qt6/plugins/sqldrivers)
			endif()
		else()
			string(REGEX REPLACE "^/usr/(.*)$" "\\1" QT_PLUGIN_DIR_SUFFIX "${QSQLCIPHER_QT_PLUGIN_DIR}")
			message(STATUS "Stripped plugin path to ${QT_PLUGIN_DIR_SUFFIX} from ${QSQLCIPHER_QT_PLUGIN_DIR}")
			INSTALL(TARGETS qsqlcipher DESTINATION "${QT_PLUGIN_DIR_SUFFIX}/sqldrivers")
		endif()
	elseif (APPLE)
		message(STATUS "Packaging for Mac OSX is done through homebrew, if you are not using it right now, you should.")
		INSTALL(TARGETS qsqlcipher DESTINATION sqldrivers)
		if (QSQLCIPHER_BUILD_TESTS)
			INSTALL(TARGETS qsqlcipher-test DESTINATION bin)
		endif()
	else()
		message(WARNING "Packaging is not set up for this platform, either submit a ticket or change/add pathes yourself, if packaging is required.")
		INSTALL(TARGETS qsqlcipher DESTINATION sqldrivers)
		if (QSQLCIPHER_BUILD_TESTS)
			INSTALL(TARGETS qsqlcipher-test DESTINATION bin)
		endif()
	endif()
else()
	INSTALL(TARGETS qsqlcipher DESTINATION sqldrivers)
endif()

# Packaging
SET(CPACK_PACKAGE_NAME "libqt6sql6-sqlcipher")
SET(CPACK_PACKAGE_CONTACT "packaging@openmittsu.de")

SET(CPACK_PACKAGE_VERSION_MAJOR "0")
SET(CPACK_PACKAGE_VERSION_MINOR "2")
SET(CPACK_PACKAGE_VERSION_PATCH "0")
SET(CPACK_PACKAGE_VERSION_REVISION "1-${Qt6Sql_VERSION}")
SET(CPACK_PACKAGE_VERSION "${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}")

set(DISTRO_CODENAME $ENV{DISTRO_CODENAME})
find_program(LSB_RELEASE_CMD lsb_release)
mark_as_advanced(LSB_RELEASE_CMD)
if (LSB_RELEASE_CMD)
	execute_process(COMMAND "${LSB_RELEASE_CMD}" --codename --short
			OUTPUT_VARIABLE DISTRO_CODENAME
			OUTPUT_STRIP_TRAILING_WHITESPACE)
endif ()
if (DISTRO_CODENAME)
	set(CPACK_PACKAGE_VERSION ${CPACK_PACKAGE_VERSION}~${DISTRO_CODENAME})
else ()
	message(STATUS "Could not find lsb_release nor is DISTRO_CODENAME set.")
endif ()

if (DPKG_PROGRAM)
	execute_process(COMMAND ${DPKG_PROGRAM} --print-architecture OUTPUT_VARIABLE CPACK_DEBIAN_PACKAGE_ARCHITECTURE OUTPUT_STRIP_TRAILING_WHITESPACE)
	SET(CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}_${CPACK_PACKAGE_VERSION}-${CPACK_PACKAGE_VERSION_REVISION}_${CPACK_DEBIAN_PACKAGE_ARCHITECTURE}")
else (DPKG_PROGRAM)
	SET(CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}_${CPACK_PACKAGE_VERSION}-${CPACK_PACKAGE_VERSION_REVISION}_${CMAKE_SYSTEM_NAME}")
	SET(CPACK_DEBIAN_PACKAGE_ARCHITECTURE "amd64")
endif(DPKG_PROGRAM)

SET(CPACK_DEBIAN_PACKAGE_DEPENDS "libqt6sql6, libsqlcipher0 (>= 3.4.1-1)")
SET(DEBIAN_PACKAGE_BUILDS_DEPENDS "debhelper (>= 9), cmake (>= 3.10), qt6-base-dev, qt6-base-private-dev, qt6-base-dev-tools, qt6-multimedia-dev, gcc, g++")
SET(CPACK_PACKAGE_DESCRIPTION_SUMMARY "A Qt6 wrapper for using SqlCipher as a QSqlDriver.")
SET(CPACK_DEBIAN_PACKAGE_SECTION "libs")
 
INCLUDE(CPack)
