cmake_minimum_required(VERSION 3.13)

# set project name and version
project(dpuser VERSION 4.2)

# specify the C++ standard
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED True)

# control where the static and shared libraries are built so that on windows
# we don't need to tinker with the path to run the executable
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}")
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}")
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}")

# FLAGS
option(BUILD_SHARED_LIBS "Build using shared libraries" ON)

option(QT "Compile for use in QFitsView. CAUTION: by manually activating this option, the compiler will fail to build." OFF)
option(HAS_VTK "has VTK" ON)
option(HAS_GDL "has GDL" OFF)
option(HAS_PYTHON "has Python" ON)
option(HAS_PLPLOT "has PLPlot" OFF)
option(HAS_PGPLOT "has PGPlot" ON)
option(HAS_DPPGPLOT "has DPPGPlot" ON)
option(HAS_PG2PLPLOT "has PG2PLPlot" OFF)

if(QT)
  add_definitions(-DDPQT)
  add_definitions(-DNO_READLINE)
endif()
if(HAS_VTK)
  add_definitions(-DHAS_VTK)
endif()
if(HAS_GDL)
  add_definitions(-DHAS_GDL)
  include_directories("../include/gdl/")
endif()
if(HAS_PYTHON)
  add_definitions(-DHAS_PYTHON)
  if(WIN32)
    include_directories("../include/WIN/python/")
  elseif(APPLE)
    include_directories("../include/MACOSX/python/")
  else()
    include_directories("../include/LINUX/python/")
  endif()
endif()
if(HAS_PLPLOT)
  add_definitions(-DHAS_PLPLOT)
endif()
if(HAS_PGPLOT)
  add_definitions(-DHAS_PGPLOT)
endif()
if(HAS_DPPGPLOT)
  add_definitions(-DHAS_DPPGPLOT)
endif()
if(HAS_PG2PLPLOT)
  add_definitions(-DHAS_PG2PLPLOT)
endif()

if (HAS_PGPLOT AND HAS_PG2PLPLOT)
  message("Both HAS_PGPLOT and HAS_PG2PLPLOT defined, thus DPPGPLOT must be undefined.")
  unset(HAS_DPPGPLOT)
  remove_definitions(-DHAS_DPPGPLOT)
endif()

if(WIN32)
  add_definitions(-DHAVE_MINGW32)
  add_definitions(-DWIN)
endif()

# configure files that have special variables in them
#@configure_file(dpuser.h.in dpuser.h)

# BISON & FLEX - uncomment if modifying the parsers
find_package(BISON 2.6)
find_package(FLEX 2.6.4)

# mpfit subdirectory
IF(BISON_FOUND AND FLEX_FOUND)
  BISON_TARGET(mpfitParser mpfit/mpfit.y "${CMAKE_CURRENT_BINARY_DIR}/mpfitParser.cpp" DEFINES_FILE "${CMAKE_CURRENT_BINARY_DIR}/mpfitParser.h")

  ADD_CUSTOM_TARGET(
     patchMpfitParser
     COMMAND ${CMAKE_COMMAND} -P "${PROJECT_SOURCE_DIR}/mpfit/patch_mpfit_parser.cmake"
     DEPENDS ${BISON_mpfitParser_OUTPUTS}
  )

  FLEX_TARGET(mpfitScanner mpfit/mpfit.l "${CMAKE_CURRENT_BINARY_DIR}/mpfitScanner.cpp" COMPILE_FLAGS "-l")

  ADD_CUSTOM_TARGET(
     patchMpfitScanner
     COMMAND ${CMAKE_COMMAND} -P "${PROJECT_SOURCE_DIR}/mpfit/patch_mpfit_scanner.cmake"
     DEPENDS ${FLEX_mpfitScanner_OUTPUTS}
  )

  ADD_FLEX_BISON_DEPENDENCY(mpfitScanner mpfitParser)



# parser subdirectory
  BISON_TARGET(astParser parser/ast.y "${CMAKE_CURRENT_BINARY_DIR}/astParser.cpp" DEFINES_FILE "${CMAKE_CURRENT_BINARY_DIR}/astParser.h")
FLEX_TARGET(astScanner parser/ast.l "${CMAKE_CURRENT_BINARY_DIR}/astScanner.cpp"  COMPILE_FLAGS "-l")
ADD_FLEX_BISON_DEPENDENCY(astScanner astParser)
ENDIF()

# doc subdirectory
#@if (UNIX)
#@  ADD_CUSTOM_COMMAND(
#@                    WORKING_DIRECTORY doc/
#@                    COMMAND ./makec.sh
#@                    COMMENT "Generating helpmap..."
#@                    OUTPUT doc/helpmap.cpp
#@                    USES_TERMINAL
#@                    )

  set(DOCS
     doc/helpmap.cpp
     )
#@else()
#@  message("Unable to generate helpmap. The helpmap can only be generated on UNIX systems.")
#@endif()

# other dependencies to include: libfits
include_directories("../libfits/")

set(LIBFITS
   ../libfits/3d_stuff.cpp
   ../libfits/astrolib.cpp
   ../libfits/cube.c
   ../libfits/dpComplex.cpp
   ../libfits/dpheader.cpp
   ../libfits/fits.cpp
   ../libfits/fits_cube.cpp
   ../libfits/fits_dpl.cpp
   ../libfits/fits_exc.cpp
   ../libfits/fits_file.cpp
   ../libfits/fits_filters.cpp
   ../libfits/fits_funcs.cpp
   ../libfits/fits_logic.cpp
   ../libfits/fits_mem.cpp
   ../libfits/fits_ops.cpp
   ../libfits/fits_procs.cpp
   ../libfits/fits_range.cpp
   ../libfits/fits_red.cpp
   ../libfits/fitting.cpp
   ../libfits/JulianDay.cpp
   ../libfits/math_utils.cpp
   ../libfits/voronoi.cpp
   )

foreach(file ${LIBFITS})
  message(STATUS "${file}")
endforeach()

# other dependencies to include: utils
include_directories("../utils/")
include_directories("../utils/kabsch/")
include_directories("../utils/cmpfit/")
include_directories("../utils/regex/")

set(UTILS
   ../utils/dpstring.cpp
   ../utils/dpstringlist.cpp
   ../utils/cpgplot.cpp
   ../utils/kabsch/kabsch2d.cpp
   ../utils/cmpfit/mpfit.cpp
   ../utils/regex/regex_sr.cpp
   )

if (HAS_PGPLOT AND HAS_DPPGPLOT)
  set(UTILS
     ${UTILS}
     ../utils/cpg3d.c
     )
endif()

foreach(file ${UTILS})
  message(STATUS "${file}")
endforeach()

IF(BISON_FOUND AND FLEX_FOUND)
set(PARSERS
   ${BISON_astParser_OUTPUTS}
   ${FLEX_astScanner_OUTPUTS}
   ${BISON_mpfitParser_OUTPUTS}
   ${FLEX_mpfitScanner_OUTPUTS}
)
ELSE()
set(PARSERS
   parser/astScanner.cpp
   parser/astParser.cpp
   mpfit/mpfitScanner.cpp
   mpfit/mpfitParser.cpp
)
ENDIF()

# other dependencies to include: include
include_directories("../include/")

# other dependencies to include: include/gdl if HAS_GDL is defined
if (HAS_GDL)
  include_directories("../include/gdl/")
endif()

# build the executable: dpuser
add_executable(dpuser
              arithmetics.cpp
              boolean.cpp
              dpuserAST.cpp
              dpuser.input.cpp
              dpuser.procs.cpp
              dpuserType.cpp
              dpuser_utils.cpp
              dpuser.yacchelper.cpp
              functions.cpp
              gdl_dpuser.cpp
              procedures.cpp
              python_dpuser.cpp
              qtstubs.cpp
              # doc
              ${DOCS}
              # mpfit + parser
              ${PARSERS}
              mpfit/mpfitAST.cpp
              # other dependencies
              ${LIBFITS}
              ${UTILS}
              )

IF(BISON_FOUND AND FLEX_FOUND)
add_dependencies(dpuser patchMpfitParser)
add_dependencies(dpuser patchMpfitScanner)
ENDIF()

# DEPENDENCIES: SYSTEM LIBRARIES (SHARED | STATIC)

if(UNIX AND NOT APPLE)
    set(LINUX TRUE)
endif()

if (NOT LIB_PATH)
  if (WIN32)
    GET_FILENAME_COMPONENT(LIB_PATH "../lib/WIN64" ABSOLUTE)
	endif()
  if (APPLE)
    GET_FILENAME_COMPONENT(LIB_PATH "../lib/MACOSARM64" ABSOLUTE)
	endif()
  if (LINUX)
    GET_FILENAME_COMPONENT(LIB_PATH "../lib/LINUX64" ABSOLUTE)
  endif()
endif()

if (NOT BUILD_SHARED_LIBS)
  message("Statically linking system libraries. Please note: Manual compilation of system libraries is required. Looking in ${LIB_PATH}.")
  target_link_libraries(dpuser -static-libgcc -static-libstdc++)
#  target_link_libraries(dpuser -static)
#  set(CMAKE_EXE_LINKER_FLAGS "-static")
endif()

# BASE
set(SYSTEM_LIBRARIES ${SYSTEM_LIBRARIES} xpa fftw3 readline cfitsio)
if (NOT WIN32)
  set(SYSTEM_LIBRARIES ${SYSTEM_LIBRARIES} ncurses)
else()
  set(SYSTEM_LIBRARIES ${SYSTEM_LIBRARIES} termcap)
endif()
#target_link_libraries(dpuser -lreadline) # TODO: workaround

# PGPLOT
if (HAS_PGPLOT AND NOT HAS_PG2PLPLOT)
  set(SYSTEM_LIBRARIES ${SYSTEM_LIBRARIES} cpgplot pgplot f2c)
endif()

# PLPLOT
if ((HAS_PGPLOT AND HAS_PG2PLPLOT) OR HAS_PLPLOT OR HAS_GDL)
  set(SYSTEM_LIBRARIES ${SYSTEM_LIBRARIES} plplotcxx fftw3f plplot qsastime)
endif()

# GDL
if (HAS_GDL)
  set(SYSTEM_LIBRARIES ${SYSTEM_LIBRARIES} gdl)
endif()

set(SYSTEM_LIBRARIES ${SYSTEM_LIBRARIES} gsl z gslcblas png)

if (LINUX)
  set(SYSTEM_LIBRARIES ${SYSTEM_LIBRARIES} X11 dl xcb Xdmcp Xau)
endif()

# Include libraries
message("Included libraries (please make sure that they are installed):")
foreach(library ${SYSTEM_LIBRARIES})
  message("* lib${library}")

  find_library(dynlib${library}
              "lib${library}.so"
              )
  if (BUILD_SHARED_LIBS AND dynlib${library})
    target_link_libraries(dpuser -l${library})
    message(${dynlib${library}})
  else()
    find_library(libpath${library}
                "lib${library}.a"
                HINTS "${LIB_PATH}" 
                )
    message(${libpath${library}})

    add_library(lib${library} STATIC IMPORTED)
    set_property(TARGET lib${library} PROPERTY IMPORTED_LOCATION ${libpath${library}})
    target_link_libraries(dpuser lib${library})
  endif()
endforeach()

if(WIN32)
  target_link_libraries(dpuser -static -lws2_32)
endif()

# Include directories
target_include_directories(dpuser PUBLIC
                          "${PROJECT_BINARY_DIR}"
                          "${PROJECT_SOURCE_DIR}"
                          "${PROJECT_SOURCE_DIR}/mpfit"
                          "${PROJECT_SOURCE_DIR}/parser"
                          )

# for installation
install(TARGETS dpuser DESTINATION bin)
