#!/bin/bash

# Purpose {{{
# This script will download Clonezilla Stable installer for both AMD64 and i368
# and make a sample menu.cfg config file.
# }}}
# Vars {{{
readonly PROGNAME=$(basename "${0}")
readonly NBARGS="${#}"
[ -z "${DEBUG}" ] && DEBUG=1
## Export DEBUG for sub-script
export DEBUG

# Default value for TFTP's directory
if command -v in.tftpd > /dev/null; then
	source /etc/default/tftpd-hpa
else
	TFTP_DIRECTORY="/srv/tftp"
fi

CZ_INSTALLER_DIR="${TFTP_DIRECTORY}/installer/clonezilla"
CZ_CONFIG_PXE="${CZ_INSTALLER_DIR}/menu.cfg.example"
# Get latest version from https://clonezilla.org
CZ_VERSION_DEFAULT="$(curl --no-progress-meter https://clonezilla.org/downloads.php | sed --silent 's;.*<b>stable</b>.*<font.*>\(.*\)</font>.*;\1;p')"

## Colors
readonly PURPLE='\033[1;35m'
readonly RED='\033[0;31m'
readonly RESET='\033[0m'
readonly COLOR_DEBUG="${PURPLE}"
# }}}
usage() {                                                       # {{{

	cat <<- EOF
usage: $PROGNAME [-d|-h|-v]

This script will download Clonezilla Stable for both AMD64 and i368 architectures.

EXAMPLES :
    - Download Clonezilla's to default place (${TFTP_DIRECTORY}).
        ${PROGNAME}

    - Download a specific version of Clonezilla (default : ${CZ_VERSION_DEFAULT}).
        ${PROGNAME} --version "2.7.1"

OPTIONS :

    -v,--version
        Define the version of Clonezilla to download.

    -d,--debug
        Enable debug messages.

    -h,--help
        Print this help message.

EOF

}
# }}}
debug_message() {                                               # {{{

	local_message="${1}"

	## Print message if DEBUG is enable (=0)
	[ "${DEBUG}" -eq "0" ] && printf '\e[1;35m%-6b\e[m\n' "DEBUG − ${PROGNAME} : ${local_message}"

	return 0
}
# }}}
error_message() {                                               # {{{

	local_error_message="${1}"
	local_error_code="${2}"

	## Print message
	printf '%b\n' "ERROR − ${PROGNAME} : ${RED}${local_error_message}${RESET}"

	exit "${local_error_code:=66}"
}
# }}}
define_vars() {                                                 # {{{

	# If cz_version wasn't defined (argument) {{{
	if [ -z "${cz_version}" ]; then
		## Use default value
		cz_version="${CZ_VERSION_DEFAULT}"
	fi
	# }}}
}
# }}}

is_var_empty() {                                                # {{{

	## Return False by default
	return_var_empty="1"
	## Total number of variables to test
	local_total_var="${#}"

	loop_count_var_empty="0"

	## While it remains a variable to test
	while [ "${local_total_var}" -gt "${loop_count_var_empty}" ]; do
		debug_message "is_var_empty − \
Test var: ${1}."
		### Test if this is empty and set return value to True
		[ -z "${1}" ] && return_var_empty="0"

		### Increase the number of tested variables
		loop_count_var_empty=$((loop_count_var_empty+1))

		### Shift to the next variable
		shift
	done

	return "${return_var_empty}"

}
# }}}
is_file_absent() {                                              # {{{

	local_file_absent="${1}"

	## File exists by default
	return_is_file_absent="1"

	### Check if the file exists
	# shellcheck disable=SC2086
	if find ${local_file_absent} > /dev/null 2>&1; then
		return_is_file_absent="1"
		debug_message "is_file_absent − \
The file ${RED}${local_file_absent}${COLOR_DEBUG} exists."
	else
		return_is_file_absent="0"
		debug_message "is_file_absent − \
The file ${RED}${local_file_absent}${COLOR_DEBUG} doesn't exist."
	fi

	return "${return_is_file_absent}"

}
# }}}
download_file() {                                               # {{{

	local_url="${1}"
	local_dest_file="${2}"

	debug_message "download_file − \
Download ${local_url} to ${RED}${local_dest_file}${COLOR_DEBUG} ."

	wget --quiet "${local_url}" --output-document="${local_dest_file}"

	## Unset variables
	unset local_url
	unset local_dest_file
}
# }}}
is_file_empty() {                                               # {{{

	local_file="${1}"

	## File is empty by default
	return_is_file_empty="0"

	### Check if the file is empty
	if [ ! -s "${local_file}" ]; then
		return_is_file_empty="0"
		debug_message "is_file_empty − \
The file ${RED}${local_file}${COLOR_DEBUG} is empty or doesn't exists."
	else
		return_is_file_empty="1"
		debug_message "is_file_empty − \
The file ${RED}${local_file}${COLOR_DEBUG} exists and has a size greater than zero."
	fi

	## Unset variables
	unset local_file

	return "${return_is_file_empty}"
}
# }}}

main() {                                                        # {{{

	# Define all vars
	define_vars

	# If cz_version is empty {{{
	# Exit with error
	is_var_empty "${cz_version}" \
		&& error_message "Clonezilla version variable is empty" 6
	# }}}

	# Create directories and config file
	debug_message "Main − \
Create ${CZ_INSTALLER_DIR} tree."
	mkdir --parents -- "${CZ_INSTALLER_DIR}" \
			|| error_message "Can't create ${CZ_INSTALLER_DIR}/ directory." 1
	true > "${CZ_CONFIG_PXE}"

	for ARCH in amd64 i686; do # For available classic architectures
		#CZ_URL="https://osdn.jp/dl/clonezilla/clonezilla-live-${cz_version}-${ARCH}.zip"
		CZ_URL="https://sourceforge.net/projects/clonezilla/files/clonezilla_live_stable/${cz_version}/clonezilla-live-${cz_version}-${ARCH}.zip/download"
		CZ_TEMP_FILE="/tmp/clonezilla-live-${cz_version}-${ARCH}.zip"

		## If this version is not already present on the system
		if is_file_absent "${CZ_INSTALLER_DIR}/${ARCH}/${cz_version}"; then
			### Recreate directory and go
			rm --recursive --force -- "${CZ_INSTALLER_DIR}/${ARCH}"
			mkdir --parents -- "${CZ_INSTALLER_DIR}/${ARCH}" \
				|| error_message "Can't create ${CZ_INSTALLER_DIR}/${ARCH}/ directory." 1
			pushd "${CZ_INSTALLER_DIR}/${ARCH}" > /dev/null \
				|| error_message "Can't move to ${CZ_INSTALLER_DIR}/${ARCH} temp directory." 2

			### Download and extract only PXE files {{{
			download_file "${CZ_URL}" "${CZ_TEMP_FILE}"
			is_file_empty "${CZ_TEMP_FILE}" \
				&& error_message "${CZ_TEMP_FILE} is empty." 3
			debug_message "FOR loop − ${ARCH} − \
Uncompress PXE files from ${CZ_TEMP_FILE} ."
			unzip -qq -j "${CZ_TEMP_FILE}" live/vmlinuz live/initrd.img live/filesystem.squashfs -d . \
				|| error_message "Can't properly extract ${CZ_TEMP_FILE} archive."
			### }}}

			### Remove temp file
			rm --force -- "${CZ_TEMP_FILE}" \
				|| error_message "Can't remove ${CZ_TEMP_FILE} temp file."

			### Add flag file to know that this version is available
			true > "${CZ_INSTALLER_DIR}/${ARCH}/${cz_version}"

			popd > /dev/null \
				|| error_message "Can't move back from ${CZ_INSTALLER_DIR}/${ARCH}/ directory." 2
		fi

		## Add informations to sample config file
		/bin/cat >> "${CZ_CONFIG_PXE}" << EOF
	label live${ARCH}
		menu label Clonezilla Live ^${ARCH}
		kernel installer/clonezilla/${ARCH}/vmlinuz
		APPEND initrd=installer/clonezilla/${ARCH}/initrd.img boot=live username=user union=overlay config components quiet noswap edd=on nomodeset nodmraid locales= keyboard-layouts= ocs_live_run="ocs-live-general" ocs_live_extra_param="" ocs_live_batch=no net.ifnames=0 nosplash noprompt fetch=tftp://129.20.203.27/installer/clonezilla/${ARCH}/filesystem.squashfs
EOF

	done

	# Add separator and menu to sample config file
	/bin/cat >> "${CZ_CONFIG_PXE}" << EOF
	label separator
		menu label -----
	label mainmenu
		menu label ^Back..
		menu exit
EOF

}
# }}}

# Manage arguments                                                # {{{
# This code can't be in a function due to argument management

if [ ! "${NBARGS}" -eq "0" ]; then

	manage_arg="0"

	## If the first argument is not an option
	if ! printf -- '%s' "${1}" | grep -q -E -- "^-+";
	then
		## Print help message and exit
		printf '%b\n' "${RED}Invalid option: ${1}${RESET}"
		printf '%b\n' "---"
		usage

		exit 1
	fi

	# Parse all options (start with a "-") one by one
	while printf -- '%s' "${1}" | grep -q -E -- "^-+"; do

	case "${1}" in
		-v|--version )                        ## Define cz_version
			## Move to the next argument
			shift
			## Define var
			readonly cz_version="${1}"
			;;
		-d|--debug )                          ## debug
			DEBUG=0
			;;
		-h|--help )                           ## help
			usage
			## Exit after help informations
			exit 0
			;;
		* )                                   ## unknow option
			printf '%b\n' "${RED}Invalid option: ${1}${RESET}"
			printf '%b\n' "---"
			usage
			exit 1
			;;
	esac

	debug_message "Arguments management − \
${RED}${1}${COLOR_DEBUG} option managed."

	## Move to the next argument
	shift
	manage_arg=$((manage_arg+1))

	done

	debug_message "Arguments management − \
${RED}${manage_arg}${COLOR_DEBUG} argument(s) successfully managed."
else
	debug_message "Arguments management − \
No arguments/options to manage."
fi

# }}}

main

exit 0
