# incorrect arguments passed
if(archive AND missing)
  message(FATAL_ERROR "Wrong argument -Darchive=xyz and -Dmissing=xyz passed to script simultaneously")
endif()

# Missing tool mode: FLEX not found or BISON not found, just check that sources have not been
# tampered with, if possible (i.e., this is a git worktree)
if(missing)
  if(NOT source OR NOT srcdir)
    # Script Argument errors
    message(FATAL_ERROR "Script called incorrectly, you need to set -Dsource=xyz.l and -Dsrcdir=\${PROJECT_SOURCE_DIR}")
  endif()

  execute_process(
    COMMAND git status --porcelain -- ${source}
    WORKING_DIRECTORY ${srcdir}
    RESULT_VARIABLE ret
    OUTPUT_VARIABLE stdout
    ERROR_VARIABLE stderr)
  if(ret)
    # git not found, not a worktree, etc. Assume we are not in a dev environment and just bail-out
    #message(STATUS "git status could not verify if ${source} has been modified: ${stderr}")
    return()
  endif()

  if(NOT stdout)
    # git found, version controlled file, no changes
    #message(STATUS "${source} has not been modified")
    return()
  endif()

  # git found changes, yet we do not have flex/bison, abort
  message(FATAL_ERROR "${source} has been modified: you need ${missing} to regenerate dependent files!")
endif(missing)

# Archive mode: FLEX_FOUND and BISON_FOUND, we can regenerate the bundle
if(archive)
  if(NOT srcdir OR NOT builddir OR NOT archive)
    message(FATAL_ERROR "Missing argument -Dsrcdir=xyz -Dbuilddir=xyz -Darchive=xyz.tar")
  endif()

  file(GLOB_RECURSE generated_files RELATIVE ${CMAKE_CURRENT_BINARY_DIR} "*.l.c" "*.y.c" "*.y.h")
  foreach(file IN LISTS generated_files)
    # strip out the '.[ch]' from '.[ly].[ch]'
    string(REPLACE ".l.c" ".l" source ${file})
    string(REPLACE ".y.c" ".y" source ${source})
    string(REPLACE ".y.h" ".y" source ${source})

    # Check for problems: stray files in build directory
    execute_process(
      COMMAND git ls-files --error-unmatch ${srcdir}/${source}
      RESULT_VARIABLE ret
      OUTPUT_VARIABLE stdout
      ERROR_VARIABLE stderr
      ECHO_ERROR_VARIABLE)
    if(ret)
      # git not found, not a worktree, file not under version control, etc.
      message(FATAL_ERROR "git could not find ${source} under version control; Is this a clean git worktree and build directory (notably stray files in ${CMAKE_CURRENT_BINARY_DIR}?")
    endif()

    # Check for modifications
    execute_process(
      COMMAND git status --porcelain -- ${srcdir}/${source}
      RESULT_VARIABLE ret
      OUTPUT_VARIABLE stdout
      ERROR_VARIABLE stderr
      ECHO_ERROR_VARIABLE)
    if(ret)
      message(FATAL_ERROR "git status could not verify if ${source} has been modified")
    endif()

    if(NOT stdout)
      # we already checked the file exists, so it means no changes
      message(STATUS "${source}: not modified")
      continue()
    endif()

    string(STRIP "${stdout}" stdout)
    if(stdout MATCHES "^R?M ")
      message(STATUS "${stdout}: modified")
      list(APPEND modified ${file})
    else()
      message(FATAL_ERROR "${stdout}: the worktree is not clean (merging/rebase in progress?; removed files in git still in build?); ABORTING; run again when merge is complete and both worktree and build dir are clean")
    endif()
  endforeach()

  if(NOT modified)
    file(RELATIVE_PATH archive_rp ${srcdir} ${archive})

    message(WARNING "No modified .y/.l files. The archive has been created (for when a dev forgot to update the archive in a prior commit). Should you -really- commit the resulting archive? You can revert changes to the worktree with `git checkout -- ${archive_rp}`")
  endif()
  file(ARCHIVE_CREATE
    OUTPUT ${archive}
    PATHS ${generated_files})
endif(archive)

