#---------------------------------------------------------------------
# Sub project name

PROJECT( elxComponents )

#---------------------------------------------------------------------
# Set the libraries to be linked.

# Linux gave an error, if param was linked. This was only
# when we still used .dll's. I'm not sure if it will still
# give an error, but as long as linux does not complain
# about the missing param, just leave it out.
IF( UNIX )
  IF ( NOT APPLE )
    SET(elxLinkLibs
      xoutlib
      elxCommon
      elxCore
      ITKBasicFilters
      ITKNumerics
      ITKIO
      ITKCommon
      ITKStatistics )
  ENDIF( NOT APPLE )
ENDIF( UNIX )

# Interestingly, visual c++ and MAC-GCC do need param
IF( WIN32 OR APPLE )
  SET( elxLinkLibs
    param
    xoutlib
    elxCommon
    elxCore
    ITKBasicFilters
    ITKNumerics
    ITKIO
    ITKCommon
    ITKStatistics )
ENDIF( WIN32 OR APPLE )

#--------------------------------------------------------------------
# Prepare elxInstallComponentFunctionDeclarations.h and
# elxInstallComponentFunctionCalls.h
# In the ADD_ELXCOMPONENT macro a line is added
#

SET( InstallFunctionDeclarationFile
  ${elastix_BINARY_DIR}/elxInstallComponentFunctionDeclarations.h )
SET( InstallFunctionCallFile
  ${elastix_BINARY_DIR}/elxInstallComponentFunctionCalls.h )

FILE( WRITE ${InstallFunctionDeclarationFile}
  "\n" "//This file is generated by CMake. Do not edit manually!\n\n" )
FILE( WRITE ${InstallFunctionCallFile}
  "\n" "//This file is generated by CMake. Do not edit manually!\n\n" )


#---------------------------------------------------------------------
# Macros that simplify the addition (and removal) of elx-components
#
# Usage:
# ADD_ELXCOMPONENT( <name_of_lib> <list_of_source_and_header_files> )
#
# The name_of_lib should be equal to the name of the elx class,
# which also should be the name used in the elxInstallMacro, in the
# the .cxx file of the component.
#
# The REMOVE_ELXCOMPONENT is in some cases useful, if you want to
# skip building the component in case some other cmake setting is not
# correct. Most users will not need to invoke this macro though.
#
# Usage:
# REMOVE_ELXCOMPONENT( <name_of_lib> )
#
INCLUDE( CMakeDependentOption )

MACRO( REMOVE_ELXCOMPONENT name )
  # remove lib from link list
  IF( DEFINED AllComponentLibs )
    SET( dummy ${AllComponentLibs} )
	IF( NOT "${dummy}" STREQUAL "")
      LIST( REMOVE_ITEM dummy ${name} )
	ENDIF()
  ELSE()
    SET( dummy "" )
  ENDIF()
  SET( AllComponentLibs ${dummy} CACHE INTERNAL "All component libraries for elastix/transformix"  )
ENDMACRO( REMOVE_ELXCOMPONENT )

MACRO( ADD_ELXCOMPONENT name )

  # Compile this component or not
  SET( defaultValue ON )
  IF( ${ARGV1} STREQUAL "OFF" )
    SET( defaultValue OFF )
  ENDIF()
  MARK_AS_ADVANCED( USE_${name} )
  SET( USE_${name} ${defaultValue} CACHE BOOL "Compile this component")

  # If USE_ALL_COMPONENTS is turned ON, we make a backup of the
  # current value, and force the use_var to ON. If USE_ALL_COMPONENTS
  # is OFF, and there is a backup, set the use_var to the backed-up
  # value and remove the backup; otherwise, leave the use_var to its
  # current (default or user-specified) value.
  IF( USE_ALL_COMPONENTS )
    # make backup
    IF( NOT DEFINED USE_${name}_BACKUP )
      IF( USE_${name} )
        SET( USE_${name}_BACKUP ON CACHE INTERNAL "Backup of USE_var" FORCE )
      ELSE()
        SET( USE_${name}_BACKUP OFF CACHE INTERNAL "Backup of USE_var" FORCE )
      ENDIF()
    ENDIF()
    # turn use_var to on;
    SET( USE_${name} ON CACHE BOOL "Compile this component" FORCE )
  ELSE()
    # if there is a backup, set the use_var to the backed-up value
    # and remove the backup.
    IF( DEFINED USE_${name}_BACKUP )
      # this unset command is important; it makes sure the use_var is reset
      UNSET( USE_${name} CACHE )
      IF( USE_${name}_BACKUP )
        SET( USE_${name} ON CACHE BOOL "Compile this component")
      ELSE()
        SET( USE_${name} OFF CACHE BOOL "Compile this component")
      ENDIF()
      UNSET( USE_${name}_BACKUP CACHE )
    ENDIF()
  ENDIF()

  IF( USE_${name} )
    # Create the list of files which create the library
    SET( filelist ${ARGN} )
    LIST( REMOVE_ITEM filelist "ON" "OFF" )

    # Create project and library
    PROJECT( ${name} )
    ADD_LIBRARY( ${name} STATIC ${filelist} )
    TARGET_LINK_LIBRARIES( ${name} ${elxLinkLibs} )

    # Group in IDE's like Visual Studio
    STRING( REGEX MATCH "[a-zA-Z]+" comp_group ${relative_path_to_comp} )
    SET_PROPERTY( TARGET ${name} PROPERTY FOLDER ${comp_group} )

    # Update AllComponentLibs, while avoiding duplicates:
    IF( DEFINED AllComponentLibs )
      SET( dummy ${AllComponentLibs} )
			IF( NOT "${dummy}" STREQUAL "")
			  LIST( REMOVE_ITEM dummy ${name} )
			ENDIF()
      SET( dummy ${dummy} ${name} )
    ELSE()
      SET( dummy ${name} )
    ENDIF()
    SET( AllComponentLibs ${dummy} CACHE INTERNAL "All component libraries for elastix/transformix" )

    # Write lines to two files
    FILE( APPEND ${InstallFunctionDeclarationFile}
      "elxInstallComponentFunctionDeclarationMacro( " ${name} " );\n\n" )
    FILE( APPEND ${InstallFunctionCallFile}
      "elxInstallComponentFunctionCallMacro( " ${name} " );\n\n" )

  ELSE( USE_${name} )
    # Remove from link list
    REMOVE_ELXCOMPONENT( ${name} )
  ENDIF()

ENDMACRO( ADD_ELXCOMPONENT )

#---------------------------------------------------------------------
# Option to turn on all components by default
MARK_AS_ADVANCED( USE_ALL_COMPONENTS )
SET( USE_ALL_COMPONENTS OFF CACHE BOOL "Compile all components" )


#---------------------------------------------------------------------
# Search for all components in the elastix source directory
#

# Initialize the list of link libs.
SET( AllComponentLibs "" CACHE INTERNAL "All component libraries for elastix/transformix"  )

FILE( GLOB_RECURSE ListOfComponents "*/CMakeLists.txt" )

FOREACH( component ${ListOfComponents} )
  GET_FILENAME_COMPONENT( path_to_comp ${component} PATH )
  # Make the path relative to the elxComponents_SOURCE_DIR
  STRING( REGEX REPLACE "${elxComponents_SOURCE_DIR}/" "" relative_path_to_comp ${path_to_comp} )
  ADD_SUBDIRECTORY( ${relative_path_to_comp} )
ENDFOREACH()


#----------------------------------------------------------------------
# Search for user components
# These are components defined in external directories
# outside elastix, defined by the user.

FOREACH( userComponentDir ${ELASTIX_USER_COMPONENT_DIRS} )

  MESSAGE( STATUS "Searching for user components in: ${userComponentDir}" )
  FILE( GLOB_RECURSE listOfUserComponents "${userComponentDir}/CMakeLists.txt" )

  FOREACH( userComponent ${listOfUserComponents} )

    GET_FILENAME_COMPONENT( pathToComp ${userComponent} PATH )

    # read project name from cmakelists.txt
    MESSAGE( STATUS "Reading: ${userComponent}" )

    # Find the first line that has the following structure:
    # ADD_ELXCOMPONENT( projectname [....]
    # spaces before/after/inbetween are allowed.
    # ADD_ELXCOMPONENT does not have to be capitalized.
    # Commented lines (where the first nonwhite character is a #) are ignored.
    FILE( STRINGS ${userComponent} addElxComponentLine LIMIT_COUNT 1 REGEX
      "^[ \t]*[Aa][Dd][Dd]_[Ee][Ll][Xx][Cc][Oo][Mm][Pp][Oo][Nn][Ee][Nn][Tt][ \t]*[(][ \t]*[^ #\t()]+" )

    # Extract the projectname.
    STRING(REGEX REPLACE
      "^[ \t]*[Aa][Dd][Dd]_[Ee][Ll][Xx][Cc][Oo][Mm][Pp][Oo][Nn][Ee][Nn][Tt][ \t]*[(][ \t]*([^ #\t()]+).*"
      "\\1" componentName "${addElxComponentLine}")

		IF( NOT "${componentName}" STREQUAL "" )
      MESSAGE( STATUS "Found user component: ${componentName}" )

      # For non-subdirectories, the binarydir should be specified.
      # We use the name of the component for that.
      SET( binaryDir "${elastix_BINARY_DIR}/UserComponents/${componentName}" )

      # Add
  		ADD_SUBDIRECTORY( ${pathToComp} ${binaryDir} )

		ELSE()
      MESSAGE( STATUS "No user component definition found in: ${userComponent}" )
  	ENDIF()

  ENDFOREACH()
ENDFOREACH()

