include(FindPkgConfig)
include(FetchContent)

# zlib
find_package(ZLIB REQUIRED)
list(APPEND ASY_STATIC_LIBARIES ZLIB::ZLIB)

# flex + bison
if (UNIX)
   include(FindFLEX)
   include(FindBISON)

   if (NOT FLEX_FOUND)
       message(FATAL_ERROR "FLEX is required for building")
   endif()

   if (NOT BISON_FOUND)
       message(FATAL_ERROR "Bison is required for building")
   endif()
elseif(WIN32)
   if ((NOT WIN32_FLEX_BINARY) OR (NOT WIN32_BISON_BINARY))
       # downlod winflexbison
       message(STATUS "Flex or bison not given; downloading winflexbison.")


       FetchContent_Declare(
               winflexbison
               URL https://github.com/lexxmark/winflexbison/releases/download/v2.5.25/win_flex_bison-2.5.25.zip
               URL_HASH SHA256=8D324B62BE33604B2C45AD1DD34AB93D722534448F55A16CA7292DE32B6AC135
       )
       FetchContent_MakeAvailable(winflexbison)
       message(STATUS "Downloaded winflexbison")

       if (NOT WIN32_FLEX_BINARY)
           set(FLEX_EXECUTABLE ${winflexbison_SOURCE_DIR}/win_flex.exe)
       endif()

       if (NOT WIN32_BISON_BINARY)
           set(BISON_EXECUTABLE ${winflexbison_SOURCE_DIR}/win_bison.exe)
       endif()
   else()
       set(FLEX_EXECUTABLE ${WIN32_FLEX_BINARY})
       set(BISON_EXECUTABLE ${WIN32_BISON_BINARY})
   endif()
endif()

# getopt (win32 only)

if (WIN32)
   find_package(unofficial-getopt-win32 REQUIRED)
   list(APPEND ASY_STATIC_LIBARIES unofficial::getopt-win32::getopt)
endif()

# glm; mandatory for all builds
find_package(glm CONFIG)
if (glm_FOUND)
   list(APPEND ASY_STATIC_LIBARIES glm::glm)
   list(APPEND ASY_MACROS HAVE_LIBGLM)
else()
   message(FATAL_ERROR "glm not found; will not use glm")
endif()

if (ENABLE_READLINE)
# curses
   if (UNIX)
       # we know ncurses work on unix systems, however
       # not always supported on windows (esp. msvc)
       set(CURSES_NEED_NCURSES TRUE)

       find_package(Curses)
       if (Curses_FOUND)
           list(APPEND ASYMPTOTE_INCLUDES ${CURSES_INCLUDE_DIRS})
           list(APPEND ASY_COMPILE_OPTS ${CURSES_CFLAGS})
           list(APPEND ASY_STATIC_LIBRARIES ${CURSES_LIBRARIES})

           list(APPEND ASY_MACROS HAVE_NCURSES_CURSES_H HAVE_LIBCURSES)
       else()
           message(FATAL_ERROR "curses not found; will compile without curses")
       endif()

       pkg_check_modules(readline IMPORTED_TARGET readline)

       if (readline_FOUND)
           list(APPEND ASY_STATIC_LIBARIES PkgConfig::readline)
           list(APPEND ASY_MACROS HAVE_LIBREADLINE)
       else ()
           message(FATAL_ERROR "readline not found; will compile without libreadline")
       endif()
   elseif(WIN32)
       find_package(unofficial-pdcurses CONFIG)
       if (unofficial-pdcurses_FOUND)
           list(APPEND ASY_STATIC_LIBRARIES unofficial::pdcurses::pdcurses)
           list(APPEND ASY_MACROS HAVE_CURSES_H HAVE_LIBCURSES)
       else()
           message(FATAL_ERROR "curses not found; will compile without curses")
       endif()

       find_package(unofficial-readline-win32 CONFIG)
       if (unofficial-readline-win32_FOUND)
           list(APPEND ASY_STATIC_LIBARIES unofficial::readline-win32::readline)
           list(APPEND ASY_MACROS HAVE_LIBREADLINE)
       else ()
           message(FATAL_ERROR "readline not found; will compile without libreadline")
       endif()
   else()
       message(FATAL_ERROR "Only supported on Unix or Win32 systems")
   endif()
else()
   message(STATUS "libreadline disabled; will not use libreadline")
endif()

# libcurl
if (ENABLE_CURL)
   find_package(CURL)
   if (CURL_FOUND)
       list(APPEND ASY_STATIC_LIBARIES CURL::libcurl)
       list(APPEND ASY_MACROS HAVE_LIBCURL)
   else()
       message(FATAL_ERROR "curl not found")
   endif()
else()
   message(STATUS "Disabling curl support")
endif()

# pthreads
if (ENABLE_THREADING)
   if (UNIX)
       set(CMAKE_THREAD_PREFER_PTHREAD TRUE)
       set(THREADS_PREFER_PTHREAD_FLAG TRUE)
       include(FindThreads)

       if(CMAKE_USE_PTHREADS_INIT)
           list(APPEND ASY_STATIC_LIBARIES Threads::Threads)
           list(APPEND ASY_MACROS HAVE_PTHREAD=1)
       else()
           message(FATAL_ERROR "No thread library specified")
       endif()
   elseif(WIN32)
       find_package(PThreads4W)

       if(PThreads4W_FOUND)
           list(APPEND ASY_STATIC_LIBARIES PThreads4W::PThreads4W)
           list(APPEND ASY_MACROS HAVE_PTHREAD=1)
       else()
           message(FATAL_ERROR "No thread library specified")
       endif()
   else()
       message(FATAL_ERROR "Only supported on Unix or Win32 systems")
   endif()
else()
   message(STATUS "Disabling threading support")
endif()

# gsl
if (ENABLE_GSL)
   find_package(GSL)
   if (GSL_FOUND)
       list(APPEND ASY_STATIC_LIBARIES GSL::gsl)
       list(APPEND ASY_MACROS HAVE_LIBGSL)
   else()
       message(FATAL_ERROR "GSL not found")
   endif()
else()
   message(STATUS "Disabling gsl support")
endif()


# eigen
if (ENABLE_EIGEN3)
find_package(Eigen3 CONFIG)
   if (Eigen3_FOUND)
       list(APPEND ASY_STATIC_LIBARIES Eigen3::Eigen)
       list(APPEND ASY_MACROS HAVE_EIGEN_DENSE)
   else()
       message(FATAL_ERROR "eigen3 not found")
   endif()
else()
   message(STATUS "Disabling eigen3 support")
endif()

# OpenGL stuff
if (ENABLE_OPENGL)
   # fatal error here, since OpenGL is optional
   find_package(OpenGL REQUIRED)
   if (OPENGL_FOUND)
       list(APPEND ASY_STATIC_LIBARIES OpenGL::GL)
   else()
       message(WARNING "gl libraries not found")
   endif()

   if (OPENGL_GLU_FOUND)
       list(APPEND ASY_MACROS HAVE_LIBGL)
   else()
       message(FATAL_ERROR "GL components incomplete; will not use OpenGL")
   endif()

   find_package(FreeGLUT CONFIG)
   if (FreeGLUT_FOUND)
       list(APPEND ASY_STATIC_LIBARIES
               $<IF:$<TARGET_EXISTS:FreeGLUT::freeglut>,FreeGLUT::freeglut,FreeGLUT::freeglut_static>)
       list(APPEND ASY_MACROS FREEGLUT HAVE_LIBGLUT)
   else()
       message(FATAL_ERROR "freeglut not found; will not use freeglut")
   endif()

   if (ENABLE_GL_COMPUTE_SHADERS)
       list(APPEND ASY_MACROS HAVE_COMPUTE_SHADER)
   else()
       message(WARNING "Compute shader disabled")
   endif()

   if (ENABLE_GL_SSBO)
       list(APPEND ASY_MACROS HAVE_SSBO)
   else()
       message(WARNING "SSBO disabled")
   endif()
else()
   message(STATUS "Disabling opengl support")
endif()


if (ENABLE_RPC_FEATURES)
   if(UNIX)
       pkg_check_modules(TIRPC REQUIRED IMPORTED_TARGET libtirpc)
       list(APPEND ASY_STATIC_LIBARIES PkgConfig::TIRPC)
   endif()

   if (WIN32)
       # win32 does not have native open_memstream support
       set(OLD_BUILD_TESTING ${BUILD_TESTING})
       set(BUILD_TESTING OFF CACHE INTERNAL "build testing")
       FetchContent_Declare(
               fmem
               GIT_REPOSITORY https://github.com/Kreijstal/fmem.git
               GIT_TAG 5f79fef3606be5dac54d62c7d0e2123363afabd7
       )
       FetchContent_MakeAvailable(fmem)
       set(BUILD_TESTING ${OLD_BUILD_TESTING} CACHE INTERNAL "build testing")

       list(APPEND ASY_STATIC_LIBARIES fmem)
       list(APPEND ASYMPTOTE_INCLUDES $<TARGET_PROPERTY:fmem,INCLUDE_DIRECTORIES>)
   endif()
   list(APPEND ASY_MACROS HAVE_LIBTIRPC)


else()
   message(STATUS "Disabling rpc and xdr/v3d support")
endif()

# fftw3

if (ENABLE_FFTW3)
   set(FFTW3_USABLE TRUE)
   find_package(FFTW3 CONFIG)
   if (NOT FFTW3_FOUND)
       message(WARNING "libfftw3 not found; will not use fftw3")
       set(FFTW3_USABLE FALSE)
   endif()

   if (FFTW3_USABLE)
       list(APPEND ASY_STATIC_LIBARIES FFTW3::fftw3)
       list(APPEND ASY_MACROS HAVE_LIBFFTW3 FFTWPP_SINGLE_THREAD)
   else()
       message(FATAL_ERROR "environment lacks needed fftw3 features")
   endif()
else()
   message(STATUS "Disabling fftw3 support")
endif()