###############################################################################
# configure tcl
# TCL support is currently unstable. Show the warning message
message(WARNING "TCL support is currently unstable.But if we you still want to use it, please go ahead!")

if(WRAP_ITK_INSTALL_COMPONENT_PER_MODULE)
  message(WARNING "Option WRAP_ITK_INSTALL_COMPONENT_PER_MODULE is not supported for TCL wrapping language")
endif()

find_package(TCL REQUIRED)
# Hide useless settings provided by FindTCL.
foreach(entry TCL_LIBRARY_DEBUG
              TK_LIBRARY_DEBUG
              TCL_STUB_LIBRARY
              TCL_STUB_LIBRARY_DEBUG
              TK_STUB_LIBRARY
              TK_STUB_LIBRARY_DEBUG
              TK_WISH)
  set(${entry} "${${entry}}" CACHE INTERNAL "This value is not used by ITK.")
endforeach()

include_directories(${TCL_INCLUDE_PATH} ${TK_INCLUDE_PATH})


###############################################################################
# store the current dir, so it can be reused later
set(ITK_WRAP_TCL_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}" CACHE INTERNAL "tcl source dir")
set(ITK_WRAP_TCL_BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}" CACHE INTERNAL "tcl binary dir")


###############################################################################
# create the tcl directory in the classindex dir
file(MAKE_DIRECTORY ${WRAPPER_MASTER_INDEX_OUTPUT_DIR}/tcl)



macro(itk_wrap_module_tcl library_name)
  set(ITK_WRAP_TCL_LIBRARY_DEPS )
  set(ITK_WRAP_TCL_LIBRARY_DECLS )
  set(ITK_WRAP_TCL_LIBRARY_CALLS )
  set(ITK_WRAP_TCL_CXX_FILES )
endmacro()


macro(itk_end_wrap_module_tcl)

  # Loop over the extra swig input files and add them to the generated files
  # lists. Guess that the generated cxx output will have the same name as
  # the .i input file.
  foreach(source ${WRAPPER_LIBRARY_SWIG_INPUTS})
    get_filename_component(base_name ${source} NAME_WE)
    itk_wrap_submodule_tcl("${base_name}")
    itk_end_wrap_submodule_tcl("${base_name}")
  endforeach()



  # create the tcl customization stuff in the main module
  # it allow to group the tcls module in a single shared lib, by loading the int
  # functions of the module. I also import the objects from the submodules in the
  # main module.
  #
  # It uses ITK_WRAP_TCL_LIBRARY_DECLS, ITK_WRAP_TCL_LIBRARY_CALLS
  configure_file("${ITK_WRAP_TCL_SOURCE_DIR}/main_module_ext.i.in"
    "${WRAPPER_MASTER_INDEX_OUTPUT_DIR}/tcl/${WRAPPER_LIBRARY_NAME}_ext.i"
    @ONLY)
  )


  # set some var reused later
  set(interface_file "${WRAPPER_MASTER_INDEX_OUTPUT_DIR}/${WRAPPER_LIBRARY_NAME}.i")
  set(lib ${WRAPPER_LIBRARY_NAME}Tcl)
  set(cpp_file "${CMAKE_CURRENT_BINARY_DIR}/${WRAPPER_LIBRARY_NAME}Tcl.cpp")

  set(swig_command ${SWIG_EXECUTABLE})
  if(ITK_USE_CCACHE)
    set(swig_command ${CCACHE_EXECUTABLE} ${swig_command})
  endif()

  # and generate c++ code from the main module swig interface.
  add_custom_command(
    OUTPUT ${cpp_file}
    COMMAND ${swig_command} -c++ -tcl -O -features autodoc=1 # -Werror
#       -fcompact
    -w509 # Overloaded method
    -w365 # operator+= ignored
    -w366 # operator-= ignored
    -w367 # operator*= ignored
    -w368 # operator/= ignored
    -w378 # operator!= ignored
    -w503 # Can't wrap 'operator []' unless renamed to a valid identifier.
    -w508 # Declaration of '???' shadows declaration accessible via operator->()
    ### TODO: remove that once the bug for std::vector is fixed ###
    -w401 # Maybe you forgot to instantiate 'XXX' using %template.
    ###
    -w350 -w394 -w395  # operator new/new[]/delete[] ignored
    -o ${cpp_file}
    -I${GENERATORS_SRC_DIR}
    -I${WRAP_ITK_TYPEDEFS_DIRECTORY}/tcl
    -I${WRAP_ITK_TYPEDEFS_DIRECTORY}
    -outdir ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}
    ${interface_file}
    WORKING_DIRECTORY ${WRAPPER_MASTER_INDEX_OUTPUT_DIR}/tcl
    DEPENDS ${DEPS} ${ITK_WRAP_TCL_LIBRARY_DEPS} ${interface_file} ${WRAPPER_MASTER_INDEX_OUTPUT_DIR}/tcl/${WRAPPER_LIBRARY_NAME}_ext.i ${SWIG_EXECUTABLE}
  )
  WRAP_ITK_BINDINGS_INSTALL("/Tcl" "${tcl_file}")

  # build all the c++ files from this module in a common lib
  set(lib ${WRAPPER_LIBRARY_NAME}Tcl)
  add_library(${lib} SHARED ${cpp_file} ${ITK_WRAP_TCL_CXX_FILES} ${WRAPPER_LIBRARY_CXX_SOURCES})
  if(CMAKE_COMPILER_IS_GNUCC)
    # disable warnings generated by swig
    set_target_properties(${lib} PROPERTIES COMPILE_FLAGS "-Wno-missing-field-initializers -Wno-shadow")
  endif()
  target_link_libraries(${lib} ${WRAPPER_LIBRARY_LINK_LIBRARIES} ${TCL_LIBRARY})
  if(${module_prefix}_WRAP_EXPLICIT AND NOT ${WRAPPER_LIBRARY_NAME} STREQUAL ITKTclBase)
    target_link_libraries(${lib} ${WRAPPER_LIBRARY_NAME}Explicit)
  endif()
  add_dependencies(${lib} ${WRAPPER_LIBRARY_NAME}Swig)
  install(TARGETS "${lib}"
    DESTINATION "${ITK_INSTALL_LIBRARY_DIR}/ITK-${ITK_VERSION_MAJOR}.${ITK_VERSION_MINOR}/Tcl"
    COMPONENT ${WRAP_ITK_INSTALL_COMPONENT_IDENTIFIER}RuntimeLibraries
    )
  if(NOT EXTERNAL_WRAP_ITK_PROJECT)
    # don't depends on the targets from wrapitk in external projects
    foreach(dep ${WRAPPER_LIBRARY_DEPENDS})
      add_dependencies(${lib} ${dep}Swig)
    endforeach()
  endif()

endmacro()


macro(itk_end_wrap_submodule_tcl group_name)

  set(base_name ${group_name})

  # the default typemaps, exception handler, and includes
  set(ITK_WRAP_TCL_SWIG_EXT "%import tclBase.i\n\n${ITK_WRAP_TCL_SWIG_EXT}")


  # create the swig interface for all the groups in the module
  #
  set(interface_file "${WRAPPER_MASTER_INDEX_OUTPUT_DIR}/${base_name}.i")
  set(lib ${group_name}Tcl)
  set(cpp_file "${CMAKE_CURRENT_BINARY_DIR}/${base_name}Tcl.cpp")

  # create the tcl customization for that wrap_*.cmake file.
  configure_file("${ITK_WRAP_TCL_SOURCE_DIR}/module_ext.i.in"
  "${WRAPPER_MASTER_INDEX_OUTPUT_DIR}/tcl/${group_name}_ext.i"
  @ONLY)
  )

  # prepare dependencies
  set(DEPS )
  foreach(dep ${WRAPPER_LIBRARY_DEPENDS})
    list(APPEND DEPS ${${dep}SwigFiles})
  endforeach()

  set(swig_command ${SWIG_EXECUTABLE})
  if(ITK_USE_CCACHE)
    set(swig_command ${CCACHE_EXECUTABLE} ${swig_command})
  endif()

  # and run swig to produce the c++ file and the .tcl file
  add_custom_command(
    OUTPUT ${cpp_file}
    COMMAND ${swig_command} -c++ -tcl -O -features autodoc=1 # -Werror
#       -fcompact
    -w509 # Overloaded method
    -w365 # operator+= ignored
    -w366 # operator-= ignored
    -w367 # operator*= ignored
    -w368 # operator/= ignored
    -w378 # operator!= ignored
    -w503 # Can't wrap 'operator []' unless renamed to a valid identifier
    -w508 # Declaration of '???' shadows declaration accessible via operator->()
    ### TODO: remove that once the bug for std::vector is fixed ###
    -w401 # Maybe you forgot to instantiate 'XXX' using %template.
    ###
    -w350 -w394 -w395  # operator new/new[]/delete[] ignored
    -o ${cpp_file}
    -I${GENERATORS_SRC_DIR}
    -I${WRAP_ITK_TYPEDEFS_DIRECTORY}/tcl
    -I${WRAP_ITK_TYPEDEFS_DIRECTORY}
    -outdir ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}
    ${interface_file}
    WORKING_DIRECTORY ${WRAPPER_MASTER_INDEX_OUTPUT_DIR}/tcl
    DEPENDS ${DEPS} ${interface_file} ${WRAPPER_MASTER_INDEX_OUTPUT_DIR}/tcl/${base_name}_ext.i ${SWIG_EXECUTABLE}
    # ${ITK_WRAP_TCL_LIBRARY_DEPS}
  )

# gcc visibility can't be used without getting errors when passing objects
# from one module to an other
#
#    if(CMAKE_COMPILER_IS_GNUCC)
#      set_target_properties(${lib} PROPERTIES COMPILE_FLAGS "-fvisibility=hidden")
#    endif()

  # add the c++ files which will be generated by the swig command to the
  # list of tcl related c++ files, so they can be built at the end
  # of the current module.
  list(APPEND ITK_WRAP_TCL_CXX_FILES ${cpp_file})

  # add needed files to the deps list
  list(APPEND ITK_WRAP_TCL_LIBRARY_DEPS "${WRAPPER_MASTER_INDEX_OUTPUT_DIR}/tcl/${base_name}_ext.i" "${cpp_file}")

  # add this wrap_*.cmake stuff to the list of modules to init in the main module.
  # first the extern c declaration
  string(REGEX REPLACE "^(.)(.+)$" "\\1" first "${group_name}")
  string(REGEX REPLACE "^(.)(.+)$" "\\2" rest "${group_name}")
  string(TOUPPER "${first}" first)
  string(TOLOWER "${rest}" rest)
  set(capital_group_name "${first}${rest}tcl")
  set(ITK_WRAP_TCL_LIBRARY_DECLS "${ITK_WRAP_TCL_LIBRARY_DECLS}extern \"C\" int ${capital_group_name}_Init( Tcl_Interp* );\n")
  # and the call of the extern function
  set(ITK_WRAP_TCL_LIBRARY_CALLS "${ITK_WRAP_TCL_LIBRARY_CALLS}  ${capital_group_name}_Init( interp );\n")

endmacro()



macro(itk_wrap_one_type_tcl wrap_method wrap_class swig_name template_params)
endmacro()


macro(ADD_TCL_CONFIG_TEMPLATE base_name wrap_class swig_name template_params)
endmacro()


macro(itk_wrap_submodule_tcl module)
  set(ITK_WRAP_TCL_SWIG_EXT "")
endmacro()


macro(itk_wrap_named_class_tcl class swig_name)
  # store the current class wrapped, so we can generate the typemaps for itk::ImageSource
  set(ITK_WRAP_TCL_CURRENT_CLASS "${class}")
  set(ITK_WRAP_TCL_CURRENT_SWIG_NAME "${swig_name}")
endmacro()


macro(itk_wrap_template_tcl name types)
endmacro()


macro(itk_wrap_simple_type_tcl wrap_class swig_name)
  if("${wrap_class}" MATCHES "<.*>")
    string(REGEX REPLACE "^([^<]+)< *(.+) *>([^>]*)$" "\\1" cpp_name "${wrap_class}")
    string(REGEX REPLACE "^([^<]+)< *(.+) *>([^>]*)$" "\\2" template_params "${wrap_class}")
    string(REGEX REPLACE "^([^<]+)< *(.+) *>([^>]*)$" "\\3" ext_def "${wrap_class}")
  else()
    set(cpp_name "${wrap_class}")
    set(template_params NO_TEMPLATE)
    set(ext_def "")
  endif()
  string(REGEX REPLACE ".*::" "" simple_name "${cpp_name}")
#  message("${wrap_class} -- ${swig_name}")
#  message("${cpp_name} -- ${template_params} -- ${ext_def}")

# can't use that because std_vector.i complains loudly (with an error) about invalid superclass when that superclass is a std::vector
# not wrapped with %template
# but we can't declare them outside the current file without making swig use function defined outside
# TODO: reenable that once that bug is fixed
#
#   if("${cpp_name}" STREQUAL "itk::VectorContainer" AND NOT "${swig_name}" MATCHES "Pointer$")
#     # add a template definition for the superclass which is not in ITK
#     string(REGEX REPLACE "^[^,]+, *(.+) *$" "\\1" superclass_template_param "${template_params}")
#     if("${superclass_template_param}" MATCHES "::")
#       set(param "${superclass_template_param}")
#       string(REPLACE "::" "" superclass_template_param "${superclass_template_param}")
#       string(REPLACE "unsigned" "U" superclass_template_param "${superclass_template_param}")
#       string(REPLACE "signed" "S" superclass_template_param "${superclass_template_param}")
#       string(REPLACE "char" "C" superclass_template_param "${superclass_template_param}")
#       string(REPLACE "short" "S" superclass_template_param "${superclass_template_param}")
#       string(REPLACE "long" "L" superclass_template_param "${superclass_template_param}")
#       string(REPLACE "float" "F" superclass_template_param "${superclass_template_param}")
#       string(REPLACE "double" "D" superclass_template_param "${superclass_template_param}")
#       string(REPLACE " " "" superclass_template_param "${superclass_template_param}")
#       string(REPLACE "<" "" superclass_template_param "${superclass_template_param}")
#       string(REPLACE ">" "" superclass_template_param "${superclass_template_param}")
#       string(REPLACE "," "" superclass_template_param "${superclass_template_param}")
#       set(ITK_WRAP_TCL_SWIG_EXT "${ITK_WRAP_TCL_SWIG_EXT}%template(${swig_name}_Superclass) std::vector< ${superclass_template_param} >;\n")
#     endif()
#   endif()

# This part is useless because swig doesn't recognize that std::map< X, Y > is the same than
# std::map< X, Y, std::less< X > > and doesn't support a third parameter in the template
# specification.
# TODO: make a bugreport
#
#   if("${cpp_name}" STREQUAL "itk::MapContainer" AND NOT "${swig_name}" MATCHES "Pointer$")
#     # add a template definition for the superclass which is not in ITK
#     string(REGEX REPLACE "^[^,]+, *(.+) *$" "\\1" superclass_template_param "${template_params}")
#     if("${superclass_template_param}" MATCHES "::")
#       set(param "${superclass_template_param}")
#       string(REPLACE "::" "" superclass_template_param "${superclass_template_param}")
#       string(REPLACE "unsigned" "U" superclass_template_param "${superclass_template_param}")
#       string(REPLACE "signed" "S" superclass_template_param "${superclass_template_param}")
#       string(REPLACE "char" "C" superclass_template_param "${superclass_template_param}")
#       string(REPLACE "short" "S" superclass_template_param "${superclass_template_param}")
#       string(REPLACE "long" "L" superclass_template_param "${superclass_template_param}")
#       string(REPLACE "float" "F" superclass_template_param "${superclass_template_param}")
#       string(REPLACE "double" "D" superclass_template_param "${superclass_template_param}")
#       string(REPLACE " " "" superclass_template_param "${superclass_template_param}")
#       string(REPLACE "<" "" superclass_template_param "${superclass_template_param}")
#       string(REPLACE ">" "" superclass_template_param "${superclass_template_param}")
#       string(REPLACE "," "" superclass_template_param "${superclass_template_param}")
#       set(ITK_WRAP_TCL_SWIG_EXT "${ITK_WRAP_TCL_SWIG_EXT}%template(${swig_name}_Superclass) std::map< unsigned long, ${superclass_template_param}, std::less< unsigned long > >;\n")
#     endif()
#   endif()
endmacro()




###############################################################################
# Create the TclUtils library

if(NOT EXTERNAL_WRAP_ITK_PROJECT)
  add_subdirectory(Tests)

  macro(itk_end_wrap_modules_tcl)
    ###############################################################################
    # Configure pkgIndex.tcl for the build tree.
    if(CMAKE_CONFIGURATION_TYPES)
      foreach(config ${CMAKE_CONFIGURATION_TYPES})
        set(ITK_WRAP_TCL_PACKAGE_DIR "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/${config}")
        configure_file("${ITK_WRAP_TCL_SOURCE_DIR}/pkgIndex.tcl.in"
                       "${ITK_WRAP_TCL_BINARY_DIR}/${config}/pkgIndex.tcl"
                       @ONLY)
      endforeach()
    else()
      set(ITK_WRAP_TCL_PACKAGE_DIR "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}")
      configure_file("${ITK_WRAP_TCL_SOURCE_DIR}/pkgIndex.tcl.in"
                     "${ITK_WRAP_TCL_BINARY_DIR}/pkgIndex.tcl"
                     @ONLY)
    endif()

    # configure pkgIndex.tcl for the installed tree
    set(ITK_WRAP_TCL_PACKAGE_DIR "${ITK_INSTALL_LIBRARY_DIR}/ITK-${ITK_VERSION_MAJOR}.${ITK_VERSION_MINOR}/Tcl")
    configure_file("${ITK_WRAP_TCL_SOURCE_DIR}/pkgIndex.tcl.in"
                   "${ITK_WRAP_TCL_BINARY_DIR}/InstallOnly/itkwish_wont_find_me_here/pkgIndex.tcl"
                  @ONLY)
    WRAP_ITK_BINDINGS_INSTALL(/Tcl "${ITK_WRAP_TCL_BINARY_DIR}/InstallOnly/itkwish_wont_find_me_here/pkgIndex.tcl")

    #install the actual executable
    install(FILES ${ITK_WRAP_TCL_SOURCE_DIR}/itkinteraction.tcl
                  ${ITK_WRAP_TCL_SOURCE_DIR}/itktesting.tcl
                  ${ITK_WRAP_TCL_SOURCE_DIR}/itkdata.tcl
                  ${ITK_WRAP_TCL_SOURCE_DIR}/itkutils.tcl
                  DESTINATION "${ITK_INSTALL_LIBRARY_DIR}/ITK-${ITK_VERSION_MAJOR}.${ITK_VERSION_MINOR}/Tcl"
                  COMPONENT ${WRAP_ITK_INSTALL_COMPONENT_IDENTIFIER}RuntimeLibraries
           )

  endmacro()

  macro(itk_wrap_modules_tcl)
    add_subdirectory(${ITK_WRAP_TCL_SOURCE_DIR}/TclBase)
  endmacro()

else()
  macro(itk_end_wrap_modules_tcl)
    # just do nothing
  endmacro()

  macro(itk_wrap_modules_tcl)
    # just do nothing
  endmacro()

endif()
