include(${CMAKE_CURRENT_LIST_DIR}/CMake_coverage.txt)

##############################################################################################
# antlr4 settings
##############################################################################################
# there are two types of distribution the all in one antlr4-complete.jar or group of antrl4 jars
find_jar(_ANTLR_JAR_LOCATION_antlr4_complete "antlr4-complete"
	PATHS "/usr/share/java/antlr4-complete.jar"
		  "antlr4-complete.jar" ENV ANTLR_COMPLETE_PATH)
if(_ANTLR_JAR_LOCATION_antlr4_complete)
	MESSAGE(STATUS "using antlr4-complete.jar found in ${_ANTLR_JAR_LOCATION_antlr4_complete}")
	set(ANTLR_CLASSPATH "${_ANTLR_JAR_LOCATION_antlr4_complete}")
else()
	set(ANTLR_CLASSPATH "")
	set(ANTLR_JARS "stringtemplate4;antlr4;antlr4-runtime;antlr3-runtime;treelayout")
	FOREACH(antlr_jar ${ANTLR_JARS})
	  find_jar(_ANTLR_JAR_LOCATION_${antlr_jar} "${antlr_jar}"
	  		PATHS "/usr/share/java/${antlr_jar}.jar")
	  set(_ANTLR_JAR_LOCATION ${_ANTLR_JAR_LOCATION_${antlr_jar}})
	  if (NOT _ANTLR_JAR_LOCATION)
	    MESSAGE(FATAL_ERROR "ANTLR: Can not find ${antlr_jar} jar from ANTLR installation")
	  else()
		MESSAGE(STATUS "ANTLR: using ${antlr_jar} jar found in ${_ANTLR_JAR_LOCATION}")
	  endif()
	  if(ANTLR_CLASSPATH)
	  	set(ANTLR_CLASSPATH "${ANTLR_CLASSPATH}:${_ANTLR_JAR_LOCATION}")
	  else()
	  	set(ANTLR_CLASSPATH "${_ANTLR_JAR_LOCATION}")
	  endif()
	ENDFOREACH()
endif()

# search for antlr4 include dir and library
if(ANTLR4CPP_ROOT)
	MESSAGE(STATUS "Antlr4 cpp runtime root set to: ${ANTLR4CPP_ROOT}")
endif()
find_path(ANTLR4CPP_INCLUDE_DIRS antlr4-runtime.h
	HINTS "${ANTLR4CPP_ROOT}/usr/include/antlr4-runtime/"
	      "${ANTLR4CPP_ROOT}/include/antlr4-runtime/"
    PATH_SUFFIXES antlr4-runtime)
if(NOT ANTLR4CPP_INCLUDE_DIRS)
	MESSAGE(FATAL_ERROR "Can not find ANTLR4CPP_INCLUDE_DIRS")
else()
	MESSAGE(STATUS "ANTLR4CPP_INCLUDE_DIRS=${ANTLR4CPP_INCLUDE_DIRS}")
endif()
include_directories(${ANTLR4CPP_INCLUDE_DIRS})

# [todo] rather explicitly specify static/dynamic antlr linking
find_library(ANTLR4CPP_LIBRARIES 
	libantlr4-runtime.dll libantlr4-runtime.so
	libantlr4-runtime.a libantlr4-runtime.dylib
	antlr4-runtime-static.lib
	HINTS "${ANTLR4CPP_ROOT}/usr/lib"
	      "${ANTLR4CPP_ROOT}/lib")

if(NOT ANTLR4CPP_LIBRARIES)
	MESSAGE(FATAL_ERROR "Can not find ANTLR4CPP_LIBRARIES")
else()
	MESSAGE(STATUS "ANTLR4CPP_LIBRARIES=${ANTLR4CPP_LIBRARIES}")
endif()

if(CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
	add_compile_definitions(ANTLR4CPP_STATIC)
endif()

##############################################################################################
# antlr4 utils
##############################################################################################

set(PARSER_GEN_ONLY_VISITOR "-visitor" "-no-listener")
set(PARSER_GEN_ONLY_LISTENER "-listener" "-no-visitor")
set(PARSER_GEN_VISITOR "-visitor")

# @attention this project dependent constants
set(ANTLR_GRAMMAR_ROOT "${PROJECT_SOURCE_DIR}/grammars")
set(PROJECT_INCLUDE_ROOT "${PROJECT_SOURCE_DIR}/include/hdlConvertor")


# https://samthursfield.wordpress.com/2015/11/21/cmake-dependencies-between-targets-and-files-and-custom-commands/
#https://stackoverflow.com/questions/7862300/how-to-make-cmake-target-executed-whether-specified-file-was-changed
macro(AddParserToBuild name folder_name
	generate_visitor generate_listener lexer_parser_separate)
	# @param name the name of the parser grammar and parser itself
	# @param folder_name name of folder where convertor is stored
	#	(which is using this parser)
	# @param lexer_parser_separate if ON the ${name}Lexer.g4 ${name}Parser.g4 is used otherwise just ${name}.g4
	set(GENERATED_SRC
		${CMAKE_CURRENT_SOURCE_DIR}/${name}Parser/${name}Lexer.cpp
		${CMAKE_CURRENT_SOURCE_DIR}/${name}Parser/${name}Parser.cpp
	)
	if(CMAKE_SYSTEM_NAME MATCHES "Linux")
		#Suppress warnings on generated code.
		set_property(SOURCE ${GENERATED_SRC} PROPERTY
			COMPILE_FLAGS -Wno-unused-parameter)
	endif()
	
	# @attention PROJECT_INCLUDE_ROOT depends on project name and has to be updated for other projects
	set(GEN_INC_DIR
		${PROJECT_INCLUDE_ROOT}/${folder_name}/${name}Parser)
	set(GENERATED_INC
		${GEN_INC_DIR}/${name}Lexer.h
		${GEN_INC_DIR}/${name}Parser.h
	)

	# explicitely named all header files which are generated by ANTLR
	set(ORIG_GENERATED_INC
		${CMAKE_CURRENT_SOURCE_DIR}/${name}Parser/${name}Lexer.h
		${CMAKE_CURRENT_SOURCE_DIR}/${name}Parser/${name}Parser.h
	)

	set(ANTLR_GEN_ARGS)
	if (${generate_visitor})
		list(APPEND ANTLR_GEN_ARGS "-visitor")
		list(APPEND ORIG_GENERATED_INC
			${CMAKE_CURRENT_SOURCE_DIR}/${name}Parser/${name}ParserBaseVisitor.h
			${CMAKE_CURRENT_SOURCE_DIR}/${name}Parser/${name}ParserVisitor.h
		)
	else()
	    list(APPEND ANTLR_GEN_ARGS "-no-visitor")
	endif()
	if (${generate_listener})
		list(APPEND ANTLR_GEN_ARGS "-listener")
		list(APPEND ORIG_GENERATED_INC
			${CMAKE_CURRENT_SOURCE_DIR}/${name}Parser/${name}ParserBaseListener.h
			${CMAKE_CURRENT_SOURCE_DIR}/${name}Parser/${name}ParserListener.h
		)
	else()
	 	list(APPEND ANTLR_GEN_ARGS "-no-listener")
	endif()

	set(PARSER_SRC_DIR ${CMAKE_CURRENT_SOURCE_DIR}/${name}Parser)

	# delete generated files on clean
	set_property(DIRECTORY PROPERTY ADDITIONAL_MAKE_CLEAN_FILES
	   "${CMAKE_CURRENT_SOURCE_DIR}/${name}Parser"
	   "${GEN_INC_DIR}")

	if(${lexer_parser_separate})
		set(GRAMMARS
			${ANTLR_GRAMMAR_ROOT}/${name}Lexer.g4
        	${ANTLR_GRAMMAR_ROOT}/${name}Parser.g4)
	else()
		set(GRAMMARS
			${ANTLR_GRAMMAR_ROOT}/${name}.g4)
	endif()

	# create source directory
	# create include directory
	# run antlr to generate parser
	# mv headers to include directory
	add_custom_command(
		OUTPUT
		${GENERATED_INC} ${GENERATED_SRC}
		COMMAND
		${CMAKE_COMMAND} -E make_directory ${PARSER_SRC_DIR}
		COMMAND
		${CMAKE_COMMAND} -E make_directory ${GEN_INC_DIR}
		COMMAND
		"${Java_JAVA_EXECUTABLE}" -cp "${ANTLR_CLASSPATH}" "org.antlr.v4.Tool"
		-Dlanguage=Cpp ${ANTLR_GEN_ARGS} -package ${name}_antlr -encoding utf-8
		-o ${CMAKE_CURRENT_SOURCE_DIR}/${name}Parser
		${GRAMMARS}
		COMMAND
		${CMAKE_COMMAND} -E copy ${ORIG_GENERATED_INC} ${GEN_INC_DIR}
		DEPENDS ${GRAMMARS}
		COMMENT "generating sources for ${name}Parser"
	)

	file(GLOB SRC
	     "${CMAKE_CURRENT_SOURCE_DIR}/*.cpp"
	)

	add_library(${folder_name}_static STATIC
		${SRC}
	  	${GENERATED_SRC}
	  	${GENERATED_INC})
	set_coverage_if_enabled(${folder_name}_static ON)

	if(NOT HDLCONVERTOR_PYTHON)
		# we do not want to install headers if we are building python module
		set_target_properties(${folder_name}_static
		    PROPERTIES PUBLIC_HEADER "${GENERATED_INC}")
	endif()
				
	set_target_properties(${folder_name}_static
		PROPERTIES VERSION "1.0.0"
		OUTPUT_NAME ${folder_name}
		POSITION_INDEPENDENT_CODE ON
	)
endmacro()
