# generated include directories
set(GENERATED_INCLUDE_DIR "${CMAKE_CURRENT_BINARY_DIR}/generated/include")
file(MAKE_DIRECTORY ${GENERATED_INCLUDE_DIR})

# directory for auxilliary files
set(GENERATED_AUX_DIR "${CMAKE_CURRENT_BINARY_DIR}/generated/auxiliary")
file(MAKE_DIRECTORY ${GENERATED_AUX_DIR})

# generated sources
set(GENERATED_SRC_DIR "${CMAKE_CURRENT_BINARY_DIR}/generated/src")
file(MAKE_DIRECTORY ${GENERATED_SRC_DIR})


# opsymbols.h
add_custom_command(
       OUTPUT ${GENERATED_INCLUDE_DIR}/opsymbols.h
       COMMAND ${PY3_INTERPRETER}
           ${ASY_SCRIPTS_DIR}/opsymbols.py
           --campfile ${ASY_RESOURCE_DIR}/camp.l
           --output ${GENERATED_INCLUDE_DIR}/opsymbols.h
       MAIN_DEPENDENCY ${ASY_RESOURCE_DIR}/camp.l
       DEPENDS ${ASY_SCRIPTS_DIR}/opsymbols.py
)

list(APPEND ASYMPTOTE_INCLUDES ${GENERATED_INCLUDE_DIR})
list(APPEND ASYMPTOTE_GENERATED_HEADERS ${GENERATED_INCLUDE_DIR}/opsymbols.h)
list(APPEND ASYMPTOTE_SYM_PROCESS_NEEDED_HEADERS ${GENERATED_INCLUDE_DIR}/opsymbols.h)

# run-* files
function(_int_add_runtime_file runtime_file)
   set(RUNTIME_FILE_IN_BASE ${ASY_SRC_TEMPLATES_DIR}/${runtime_file})
   set(RUNTIME_FILES_OUT ${GENERATED_SRC_DIR}/${runtime_file}.cc ${GENERATED_INCLUDE_DIR}/${runtime_file}.h)
   set(RUNTIME_SCRIPT ${ASY_SCRIPTS_DIR}/runtime.pl)
   set(OPSYM_FILE ${GENERATED_INCLUDE_DIR}/opsymbols.h)
   set(RUNTIME_BASE_FILE ${ASY_SRC_TEMPLATES_DIR}/runtimebase.in)
   add_custom_command(
           OUTPUT ${RUNTIME_FILES_OUT}
           COMMAND ${PERL_INTERPRETER} ${RUNTIME_SCRIPT}
           --opsym-file ${OPSYM_FILE}
           --runtime-base-file ${RUNTIME_BASE_FILE}
           --src-template-dir ${ASY_SRC_TEMPLATES_DIR}
           --prefix ${runtime_file}
           --header-out-dir ${GENERATED_INCLUDE_DIR}
           --src-out-dir ${GENERATED_SRC_DIR}
           MAIN_DEPENDENCY ${RUNTIME_FILE_IN_BASE}.in
           DEPENDS ${RUNTIME_SCRIPT} ${OPSYM_FILE} ${RUNTIME_BASE_FILE} ${RUNTIME_FILE_DEP}
   )
endfunction()

macro(add_runtime_file runtime_file)
   _int_add_runtime_file(${runtime_file})
   list(APPEND ASY_GENERATED_BUILD_SOURCES
           ${GENERATED_SRC_DIR}/${runtime_file}.cc
   )
   set(_ASY_GENERATED_HEADER_NAME ${GENERATED_INCLUDE_DIR}/${runtime_file}.h)
   list(APPEND ASYMPTOTE_GENERATED_HEADERS ${_ASY_GENERATED_HEADER_NAME})
   list(APPEND ASYMPTOTE_SYM_PROCESS_NEEDED_HEADERS ${_ASY_GENERATED_HEADER_NAME})
endmacro()

foreach(RUNTIME_FILE ${RUNTIME_BUILD_FILES})
   add_runtime_file(${RUNTIME_FILE})
endforeach()

# keywords.h
set(KEYWORDS_HEADER_OUT ${GENERATED_INCLUDE_DIR}/keywords.h)
add_custom_command(
       OUTPUT ${KEYWORDS_HEADER_OUT}
       COMMAND ${PY3_INTERPRETER} ${ASY_SCRIPTS_DIR}/keywords.py
           --camplfile ${ASY_RESOURCE_DIR}/camp.l
           --output ${GENERATED_INCLUDE_DIR}/keywords.h
           --process-file ${ASY_SRC_DIR}/asyprocess.cc
       MAIN_DEPENDENCY ${ASY_RESOURCE_DIR}/camp.l
       DEPENDS ${ASY_SCRIPTS_DIR}/keywords.py ${ASY_SRC_DIR}/asyprocess.cc
)

list(APPEND ASYMPTOTE_GENERATED_HEADERS ${KEYWORDS_HEADER_OUT})
list(APPEND ASYMPTOTE_SYM_PROCESS_NEEDED_HEADERS ${KEYWORDS_HEADER_OUT})

set(camp_lex_output ${GENERATED_SRC_DIR}/lex.yy.cc)
set(camp_l_file ${ASY_RESOURCE_DIR}/camp.l)

if (WIN32)
   list(APPEND FLEX_ARGS --wincompat)
endif()

# flex + bison

# flex
add_custom_command(
       OUTPUT ${camp_lex_output}
       COMMAND ${FLEX_EXECUTABLE} ${FLEX_ARGS} -o ${camp_lex_output} ${camp_l_file}
       MAIN_DEPENDENCY ${camp_l_file}
)

list(APPEND ASY_GENERATED_BUILD_SOURCES ${camp_lex_output})

# bison
set(bison_output ${GENERATED_SRC_DIR}/camp.tab.cc)
set(bison_header ${GENERATED_INCLUDE_DIR}/camp.tab.h)
set(bison_input ${ASY_RESOURCE_DIR}/camp.y)
add_custom_command(
       OUTPUT ${bison_output} ${bison_header}
       COMMAND ${BISON_EXECUTABLE} -t --header=${bison_header} -o ${bison_output} ${bison_input}
       MAIN_DEPENDENCY ${bison_input}
)

list(APPEND ASY_GENERATED_BUILD_SOURCES ${bison_output})
list(APPEND ASYMPTOTE_GENERATED_HEADERS ${bison_header})
list(APPEND ASYMPTOTE_SYM_PROCESS_NEEDED_HEADERS ${bison_header})

# generate enums from csv
foreach(csv_enum_file ${ASY_CSV_ENUM_FILES})
   set(generated_header_file ${GENERATED_INCLUDE_DIR}/${csv_enum_file}.h)

   add_custom_command(
           OUTPUT ${generated_header_file}
           COMMAND ${PY3_INTERPRETER} ${ASY_SCRIPTS_DIR}/generate_enums.py
           --language cpp
           --name ${csv_enum_file}
           --input ${ASY_RESOURCE_DIR}/${csv_enum_file}.csv
           --output ${generated_header_file}
           --xopt namespace=camp
           MAIN_DEPENDENCY ${ASY_RESOURCE_DIR}/${csv_enum_file}.csv
           DEPENDS ${ASY_SCRIPTS_DIR}/generate_enums.py
   )

   list(APPEND ASYMPTOTE_GENERATED_HEADERS ${generated_header_file})
   list(APPEND ASYMPTOTE_SYM_PROCESS_NEEDED_HEADERS ${generated_header_file})
endforeach ()

# raw.i files
# generating preprocessed files
set(FINDSYM_FILE ${ASY_SCRIPTS_DIR}/findsym.py)
# combine all files into allsymbols.h
function(symfile_preprocess src_dir symfile symfile_raw_output_varname header_output_varname)
   set(symfile_raw_output_var ${symfile_raw_output_varname})
   set(processed_output_file ${GENERATED_AUX_DIR}/${symfile}.raw.i)
   set(${symfile_raw_output_var} ${processed_output_file} PARENT_SCOPE)

   set(cxx_preprocessor ${CMAKE_CXX_COMPILER})

   if (MSVC)
       if (GCCCOMPAT_CXX_COMPILER_FOR_MSVC)
           set(cxx_preprocessor ${GCCCOMPAT_CXX_COMPILER_FOR_MSVC})
       else()
           set(msvc_flag --msvc)
       endif()
   endif()

   set(asy_includes_list "$<TARGET_PROPERTY:asy,INCLUDE_DIRECTORIES>")
   set(asy_macros_list "$<TARGET_PROPERTY:asy,COMPILE_DEFINITIONS>")
   set(asy_cxx_std "$<TARGET_PROPERTY:asy,CXX_STANDARD>")

   if (UNIX)
       # for unix systems, need verbatim flag because
       # the arguments contains semicolon, though somehow
       # verbatim option causes problems for windows
       set(ADDITIONAL_ADD_CUSTOM_CMD_ARGS VERBATIM)
   endif()

   add_custom_command(
           OUTPUT ${processed_output_file}
           COMMAND ${PY3_INTERPRETER} ${ASY_SCRIPTS_DIR}/gen_preprocessed_depfile.py
           --cxx-compiler=${cxx_preprocessor}
           "$<$<BOOL:${asy_includes_list}>:--include-dirs=$<REMOVE_DUPLICATES:${asy_includes_list}>>"
           "$<$<BOOL:${asy_cxx_std}>:--cxx-standard=${asy_cxx_std}>"
           "$<$<BOOL:${asy_macros_list}>:--macro-defs=$<REMOVE_DUPLICATES:${asy_macros_list}>>"
           --out-dep-file=${GENERATED_AUX_DIR}/${symfile}.d
           --out-i-file=${processed_output_file}
           --in-src-file=${src_dir}/${symfile}.cc
           ${msvc_flag}
           DEPFILE ${GENERATED_AUX_DIR}/${symfile}.d
           BYPRODUCTS ${GENERATED_AUX_DIR}/${symfile}.d
           DEPENDS ${src_dir}/${symfile}.cc
           ${ASY_SCRIPTS_DIR}/gen_preprocessed_depfile.py
           ${ASYMPTOTE_SYM_PROCESS_NEEDED_HEADERS}
           ${ADDITIONAL_ADD_CUSTOM_CMD_ARGS}
   )
   # *.symbols.h file
   set(symfile_raw_output_var ${header_output_varname})
   set(sym_header_file ${GENERATED_INCLUDE_DIR}/${symfile}.symbols.h)
   set(${symfile_raw_output_var} ${sym_header_file} PARENT_SCOPE)
   add_custom_command(
           OUTPUT ${sym_header_file}
           COMMAND ${PY3_INTERPRETER} ${FINDSYM_FILE}
               ${sym_header_file}
               ${processed_output_file}
           MAIN_DEPENDENCY ${processed_output_file}
   )
endfunction()

# preprocess each individual symbol files
foreach(SYM_FILE ${SYMBOL_STATIC_BUILD_FILES})
   symfile_preprocess(${ASY_SRC_DIR} ${SYM_FILE} SYMFILE_OUT HEADER_OUT)
   list(APPEND SYMFILE_OUT_LIST ${SYMFILE_OUT})
   list(APPEND ASYMPTOTE_GENERATED_HEADERS ${HEADER_OUT})
endforeach()

foreach(SYM_FILE ${RUNTIME_BUILD_FILES})
   symfile_preprocess(${GENERATED_SRC_DIR} ${SYM_FILE} SYMFILE_OUT HEADER_OUT)
   list(APPEND SYMFILE_OUT_LIST ${SYMFILE_OUT})
   list(APPEND ASYMPTOTE_GENERATED_HEADERS ${HEADER_OUT})
endforeach ()

# allsymbols.h
add_custom_command(
       OUTPUT ${GENERATED_INCLUDE_DIR}/allsymbols.h
       COMMAND ${PY3_INTERPRETER} ${FINDSYM_FILE}
           ${GENERATED_INCLUDE_DIR}/allsymbols.h
           ${SYMFILE_OUT_LIST}
       DEPENDS ${FINDSYM_FILE} ${SYMFILE_OUT_LIST}
)

list(APPEND ASYMPTOTE_GENERATED_HEADERS ${GENERATED_INCLUDE_DIR}/allsymbols.h)

# macro files
message(STATUS "Generating revision.cc file")
set(revision_cc_file ${GENERATED_SRC_DIR}/revision.cc)
configure_file(${ASY_RESOURCE_DIR}/template_rev.cc.in ${revision_cc_file})
list(APPEND ASY_GENERATED_BUILD_SOURCES ${revision_cc_file})

add_custom_target(asy_gen_headers
       DEPENDS ${ASYMPTOTE_GENERATED_HEADERS}
)