cmake_minimum_required(VERSION 3.10)

project(guayadeque)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

# Set Release type for builds where CMAKE_BUILD_TYPE is unset.
# This is usually a good default as this implictly enables
#
#   CFLAGS = -O3 -DNDEBUG
#
if (NOT CMAKE_BUILD_TYPE)
    set(CMAKE_BUILD_TYPE "Release")
endif()

# Adhere to GNU filesystem layout conventions
include(GNUInstallDirs)

message(STATUS "Building through C++ ${CMAKE_CXX_STANDARD} ...")
message(STATUS "Using install prefix ${CMAKE_INSTALL_PREFIX} ...")

find_package(PkgConfig REQUIRED)

# Prefer GLVND (libOpenGL + libGLX) over legacy libGL; silences the
# CMP0072 dev warning from FindOpenGL.cmake (pulled in via the wx 'gl'
# component). Guarded so cmake 3.10 (our minimum) still works.
if(POLICY CMP0072)
    cmake_policy(SET CMP0072 NEW)
endif()
set(OpenGL_GL_PREFERENCE GLVND)
find_package(OpenGL)

# VisPanel probes the X display (XOpenDisplay) before creating the GL canvas: wxGLCanvas is
# X11/GLX only and the ctor probe segfaults on Wayland without an X display.
if (UNIX AND NOT APPLE)
    find_package(X11 REQUIRED)
endif()

find_package(wxWidgets COMPONENTS base core adv net html xml aui gl OPTIONAL_COMPONENTS qa)

if (wxWidgets_FOUND)
    if (wxWidgets_LIBRARIES)
        if (wxWidgets_LIBRARIES MATCHES "wx_.*_qa-")   # wxWidgets_qa_FOUND does not work!
            add_definitions(-DUSE_WXQA=1)
        else()
            message(STATUS "wxWidgets QA component not found!")
        endif()
    else()
        message(FATAL_ERROR "wxWidgets libraries not found!")
    endif()
else()
    message(FATAL_ERROR "wxWidgets not found!")
endif()

find_package(ICU 60.0 COMPONENTS uc i18n REQUIRED)

pkg_check_modules(GSTREAMER120 gstreamer-1.0>=1.20)
if (NOT GSTREAMER120_FOUND)
    pkg_check_modules(GSTREAMER1 gstreamer-1.0>=1.0)
    if (NOT GSTREAMER1_FOUND)
        message(FATAL_ERROR "gstreamer >= 1.0 not found!")
    else()
        add_definitions(-DGSTREAMER_VERSION=1)
    endif()
else()
    add_definitions(-DGSTREAMER_VERSION=120)
endif()

pkg_check_modules(GSTREAMER REQUIRED gstreamer-pbutils-1.0)
pkg_check_modules(GSTREAMER_TAG REQUIRED gstreamer-tag-1.0)
pkg_check_modules(GSTREAMER_APP REQUIRED gstreamer-app-1.0)
pkg_check_modules(SQLITE3 REQUIRED sqlite3)
pkg_check_modules(LIBDBUS REQUIRED dbus-1)
pkg_check_modules(LIBGDKPIXBUF20 REQUIRED gdk-pixbuf-2.0)
pkg_check_modules(LIBGIO REQUIRED gio-2.0)

option(ENABLE_NETWORK "Enable network support by including curl support" ON)
if (ENABLE_NETWORK)
    pkg_check_modules(LIBCURL libcurl)
    if (NOT LIBCURL_FOUND)
        message(" libcurl dev not found! Network support disabled!")
    else()
        add_definitions(-DWITH_LIBCURL_SUPPORT=1)
    endif()
else()
    message(" *** Network support disabled!")
endif()

pkg_check_modules(LIBTAG taglib>=1.6.4)
if (NOT LIBTAG_FOUND)
    pkg_check_modules(LIBTAG taglib>=1.6.1)
    if (NOT LIBTAG_FOUND)
        pkg_check_modules(LIBTAG taglib>=1.6)
        if (NOT LIBTAG_FOUND)
            message(FATAL_ERROR "taglib 1.6/2.0 not found!")
        endif()
    else()
        add_definitions(-DTAGLIB_WITH_MP4_COVERS=1)
    endif()
else()
    if (LIBTAG_VERSION LESS 3.0)
        add_definitions(-DTAGLIB_WITH_MP4_COVERS=1)
        add_definitions(-DTAGLIB_WITH_APE_SUPPORT=1)
        if (NOT LIBTAG_VERSION LESS 2.0)
            add_definitions(-DTAGLIB_WITH_DSF_SUPPORT=1)
        endif()
    else()
        message(FATAL_ERROR "taglib version must be less than 3.0!")
    endif()
endif()

pkg_check_modules(LIBWXSQLITE3 wxsqlite3)
if (NOT LIBWXSQLITE3_FOUND)
	pkg_check_modules(LIBWXSQLITE33 wxsqlite3-3.2)
	if (NOT LIBWXSQLITE33_FOUND)
		pkg_check_modules(LIBWXSQLITE33 wxsqlite3-3.0)
		if (NOT LIBWXSQLITE33_FOUND)
		    message(FATAL_ERROR "wxSqlite3 not found")
		endif()
    endif()
else()
    if (LIBWXSQLITE3_VERSION GREATER_EQUAL 5.0)
        add_definitions(-DWXSQLITE3_V5_COMPAT=1)
    endif()
endif()

pkg_check_modules(LIBJSONCPP jsoncpp)
if (NOT LIBJSONCPP_FOUND)
  	message(FALTAL_ERROR "libjsoncpp not found")
endif()

option(ENABLE_IPOD "Enable iPod support by including libgpod support" ON)
if (ENABLE_IPOD)
    pkg_check_modules(LIBGPOD libgpod-1.0)
    if (NOT LIBGPOD_FOUND)
        message(" libgpod-dev not found! No iPod support!")
    else()
        add_definitions(-DWITH_LIBGPOD_SUPPORT=1)
    endif()
else()
    message(" *** iPod support disabled!")
endif()

# projectM visualizer (optional): system install via PROJECTM_PREFIX or CMAKE_PREFIX_PATH
list(APPEND CMAKE_PREFIX_PATH $ENV{PROJECTM_PREFIX})
find_package(projectM4 QUIET)
find_package(projectM4Playlist QUIET)
if (projectM4_FOUND)
    message(STATUS "projectM 4 found: visualizer enabled")
    add_definitions(-DHAVE_PROJECTM=1)
    if (NOT OPENGL_FOUND)
        message(FATAL_ERROR "OpenGL not found but required for the projectM visualizer")
    endif()
    if (projectM4Playlist_FOUND)
        message(STATUS "projectM 4 playlist found")
        add_definitions(-DHAVE_PROJECTM_PLAYLIST=1)
    endif()
else()
    find_path(PROJECTM3_INCLUDE_DIR projectM.hpp PATH_SUFFIXES libprojectM)
    find_library(PROJECTM3_LIBRARY NAMES projectM projectm)
    if (PROJECTM3_INCLUDE_DIR AND PROJECTM3_LIBRARY)
        set(PROJECTM3_FOUND TRUE)
        message(STATUS "projectM 3 found: visualizer enabled (compat path)")
        add_definitions(-DHAVE_PROJECTM=1 -DHAVE_PROJECTM3=1 -DHAVE_PROJECTM_PLAYLIST=1)
        if (NOT OPENGL_FOUND)
            message(FATAL_ERROR "OpenGL not found but required for the projectM visualizer")
        endif()
        # Older v3 (e.g. Ubuntu Noble) only has mono addPCMfloat: probe for the stereo entry and
        # fall back to a mono downmix without it. projectM 2.1.0 (same distro family) additionally
        # takes "unsigned int" in presetSwitchedEvent and has no presetSwitchFailedEvent at all
        include(CheckCXXSourceCompiles)
        set(CMAKE_REQUIRED_INCLUDES ${PROJECTM3_INCLUDE_DIR})
        set(CMAKE_REQUIRED_LIBRARIES ${PROJECTM3_LIBRARY})
        check_cxx_source_compiles("
            #include <projectM.hpp>
            int main() {
                PCM pcm;
                float data[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
                pcm.addPCMfloat_2ch( data, 4 );
                return 0;
            }
        " PROJECTM3_HAVE_PCM_2CH)
        check_cxx_source_compiles("
            #include <projectM.hpp>
            struct T : public projectM {
                T( const projectM::Settings & s ) : projectM( s ) {}
                void presetSwitchedEvent( bool a, size_t b ) const override { (void)a; (void)b; }
            };
            int main() { return 0; }
        " PROJECTM3_HAVE_SWITCHED_SIZE_T)
        check_cxx_source_compiles("
            #include <projectM.hpp>
            #include <string>
            struct T : public projectM {
                T( const projectM::Settings & s ) : projectM( s ) {}
                void presetSwitchFailedEvent( bool a, unsigned int b, const std::string & c ) const override { (void)a; (void)b; (void)c; }
            };
            int main() { return 0; }
        " PROJECTM3_HAVE_SWITCH_FAILED)
        check_cxx_source_compiles("
            #include <projectM.hpp>
            #include <string>
            struct T : public projectM {
                T( const projectM::Settings & s ) : projectM( s ) {}
                void use() {
                    projectM::Settings w;
                    w.titleFontURL = std::string();
                    w.menuFontURL = std::string();
                }
            };
            int main() { return 0; }
        " PROJECTM3_HAVE_SETTINGS_FONTS)
        check_cxx_source_compiles("
            #include <projectM.hpp>
            #include <string>
            struct T : public projectM {
                T( const projectM::Settings & s ) : projectM( s ) {}
                void use() {
                    projectM::Settings w;
                    w.datadir = std::string();
                }
            };
            int main() { return 0; }
        " PROJECTM3_HAVE_SETTINGS_DATADIR)
        unset(CMAKE_REQUIRED_INCLUDES)
        unset(CMAKE_REQUIRED_LIBRARIES)
        if (PROJECTM3_HAVE_PCM_2CH)
            message(STATUS "projectM 3 stereo PCM feed available")
            add_definitions(-DHAVE_PROJECTM_PCM_2CH=1)
        else()
            message(STATUS "projectM 3 stereo PCM feed missing: mono downmix")
        endif()
        if (PROJECTM3_HAVE_SWITCHED_SIZE_T)
            add_definitions(-DHAVE_PROJECTM_SWITCHED_SIZE_T=1)
        else()
            message(STATUS "projectM presetSwitchedEvent takes unsigned int (2.1.0 API)")
        endif()
        if (PROJECTM3_HAVE_SWITCH_FAILED)
            add_definitions(-DHAVE_PROJECTM_SWITCH_FAILED=1)
        else()
            message(STATUS "projectM presetSwitchFailedEvent missing (no failure log)")
        endif()
        if (PROJECTM3_HAVE_SETTINGS_FONTS)
            add_definitions(-DHAVE_PROJECTM_SETTINGS_FONTS=1)
        else()
            message(STATUS "projectM Settings has no font fields")
        endif()
        if (PROJECTM3_HAVE_SETTINGS_DATADIR)
            add_definitions(-DHAVE_PROJECTM_SETTINGS_DATADIR=1)
        else()
            message(STATUS "projectM Settings has no datadir field")
        endif()
    else()
        message(STATUS "projectM not found!")
    endif()
endif()

# Include wxWidgets macros
include(${wxWidgets_USE_FILE})

if (NOT _GUREVISION_)
    # Get the latest abbreviated commit hash of the working branch
    execute_process(
        COMMAND git log -1 --format=%h
        WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
        OUTPUT_VARIABLE _GUREVISION_
        OUTPUT_STRIP_TRAILING_WHITESPACE
    )
endif()

# Make Version.h
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/src/Version.h.in ${CMAKE_CURRENT_BINARY_DIR}/Version.h)

# add_definitions(${wxWidgets_DEFINITIONS})
add_compile_options(-Wall)
add_definitions(-DDATADIR=\"${CMAKE_INSTALL_FULL_DATADIR}/guayadeque\" -DDATAROOTDIR=\"${CMAKE_INSTALL_FULL_DATAROOTDIR}\")
add_definitions(-DDOCDIR=\"${CMAKE_INSTALL_FULL_DOCDIR}\")

# We define the include paths here, our minimal source dir is one,
# and also the include dirs defined by wxWidgets
include_directories(
    ${CMAKE_CURRENT_BINARY_DIR}
    ${wxWidgets_INCLUDE_DIRS}
    ${GSTREAMER_INCLUDE_DIRS}
    ${GSTREAMER_TAG_INCLUDE_DIRS}
    ${GSTREAMER_APP_INCLUDE_DIRS}
    ${SQLITE3_INCLUDE_DIRS}
    ${LIBCURL_INCLUDE_DIRS}
    ${LIBTAG_INCLUDE_DIRS}
    ${LIBDBUS_INCLUDE_DIRS}
    ${LIBGIO_INCLUDE_DIRS}
    ${LIBGPOD_INCLUDE_DIRS}
    ${LIBWXSQLITE3_INCLUDE_DIRS}
    ${LIBWXSQLITE33_INCLUDE_DIRS}
    ${LIBJSONCPP_INCLUDE_DIRS}
    ${LIBICU_INCLUDE_DIRS}
)

if (PROFILE)
    add_definitions(-pg)
    set(CMAKE_EXE_LINKER_FLAGS "-pg -g")
    message("Adding profiling code.")
endif()

add_subdirectory(src)
add_subdirectory(po)

# default configuration and desktop icon
# freedesktop.org-specific files
install(FILES defconfig/guayadeque.png DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/64x64/apps/)
install(FILES defconfig/org.guayadeque.Guayadeque.desktop DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/applications)
install(FILES defconfig/org.guayadeque.Guayadeque.metainfo.xml DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/metainfo)

# program-specific files
install(FILES defconfig/guayadeque.default.conf DESTINATION ${CMAKE_INSTALL_DATADIR}/guayadeque)
install(FILES defconfig/equalizers.default.conf DESTINATION ${CMAKE_INSTALL_DATADIR}/guayadeque)
install(FILES defconfig/lyrics_sources.xml DESTINATION ${CMAKE_INSTALL_DATADIR}/guayadeque)
install(DIRECTORY defconfig/Radios DESTINATION ${CMAKE_INSTALL_DATADIR}/guayadeque)

# docs
install(FILES CHANGELOG.md DESTINATION ${CMAKE_INSTALL_DOCDIR})
install(FILES INSTALL.md DESTINATION ${CMAKE_INSTALL_DOCDIR})
install(FILES RADIOS.md DESTINATION ${CMAKE_INSTALL_DOCDIR})
install(FILES README.md DESTINATION ${CMAKE_INSTALL_DOCDIR})
install(FILES LICENSE DESTINATION ${CMAKE_INSTALL_DOCDIR})
install(DIRECTORY doc/wiki DESTINATION ${CMAKE_INSTALL_DOCDIR})

# projectM visualization presets (curated subset, see defconfig/projectm-presets/README)
# Plain .milk files, playable by both projectM 4 and 3.
if (projectM4_FOUND OR PROJECTM3_FOUND)
    install(DIRECTORY defconfig/projectm-presets DESTINATION ${CMAKE_INSTALL_DATADIR}/guayadeque)
endif()

configure_file(
    "${CMAKE_CURRENT_SOURCE_DIR}/cmake_uninstall.cmake.in"
    "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake"
    IMMEDIATE @ONLY)

add_custom_target(uninstall
    "${CMAKE_COMMAND}" -P "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake")

add_custom_target(debug
    ${CMAKE_COMMAND} -DMAKE_BUILD_TYPE:STRING=Debug ${PROJECT_SOURCE_DIR})

add_custom_target(release
    ${CMAKE_COMMAND} -DMAKE_BUILD_TYPE:STRING=Release ${PROJECT_SOURCE_DIR})
