cmake_minimum_required(VERSION 2.8.5)

set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/modules)
set(CMAKE_TOOLCHAIN_FILE ${CMAKE_SOURCE_DIR}/cmake/toolchains/Arduino.cmake)

# modify flags from default toolchain flags
set(APM_OPT_FLAGS "-Wformat -Wall -Wshadow -Wpointer-arith -Wcast-align -Wwrite-strings -Wformat=2")

set(ARDUINO_C_FLAGS "${APM_OPT_FLAGS} -mcall-prologues -ffunction-sections -fdata-sections")
set(ARDUINO_CXX_FLAGS "${APM_OPT_FLAGS} -mcall-prologues -ffunction-sections -fdata-sections -fno-exceptions -Wno-reorder")
set(ARDUINO_LINKER_FLAGS "-lc -lm ${APM_OPT_FLAGS} -Wl,--gc-sections")

project(ArduPilotMega C CXX)

# set default cmake build type to RelWithDebInfo (None Debug Release RelWithDebInfo MinSizeRel)
if( NOT DEFINED CMAKE_BUILD_TYPE )
	set( CMAKE_BUILD_TYPE "RelWithDebInfo" )
endif()

# set these for release
set(APPLICATION_VERSION_MAJOR "1")
set(APPLICATION_VERSION_MINOR "2")
set(APPLICATION_VERSION_PATCH "0")

# dependencies
find_package(Arduino 22 REQUIRED)

# cmake settigns
set(APPLICATION_NAME ${PROJECT_NAME})
set(APPLICATION_VERSION "${APPLICATION_VERSION_MAJOR}.${APPLICATION_VERSION_MINOR}.${APPLICATION_VERSION_PATCH}")

# macros
include(MacroEnsureOutOfSourceBuild)
#include(UseDoxygen)

# disallow in-source build
macro_ensure_out_of_source_build("${PROJECT_NAME} requires an out of source build.
Please create a separate build directory and run 'cmake /path/to/${PROJECT_NAME} [options]' there.")

# options
if (NOT DEFINED BOARD)
	message(STATUS "please define the board type (for example: cmake -DBOARD=mega, assuming mega2560")
	set(BOARD "mega2560")
endif()

if (NOT DEFINED PORT)
	message(STATUS "please define the upload port (for example: cmake
	-DPORT=/dev/ttyUSB0, assuming /dev/ttyUSB0")
	set(PORT "/dev/ttyUSB0")
endif()

# cpack settings
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "A universal autopilot system for the ArduPilotMega board.")
set(CPACK_PACKAGE_VENDOR "DIYDRONES")
set(CPACK_DEBIAN_PACKAGE_MAINTAINER "james.goppert@gmail.com")
set(CPACK_PACKAGE_CONTACT "james.goppert@gmail.com")
set(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_SOURCE_DIR}/README.txt")
set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_SOURCE_DIR}/COPYING.txt")
set(CPACK_RESOURCE_FILE_README "${CMAKE_SOURCE_DIR}/README.txt")
set(CPACK_PACKAGE_VERSION_MAJOR "${APPLICATION_VERSION_MAJOR}")
set(CPACK_PACKAGE_VERSION_MINOR "${APPLICATION_VERSION_MINOR}")
set(CPACK_PACKAGE_VERSION_PATCH "${APPLICATION_VERSION_PATCH}")
set(CPACK_PACKAGE_INSTALL_DIRECTORY "CMake ${CMake_VERSION_MAJOR}.${CMake_VERSION_MINOR}")
set(CPACK_SET_DESTDIR TRUE)
set(CPACK_SOURCE_IGNORE_FILES ${CPACK_SOURCE_IGNORE_FILES}
	/.git/;/build/;~$;.*\\\\.bin$;.*\\\\.swp$)
set(CPACK_INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}")
set(CPACK_SOURCE_GENERATOR "ZIP")
set(CPACK_GENERATOR "ZIP")
set(CPACK_PACKAGE_NAME "${APPLICATION_NAME}_${BOARD}")
include(CPack)

find_package(Arduino 22 REQUIRED)

# determine board being used
if (NOT DEFINED BOARD)
	message(STATUS "board not defined, assuming mega, use cmake -DBOARD=mega2560 , etc. to specify")
	set(BOARD "mega")
endif()
message(STATUS "Board configured as: ${BOARD}")

# add a sketch
macro(add_sketch SKETCH_NAME BOARD PORT) 

	message(STATUS "Generating sketch ${SKETCH_NAME}")

	# files
	set(SKETCH_CPP ${CMAKE_CURRENT_BINARY_DIR}/${SKETCH_NAME}/${SKETCH_NAME}.cpp)
	set(SKETCH_PDE ${CMAKE_CURRENT_SOURCE_DIR}/${SKETCH_NAME}/${SKETCH_NAME}.pde)
    #message(STATUS "SKETCH_PDE:\n${SKETCH_PDE}")
    #message(STATUS "SKETCH_CPP:\n${SKETCH_CPP}")

	# settings
	set(${SKETCH_NAME}_BOARD ${BOARD})
	set(${SKETCH_NAME}_PORT ${PORT})
	set(${SKETCH_NAME}_SRCS ${SKETCH_CPP})
	set(${SKETCH_NAME}_LIBS m c)

	# find pde files
	file(GLOB PDE_SOURCES ${SKETCH_NAME}/*.pde)
	
	# find the head of the main pde
	file(WRITE ${SKETCH_CPP} "// automatically generated by arduino-cmake\n")
	file(READ ${SKETCH_PDE} FILE)

	string(FIND "${FILE}" "#include" POS1 REVERSE)
	string(LENGTH "${FILE}" FILE_LENGTH)
	math(EXPR LENGTH_STR1 "${FILE_LENGTH}-${POS1}")
	string(SUBSTRING "${FILE}" ${POS1} ${LENGTH_STR1} STR1)
	string(FIND "${STR1}" "\n" POS2)
	math(EXPR POS3 "${POS1}+${POS2}")
	string(SUBSTRING "${FILE}" 0 ${POS3} FILE_HEAD)
    #message(STATUS "FILE_HEAD:\n${FILE_HEAD}")

	# find the body of the main pde
	math(EXPR BODY_LENGTH "${FILE_LENGTH}-${POS3}-1")
	string(SUBSTRING "${FILE}" "${POS3}+1" "${BODY_LENGTH}" FILE_BODY)
    #message(STATUS "BODY:\n${FILE_BODY}")

	# write the file head
	file(APPEND ${SKETCH_CPP} "${FILE_HEAD}")
	file(APPEND ${SKETCH_CPP} "\n#include \"WProgram.h\"\n")

	# write prototypes
	foreach(PDE ${PDE_SOURCES})
        #message(STATUS "pde: ${PDE}")
		file(READ ${PDE} FILE)
		string(REGEX MATCHALL "[\n]([a-zA-Z]+[ ])*[_a-zA-Z0-9]+([ ]*[\n][\t]*|[ ])[_a-zA-Z0-9]+[ ]?[\n]?[\t]*[ ]*[(]([\t]*[ ]*[*]?[ ]?[a-zA-Z0-9_][,]?[ ]*[\n]?)*[)]" PROTOTYPES ${FILE})
		foreach(PROTOTYPE ${PROTOTYPES})	
            #message(STATUS "\tprototype: ${PROTOTYPE};")
			file(APPEND ${SKETCH_CPP} "${PROTOTYPE};")
		endforeach()
	endforeach()

	
	# write source
	file(APPEND ${SKETCH_CPP} "\n${FILE_BODY}")
	list(REMOVE_ITEM PDE_SOURCES ${SKETCH_PDE})
	list(SORT PDE_SOURCES)
	foreach (PDE ${PDE_SOURCES})
		file(READ ${PDE} FILE)
		file(APPEND ${SKETCH_CPP} "${FILE}")
	endforeach()

	# generate firmware
	include_directories(${CMAKE_CURRENT_SOURCE_DIR}/${SKETCH_NAME})
	generate_arduino_firmware(${SKETCH_NAME})
	set_target_properties(${SKETCH_NAME} PROPERTIES LINKER_LANGUAGE CXX)

	# install settings
	install(FILES
		${CMAKE_CURRENT_BINARY_DIR}/${SKETCH_NAME}.hex 
		DESTINATION bin
	)
endmacro()

# projects
add_sketch(apo ${BOARD} ${PORT})
add_sketch(ArduRover ${BOARD} ${PORT})
add_sketch(ArduBoat ${BOARD} ${PORT})
#add_sketch(ArduPlane ${BOARD} ${PORT})
#add_sketch(ArduCopter ${BOARD} ${PORT})