# bbowdapp - C++ binding for bbowda
# Copyright (C) 2025 DAGOPT Optimization Technologies GmbH (www.dagopt.com)
#                    written by Kevin Kofler <kofler@dagopt.com>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version. A copy of the GNU General Public
# License version 3 can be found in the file gpl-3.0.txt.
#
# Linking bbowda statically or dynamically (directly or indirectly) with
# other modules is making a combined work based on bbowda. Thus, the terms
# and conditions of the GNU General Public License cover the whole
# combination.
#
# In addition, as a special exception, the copyright holder of bbowda gives
# you permission to combine the bbowda program:
# * with free software programs or libraries that are released under the
#   GNU Library or Lesser General Public License (LGPL), either version 2
#   of the License, or (at your option) any later version,
# * with free software programs or libraries that are released under the
#   IBM Common Public License (CPL), either version 1.0 of the License, or
#   (at your option) any later version,
# * with free software programs or libraries that are released under the
#   eclipse.org Eclipse Public License (EPL), either version 1.0 of the
#   License, or (at your option) any later version,
# * with free software programs or libraries that are released under the
#   CeCILL-C Free Software License Agreement, either version 1 of the License,
#   or (at your option) any later version,
# * with code included in the standard release of MUMPS under the old MUMPS
#   Conditions of Use as reproduced in licenses.txt (or modified versions
#   of such code, with unchanged license; variants of the license where only
#   the list of contributors and/or the list of suggested citations changed
#   shall be considered the same license) and
# * if you qualify for a free of charge license of DONLP2, with code
#   included in the standard release of DONLP2 under the DONLP2 Conditions
#   of Use as reproduced in licenses.txt (or modified versions of such code,
#   with unchanged license).
# (For avoidance of doubt, this implies that it is permitted, e.g., to combine
# the bbowda program with current versions of Ipopt released under the EPL
# version 2.0, because 2.0 is >= 1.0. Its dependency MUMPS is released under
# the CeCILL-C version 1, which is also listed above.)
#
# You may copy and distribute such a system following the terms of the GNU
# GPL for bbowda and the licenses of the other code concerned, provided that
# you include the source code of that other code when and as the GNU GPL
# requires distribution of source code.
#
# Note that people who make modified versions of bbowda are not obligated
# to grant this special exception for their modified versions; it is their
# choice whether to do so. The GNU General Public License gives permission
# to release a modified version without this exception; this exception also
# makes it possible to release a modified version which carries forward
# this exception.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

find_package(SWIG 4 REQUIRED)
# clean up old generated source files before running SWIG, useful for Java
set(UseSWIG_MODULE_VERSION 2)
include(UseSWIG)

option(WITH_PYTHON_SPHINX "Enable Sphinx documentation for the Python binding."
       ON)
option(WITH_PYTHON_SPHINX_PDF
       "Enable Sphinx PDF documentation for the Python binding." OFF)
option(WITH_JAVA_JAVADOC "Enable Javadoc documentation for the Java binding."
       ON)
option(WITH_JAVA_JAVADOC_PDF
       "Enable Javadoc PDF documentation for the Java binding." OFF)

set_source_files_properties(bbowda.i PROPERTIES CPLUSPLUS ON)
include_directories(..)
list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake)

if(WITH_PYTHON)
  message(STATUS "Building SWIG Python 3 binding")
  if (CMAKE_VERSION VERSION_LESS 3.18)
    set(DEVELOPMENT_MODULE Development)
  else()
    set(DEVELOPMENT_MODULE Development.Module)
  endif()
  find_package(Python3 COMPONENTS Interpreter ${DEVELOPMENT_MODULE} REQUIRED)
  set(CMAKE_SWIG_FLAGS -py3 -builtin -module bbowda -directors -doxygen)
  swig_add_library(bbowda_python LANGUAGE python SOURCES bbowda.i
                   OUTPUT_DIR ${CMAKE_CURRENT_BINARY_DIR}/python
                   OUTFILE_DIR ${CMAKE_CURRENT_BINARY_DIR})
  set(CMAKE_SWIG_FLAGS)
  if (CMAKE_VERSION VERSION_LESS 3.15)
    set(PYTHON3_MODULE_LIBRARY Python3::Python)
  else()
    set(PYTHON3_MODULE_LIBRARY Python3::Module)
  endif()
  target_link_libraries(${SWIG_MODULE_bbowda_python_REAL_NAME}
                        bbowdapp ${PYTHON3_MODULE_LIBRARY})
  set_target_properties(${SWIG_MODULE_bbowda_python_REAL_NAME}
    PROPERTIES OUTPUT_NAME _bbowda COMPILE_OPTIONS
    "-Wno-unused-parameter;-Wno-unused-variable;-Wno-missing-field-initializers"
    )
  install(FILES "${CMAKE_CURRENT_BINARY_DIR}/python/bbowda.py"
          DESTINATION "${Python3_SITEARCH}")
  install(TARGETS ${SWIG_MODULE_bbowda_python_REAL_NAME}
          LIBRARY DESTINATION "${Python3_SITEARCH}")
  file(READ "../../ChangeLog" CHANGELOG_STRING)
  string(REGEX MATCH " Release [0-9]+\n" CHANGELOG_RELEASE_STRING
                     "${CHANGELOG_STRING}")
  string(STRIP "${CHANGELOG_RELEASE_STRING}" CHANGELOG_RELEASE_STRING)
  string(REPLACE "Release " "" BBOWDA_RELEASE "${CHANGELOG_RELEASE_STRING}")
  configure_file(bbowda-python.dist-info.in "bbowda-${BBOWDA_RELEASE}.dist-info"
                 @ONLY)
  install(FILES "${CMAKE_CURRENT_BINARY_DIR}/bbowda-${BBOWDA_RELEASE}.dist-info"
          DESTINATION "${Python3_SITEARCH}")
  install(PROGRAMS example.py TYPE BIN RENAME bbowda_python_example)
  if(WITH_PYTHON_SPHINX)
    message(STATUS "Building Sphinx documentation for the Python binding")
    find_package(Sphinx REQUIRED autodoc)
    mark_as_advanced(SPHINX_BUILD_EXECUTABLE SPHINX_QUICKSTART_EXECUTABLE)
    sphinx_add_docs(bbowda_sphinx_html BUILDER html
                                       SOURCE_DIRECTORY sphinx)
    add_dependencies(bbowda_sphinx_html bbowda_python_swig_compilation
                                        ${SWIG_MODULE_bbowda_python_REAL_NAME})
    install(DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/bbowda_sphinx_html"
            DESTINATION "${CMAKE_INSTALL_DATADIR}/doc/bbowda-python")
    if(WITH_PYTHON_SPHINX_PDF)
      message(STATUS "Building Sphinx PDF documentation for the Python binding")
      find_package(LATEX REQUIRED COMPONENTS PDFLATEX)
      find_program(LATEXMK_EXECUTABLE NAMES latexmk REQUIRED)
      mark_as_advanced(LATEXMK_EXECUTABLE)
      find_program(MAKE_EXECUTABLE NAMES gmake make smake REQUIRED)
      mark_as_advanced(MAKE_EXECUTABLE)
      sphinx_add_docs(bbowda_sphinx_latex BUILDER latex
                                          SOURCE_DIRECTORY sphinx)
      add_dependencies(bbowda_sphinx_latex bbowda_python_swig_compilation
                                           ${SWIG_MODULE_bbowda_python_REAL_NAME})
      # fix the above target to actually invoke the generated Makefile
      add_custom_command(TARGET bbowda_sphinx_latex POST_BUILD
                         COMMAND "${MAKE_EXECUTABLE}" all-pdf
                         WORKING_DIRECTORY
                         "${CMAKE_CURRENT_BINARY_DIR}/bbowda_sphinx_latex"
                         COMMENT "Building Sphinx LaTeX PDF documentation...")
      install(FILES
              "${CMAKE_CURRENT_BINARY_DIR}/bbowda_sphinx_latex/bbowda_python.pdf"
              DESTINATION "${CMAKE_INSTALL_DATADIR}/doc/bbowda-python")
    else()
      message(STATUS
              "Not building Sphinx PDF documentation for the Python binding")
    endif()
  else()
    message(STATUS "Not building Sphinx documentation for the Python binding")
  endif()
else()
  message(STATUS "Not building SWIG Python 3 binding")
endif()

if(WITH_JAVA)
  message(STATUS "Building SWIG Java binding")
  # we do not really need any component, only the main JNI target, but if the
  # list of components is left empty, FindJNI defaults to "JVM AWT", and we
  # specifically do not want to check for the AWT library that is not available
  # on headless installations
  find_package(JNI REQUIRED COMPONENTS JVM)
  # FindJNI.cmake in CMake versions prior to 3.24 does not export any targets
  if(JNI_FOUND AND NOT TARGET JNI::JNI)
    add_library(JNI::JNI IMPORTED INTERFACE)
    set_property(TARGET JNI::JNI PROPERTY INTERFACE_INCLUDE_DIRECTORIES
      ${JAVA_INCLUDE_PATH})
    if(NOT JNI_INCLUDE_PATH2_OPTIONAL AND JAVA_INCLUDE_PATH2)
      set_property(TARGET JNI::JNI APPEND PROPERTY INTERFACE_INCLUDE_DIRECTORIES
        ${JAVA_INCLUDE_PATH2})
    endif()
  endif()
  find_package(Java 1.5 REQUIRED)
  include (UseJava)
  set (CMAKE_SWIG_FLAGS -package com.dagopt.bbowda -module Bbowda -directors
                        -doxygen)
  # OUTPUT_DIR is ${CMAKE_CURRENT_BINARY_DIR}/java/ + the -package above (with
  # any '.' replaced by '/'). It must also match the GLOB in glob_java.cmake.
  swig_add_library(bbowda_java LANGUAGE java SOURCES bbowda.i OUTPUT_DIR
                   "${CMAKE_CURRENT_BINARY_DIR}/java/com/dagopt/bbowda"
                   OUTFILE_DIR "${CMAKE_CURRENT_BINARY_DIR}")
  set (CMAKE_SWIG_FLAGS)
  target_link_libraries(${SWIG_MODULE_bbowda_java_REAL_NAME} bbowdapp JNI::JNI)
  set_target_properties(${SWIG_MODULE_bbowda_java_REAL_NAME}
    PROPERTIES OUTPUT_NAME bbowdajni COMPILE_OPTIONS
    "-fno-strict-aliasing;-Wno-unused-function;-Wno-unused-parameter")
  # MODULE libraries are always installed to the LIBRARY DESTINATION.
  if(CMAKE_HOST_SYSTEM_NAME MATCHES Windows)
    install(TARGETS ${SWIG_MODULE_bbowda_java_REAL_NAME}
            LIBRARY DESTINATION "${CMAKE_INSTALL_BINDIR}")
  else()
    install(TARGETS ${SWIG_MODULE_bbowda_java_REAL_NAME}
            LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}")
  endif()
  # unfortunately, SWIG will not tell us which .java files it generated, so we
  # have to find out ourselves - this is the only portable way to do so
  # (The bbowda*.i dependencies are there to force updating the list of sources
  # on any changes to the SWIG interface code, they are not direct inputs.)
  add_custom_command(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/java_sources.txt"
                     COMMAND ${CMAKE_COMMAND}
                             -DBINARY_DIR="${CMAKE_CURRENT_BINARY_DIR}"
                             -P "${CMAKE_CURRENT_SOURCE_DIR}/glob_java.cmake"
                     DEPENDS "${swig_generated_file_fullname}"
                             bbowda.i bbowda_java_swig_compilation
                             glob_java.cmake)
  add_jar(bbowda_jar SOURCES "@${CMAKE_CURRENT_BINARY_DIR}/java_sources.txt"
                     OUTPUT_NAME bbowda)
  install_jar(bbowda_jar "${CMAKE_INSTALL_DATADIR}/java")
  add_jar(bbowda_java_example SOURCES example.java INCLUDE_JARS bbowda_jar
          ENTRY_POINT example MANIFEST example.java.mf)
  install_jar(bbowda_java_example "${CMAKE_INSTALL_DATADIR}/java")
  if(WITH_JAVA_JAVADOC)
    message(STATUS "Building Javadoc documentation for the Java binding")
    create_javadoc(bbowda PACKAGES "com.dagopt.bbowda"
                          SOURCEPATH "${CMAKE_CURRENT_BINARY_DIR}/java"
                          CLASSPATH ${CMAKE_JAVA_INCLUDE_PATH}
                          INSTALLPATH "${CMAKE_INSTALL_DATADIR}/javadoc/bbowda"
                          WINDOWTITLE "BBOWDA\\\;Java\\\;API"
                          AUTHOR TRUE USE TRUE VERSION TRUE)
    add_dependencies(bbowda_javadoc bbowda_java_swig_compilation)
    if(WITH_JAVA_JAVADOC_PDF)
      message(STATUS "Building Javadoc PDF documentation for the Java binding")
      find_file(PDFDOCLET_JAR pdfdoclet-1.0.3-all.jar PATHS
                ~/.local/share/java /usr/local/share/java /usr/share/java
                "${CMAKE_INSTALL_DATADIR}/java"
                DOC "Full path to pdfdoclet-1.0.3-all.jar file."
                NO_DEFAULT_PATH)
      if(NOT PDFDOCLET_JAR OR NOT EXISTS "${PDFDOCLET_JAR}")
        message(FATAL_ERROR "pdfdoclet-1.0.3-all.jar not found. "
                "Please download "
                "https://sourceforge.net/projects/pdfdoclet/files/binaries/pdfdoclet-1.0.3/pdfdoclet-1.0.3.tar.gz/download, "
                "extract pdfdoclet-1.0.3-all.jar, and set PDFDOCLET_JAR if "
                "needed. (The default search path is "
                "{~/.local,/usr/local,/usr,\$prefix}/share/java.)")
      endif()
      find_file(TOOLS_JAR tools.jar PATHS
                /usr/lib/jvm/java/lib /usr/lib/jvm/java-1.8.0/lib
                ~/.local/share/java /usr/local/share/java /usr/share/java
                "${CMAKE_INSTALL_DATADIR}/java"
                DOC "Full path to tools.jar file."
                NO_DEFAULT_PATH)
      if(NOT TOOLS_JAR OR NOT EXISTS "${TOOLS_JAR}")
        message(FATAL_ERROR "tools.jar not found. Please either install "
                "OpenJDK 1.8.0 (the last version that included the JAR, it "
                "will also work with newer Java versions) or obtain tools.jar "
                "separately from a third party, and set TOOLS_JAR if needed. "
                "(The default search path is "
                "/usr/lib/jvm/{java,java-1.8.0}/lib, "
                "{~/.local,/usr/local,/usr,\$prefix}/share/java.)")
      endif()
      set(JAVADOC_BBOWDA_PDF "${CMAKE_CURRENT_BINARY_DIR}/javadoc/bbowda.pdf")
      set(PDFDOCLET_CONFIG_PROPERTIES
          "${CMAKE_CURRENT_SOURCE_DIR}/pdfdoclet-config.properties")
      add_custom_command(OUTPUT "${JAVADOC_BBOWDA_PDF}"
                         COMMAND "${Java_JAVADOC_EXECUTABLE}"
                                 -doclet com.tarsec.javadoc.pdfdoclet.PDFDoclet
                                 -docletpath
                                 "$<SHELL_PATH:${PDFDOCLET_JAR};${TOOLS_JAR}>"
                                 -pdf "${JAVADOC_BBOWDA_PDF}"
                                 -config "${PDFDOCLET_CONFIG_PROPERTIES}"
                                 -sourcepath "${CMAKE_CURRENT_BINARY_DIR}/java"
                                 -classpath ${CMAKE_JAVA_INCLUDE_PATH}
                                 -author -version
                                 "com.dagopt.bbowda"
                          DEPENDS "${swig_generated_file_fullname}"
                                  bbowda.i bbowda_java_swig_compilation
                                  "${PDFDOCLET_CONFIG_PROPERTIES}"
                          COMMENT "Building Javadoc PDF documentation...")
      add_custom_target(bbowda_javadoc_pdf ALL DEPENDS "${JAVADOC_BBOWDA_PDF}")
      install(FILES "${JAVADOC_BBOWDA_PDF}"
              DESTINATION "${CMAKE_INSTALL_DATADIR}/javadoc")
    else()
      message(STATUS
              "Not building Javadoc PDF documentation for the Java binding")
    endif()
  else()
    message(STATUS "Not building Javadoc documentation for the Java binding")
  endif()
else()
  message(STATUS "Not building SWIG Java binding")
endif()
