# This file contains functions used to generate a list of macros that are used
# to create fixed-size typelists. See vtkTypeList for details.

# Concatenates a list of strings into a single string, since string(CONCAT ...)
# is not currently available for VTK's cmake version.
# Internal method.
function(CollapseString input output)
  set(temp "")
  foreach(line IN LISTS input)
    string(APPEND temp ${line})
  endforeach()
  set(${output} "${temp}" PARENT_SCOPE)
endfunction()

# Create list of numbers, start to end _inclusive_, storing the list in result.
# Internal method
function(CreateTypeListMacros_range start end result)
  set(temp)
  set(i ${start})
  while(NOT i GREATER end)
    list(APPEND temp ${i})
    math(EXPR i "${i} + 1")
  endwhile()
  set(${result} ${temp} PARENT_SCOPE)
endfunction()

# Creates a macro for case n = 1
# Internal method
function(CreateTypeListMacros_create_macro_1 macroPrefix typeList nullType result)
  set(temp
    "#define ${macroPrefix}_1(t1) \\\n"
    "  ${typeList}<t1, ${nullType} >\n"
  )
  CollapseString("${temp}" temp)
  set(${result} ${temp} PARENT_SCOPE)
endfunction()

# Creates a macro for case ${num}, where ${num} > 1
# Internal method
function(CreateTypeListMacros_create_macro num macroPrefix typeList nullType result)
  set(nums)
  CreateTypeListMacros_range(2 ${num} nums)
  math(EXPR lastNum "${num} - 1")
  set(decl "#define ${macroPrefix}_${num}")
  set(macroArgs "t1")
  set(lastMacroArgs "")
  set(delim "")
  foreach(i ${nums})
    string(APPEND macroArgs ", t${i}")
    string(APPEND lastMacroArgs "${delim}t${i}")
    set(delim ", ")
  endforeach()

  set(temp
    "${decl}(${macroArgs}) \\\n"
    "  ${typeList}<t1, \\\n"
    "    ${macroPrefix}_${lastNum}(${lastMacroArgs}) >\n"
  )
  CollapseString("${temp}" temp)
  set(${result} ${temp} PARENT_SCOPE)
endfunction()

# This function generates a header file that generates TypeList creator macros.
#
# Usage:
# HEADER = output string variable that will contain the complete header.
# MAX_SIZE = largest typelist macro to create.
# MACRO_PREFIX = prefix to use for macro names
# TYPELIST_T = type for TypeList implementation
# NULLTYPE_T = type for NullType implementation
#
# The output is generated to look like:
#
# #define ${MACRO_PREFIX}_1(t1) \
#   ${TYPELIST_T}<t1, ${NULLTYPE_T} >
# #define ${MACRO_PREFIX}_2(t1, t2) \
#   ${TYPELIST_T}<t1, \
#     ${MACRO_PREFIX}_1(t2)
# #define ${MACRO_PREFIX}_3(t1, t2, t3) \
#   ${TYPELIST_T}<t1, \
#     ${MACRO_PREFIX}_2(t2, t3)
# And so on, up to ${MACRO_PREFIX}_${MAX_SIZE}.
function(CreateTypeListMacros HEADER MAX_SIZE MACRO_PREFIX TYPELIST_T
         NULLTYPE_T)
  set(temp "")
  set(result
    "// This file is autogenerated by vtkCreateTypeListMacros.cmake.\n"
    "// Do not edit this file, your changes will not be saved.\n"
    "\n"
    "#ifndef vtkTypeListMacros_h\n"
    "#define vtkTypeListMacros_h\n"
    "\n"
    "#include \"vtkTypeList.h\"\n"
    "\n"
  )
  set(nums "")
  CreateTypeListMacros_range(2 ${MAX_SIZE} nums)
  CreateTypeListMacros_create_macro_1(
    "${MACRO_PREFIX}"
    "${TYPELIST_T}"
    "${NULLTYPE_T}"
    temp
  )
  list(APPEND result ${temp})
  foreach(num IN LISTS nums)
    CreateTypeListMacros_create_macro(
      "${num}"
      "${MACRO_PREFIX}"
      "${TYPELIST_T}"
      "${NULLTYPE_T}"
      temp
    )
    list(APPEND result ${temp})
  endforeach()

  list(APPEND result "\n#endif // vtkTypeListMacros_h")
  CollapseString("${result}" result)
  set(${HEADER} "${result}" PARENT_SCOPE)
endfunction()
