## pragma once
if(_DOWNLOAD_AND_EXTRACT_ZIP_FILE_CMAKE_INCLUDED_)
  return()
endif()
set(_DOWNLOAD_AND_EXTRACT_ZIP_FILE_CMAKE_INCLUDED_ true)

cmake_minimum_required(VERSION 2.8)

## CMAKE_DOCUMENTATION_START downloadAndExtractZipFile
##
## Provide a way to download zip file from public internet ZIP_URL host
## and to extract it in a specific EXCTRATED_ZIP_PATH destination. \\n
## This function use 7-Zip external tool to maximize the compatibles formats.\\n
## This will be not download again if the EXCTRATED_ZIP_PATH already exist and DL_FORCE is set to OFF.\\n
## This will try to unzip file if already exist in the ZIP_DL_PATH.\\n
## \\n
## If EXCTRATED_ZIP_PATH and/or ZIP_DL_PATH are not full path,
## it will be interpreted relative to CMAKE_BINARY_DIR \\n
## \\n
## Usage example : 
## \\code
## include(downloadAndExtractZipFile) 											\n
## downloadAndExtractZipFile( 													\n
## 	http://www.cs.cornell.edu/~snavely/bundler/distr/bundler-v0.4-source.zip	\n
## 	${CMAKE_BINARY_DIR}/Bundler/bundler-v0.4-source.zip							\n
## 	${CMAKE_BINARY_DIR}/Bundler													\n
##  [DL_FORCE ON|OFF]															\n
##  [TIMEOUT]																	\n
##  [CHECK_DIRTY_URL]															\n
## )
## \\code
## \\n
## option DL_FORCE will redownload the zip file [deafult to OFF] 							\\n
## option TIMEOUT will end the unzip process after this period of time [default to 600s]	\\n
## option CHECK_DIRTY_URL will write into the given file the downloaded URL and then, 		\\n
## next time, if the URL was updated, it detect it with this file 							\\n
## and will download the last version. This prevent to alway set manually DL_FORCE to ON...	\\n
## \\n
## Created/updated by jesnault while last cmake version was 3.0.2
##
## CMAKE_DOCUMENTATION_END
if(NOT WIN32 OR __downloadAndExtractZipFile_cmake_INCLUDED__)
	return()
else()
	set(__downloadAndExtractZipFile_cmake_INCLUDED__ ON)
endif()

function(downloadAndExtractZipFile ZIP_URL ZIP_DL_PATH EXCTRATED_ZIP_PATH)
    
	include(CMakeParseArguments)
    cmake_parse_arguments(dwnlezf "" "VERBOSE;DL_FORCE;TIMEOUT;CHECK_DIRTY_URL" "" ${ARGN})
	
	set(PROGRAMFILESx86 "PROGRAMFILES(x86)")   
    
    ## Check entries mandatory args
    if(IS_ABSOLUTE "${ZIP_DL_PATH}")
    else()
        set(ZIP_DL_PATH "${CMAKE_BINARY_DIR}/${ZIP_DL_PATH}")
    endif()
    if(IS_ABSOLUTE "${EXCTRATED_ZIP_PATH}")
    else()
        set(EXCTRATED_ZIP_PATH "${CMAKE_BINARY_DIR}/${EXCTRATED_ZIP_PATH}")
    endif()
    if(NOT EXISTS "${EXCTRATED_ZIP_PATH}")
        file(MAKE_DIRECTORY ${EXCTRATED_ZIP_PATH})
    endif()
	
    ## Check entries optional args
	macro(readDirtyUrl )
		if(dwnlezf_CHECK_DIRTY_URL)
			if(IS_ABSOLUTE "${dwnlezf_CHECK_DIRTY_URL}")
			else()
				set(dwnlezf_CHECK_DIRTY_URL "${CMAKE_BINARY_DIR}/${dwnlezf_CHECK_DIRTY_URL}")
			endif()
			get_filename_component(unzipDir 	${EXCTRATED_ZIP_PATH} NAME)
			get_filename_component(unzipPath 	${EXCTRATED_ZIP_PATH} PATH)
			message(STATUS "Checking ${unzipDir} [from ${unzipPath}]...")			
			if(EXISTS "${dwnlezf_CHECK_DIRTY_URL}")
				get_filename_component(CHECK_DIRTY_URL_FILENAME ${dwnlezf_CHECK_DIRTY_URL} NAME)
				file(STRINGS "${dwnlezf_CHECK_DIRTY_URL}" contents)
				list(GET contents 0 downloadURL)
				list(REMOVE_AT contents 0)
				if("${downloadURL}" MATCHES "${ZIP_URL}")
					if(dwnlezf_VERBOSE)
						message(STATUS "Your downloaded version (URL) seems to be up to date. Let me check if nothing is missing... (see ${dwnlezf_CHECK_DIRTY_URL}).")
					endif()
					file(GLOB PATHNAME_PATTERN_LIST "${EXCTRATED_ZIP_PATH}/*") ## is there something inside the downloaded destination ?
					unset(NAME_PATTERN_LIST)
					foreach(realPathPattern ${PATHNAME_PATTERN_LIST})
						get_filename_component(itemName ${realPathPattern} NAME)
						list(APPEND NAME_PATTERN_LIST ${itemName})
					endforeach()
					if(NAME_PATTERN_LIST)
						foreach(item ${contents})
							list(FIND NAME_PATTERN_LIST ${item} id)
							if(${id} MATCHES "-1")
								message(STATUS "${item} is missing, your downloaded version content changed, need to redownload it.")
								set(ZIP_DL_FORCE ON)
								break()
							else()
								list(REMOVE_AT NAME_PATTERN_LIST ${id})
								set(ZIP_DL_FORCE OFF)
							endif()
						endforeach()
						if(NOT ZIP_DL_FORCE AND NAME_PATTERN_LIST)
							message("You'r seems to be up to date (regarding to ${CHECK_DIRTY_URL_FILENAME})!\nBut there are additional files/folders into your downloaded destination (feel free to clean it if you want).")
							foreach(item ${NAME_PATTERN_LIST})
								if(item)
									message("${item}")
								endif()
							endforeach()
						endif()
					endif()
				else()
					set(ZIP_DL_FORCE ON)
					message(STATUS "Your downloaded version is dirty (too old).")
				endif()
			else()
				file(GLOB PATHNAME_PATTERN_LIST "${EXCTRATED_ZIP_PATH}/*") ## is there something inside the downloaded destination ?
				if(NOT PATHNAME_PATTERN_LIST)
					message("We found nothing into ${EXCTRATED_ZIP_PATH}, we will try to download it for you now.")
				endif()
				set(ZIP_DL_FORCE ON)
			endif()
		endif()
	endmacro()
	readDirtyUrl()
	if(NOT ZIP_DL_FORCE)
		return() ## do not need to further (as we are up to date, just exit the function
	endif()

	macro(writeDirtyUrl )
		if(dwnlezf_CHECK_DIRTY_URL)
			file(WRITE "${dwnlezf_CHECK_DIRTY_URL}" "${ZIP_URL}\n")
			file(GLOB PATHNAME_PATTERN_LIST "${EXCTRATED_ZIP_PATH}/*") ## is there something inside the downloaded destination ?
			unset(NAME_PATTERN_LIST)
			foreach(realPathPattern ${PATHNAME_PATTERN_LIST})
				get_filename_component(itemName ${realPathPattern} NAME)
				list(APPEND NAME_PATTERN_LIST ${itemName})
			endforeach()
			if(NAME_PATTERN_LIST)
				foreach(item ${NAME_PATTERN_LIST})
					file(APPEND "${dwnlezf_CHECK_DIRTY_URL}" "${item}\n")
				endforeach()
			endif()
		endif()
	endmacro()
	
	if(dwnlezf_DL_FORCE)
        set(ZIP_DL_FORCE ON)
    endif()
	
	if(NOT dwnlezf_TIMEOUT)
		set(dwnlezf_TIMEOUT 600)
	endif()
	math(EXPR dwnlezf_TIMEOUT_MIN "${dwnlezf_TIMEOUT}/60")
	
	macro(unzip whichZipFile)
		if(NOT SEVEN_ZIP_CMD)
			find_program(SEVEN_ZIP_CMD NAMES 7z 7za p7zip DOC "7-zip executable" PATHS "$ENV{PROGRAMFILES}/7-Zip" "$ENV{${PROGRAMFILESx86}}/7-Zip" "$ENV{ProgramW6432}/7-Zip")
		endif()
		if(SEVEN_ZIP_CMD)
            if(dwnlezf_VERBOSE)
                message(STATUS "UNZIP: please, WAIT UNTIL ${SEVEN_ZIP_CMD} finished...\n(no more than ${dwnlezf_TIMEOUT_MIN} min)")
            else()
                message(STATUS "UNZIP...wait...")
            endif()
			execute_process( 	COMMAND ${SEVEN_ZIP_CMD} x ${whichZipFile} -y
								WORKING_DIRECTORY ${EXCTRATED_ZIP_PATH}	TIMEOUT ${dwnlezf_TIMEOUT}
								RESULT_VARIABLE resVar OUTPUT_VARIABLE outVar ERROR_VARIABLE errVar
							)
			if(${resVar} MATCHES "0")
                if(dwnlezf_VERBOSE)
                    message(STATUS "SUCESS to unzip in ${EXCTRATED_ZIP_PATH}. Now we can remove the downloaded zip file.")
                endif()
				execute_process(COMMAND ${CMAKE_COMMAND} -E remove ${whichZipFile})
				mark_as_advanced(SEVEN_ZIP_CMD)
			else()
				message(WARNING "something wrong in ${EXCTRATED_ZIP_PATH}\n with \"${SEVEN_ZIP_CMD} x ${whichZipFile} -y\", redo or try to unzip by yourself...")
				message("unzip: resVar=${resVar}")
				message("unzip: outVar=${outVar}")
				message("unzip: errVar=${errVar}")
				message("unzip: failed or canceled or timeout")
			endif()
		else()
			message(WARNING "You need 7zip (http://www.7-zip.org/download.html) to unzip the downloaded dir.")
			set(SEVEN_ZIP_CMD "" CACHE FILEPATH "7-zip executable")
			mark_as_advanced(CLEAR SEVEN_ZIP_CMD)
		endif()
	endmacro()

    if(dwnlezf_VERBOSE)
        message(STATUS "Trying to look ${ZIP_DL_PATH} if a zip file exist...")
    endif()
	if(EXISTS "${ZIP_DL_PATH}")

		## already downloaded, so just unzip it
		unzip(${ZIP_DL_PATH})
		writeDirtyUrl()

	elseif(ZIP_DL_FORCE)

		## the download part (+ unzip)
		message(STATUS "Let me try to download package for you : ${ZIP_URL}")
        if(dwnlezf_VERBOSE)
            message(STATUS "Downloading...\n   SRC=${ZIP_URL}\n   DEST=${ZIP_DL_PATH}.tmp\n   INACTIVITY_TIMEOUT=180s")
        endif()
		file(DOWNLOAD ${ZIP_URL} ${ZIP_DL_PATH}.tmp INACTIVITY_TIMEOUT 180 STATUS status SHOW_PROGRESS)

		list(GET status 0 numResult)
		if(${numResult} MATCHES "0")

            if(dwnlezf_VERBOSE)
                message(STATUS "Download succeed, so let me rename the tmp file to unzip it")
            endif()
			execute_process(COMMAND ${CMAKE_COMMAND} -E rename ${ZIP_DL_PATH}.tmp ${ZIP_DL_PATH})
			unzip(${ZIP_DL_PATH})
			writeDirtyUrl()
		
		else()

			list(GET status 1 errMsg)
			message(WARNING "DOWNLOAD ${ZIP_URL} to ${ZIP_DL_PATH} failed\n:${errMsg}")
			message(WARNING "OK, you need to download the ${ZIP_URL} manually and put it into ${ZIP_DL_PATH}")
			message("Take a look at the project website page to check available URL.")
		
		endif()

	endif()

	## clean up the tmp downloaded file
	if(EXISTS "${ZIP_DL_PATH}.tmp")
		execute_process(COMMAND ${CMAKE_COMMAND} -E remove ${ZIP_DL_PATH}.tmp)
	endif()

endfunction()
