#!/bin/bash

declare -A options=(
	[help]=0	[nocolor]=0	[tests]=0
	[version]=0	[pdf]=0		[demo]=0
	[msg]=0		[tar]=0		[ebuild]=0
	[rpm]=0		[deb]=0		[windows]=0
	[clear]=0	[inno]=0	[arch]=0
	[freeBSD]=0	[readme]=0
)
declare -A COLOR=(
	[none]=""		[reg]=""		[green]=""
	[yellow]=""		[blue]=""		[purple]=""
	[purple]=""		[bold]=""
)
declare ide_version="0.0"
declare -a version
declare results=
declare cur_func="main"
declare nc_opt_long
declare nc_opt_short
declare SOURCE_DIR
declare PKG_DIR
declare WORK_DIR
declare SCRIPT_NAME

function basic_tests() {
	cur_func="basic_tests"
	local -i failed_flag=0
	print_info 0 "Running basic tests."

	print_info 1 "Checking for presence of the required programs."
	for p in tclsh wish bash cmake make pdflatex rpmbuild dpkg gawk m4 tee find locate grep md5sum sha256sum wine wc; do
		which $p &>/dev/null
		if [ "$?" == "0" ]; then
			printf "${COLOR[green]}[OK]    ${COLOR[none]} $p\n"
		else
			printf "${COLOR[red]}[FAILED]${COLOR[none]} $p\n"
			failed_flag=1
		fi
	done
	if (( failed_flag )); then
		die "Some of the required programs are missing, unable to continue!"
	fi

	print_info 1 "Running MCU 8051 IDE self testing tools."
	tclsh "${SOURCE_DIR}/lib/main.tcl" ${nc_opt_long} --check-libraries || die
	bash "${SOURCE_DIR}/regression_tests/assembler/runtest" ${nc_opt_short} || die
	bash "${SOURCE_DIR}/regression_tests/simulator/runtest" ${nc_opt_short} || die

	print_info 2 "Basic tests complete."
}

function create_launcher() {
	printf "#!/bin/sh\n" > "${2}/mcu8051ide" || die
	printf "exec tclsh8.5 ${1}/main.tcl \"\$@\" || \\\n" >> "${2}/mcu8051ide" || die
	printf "\tprintf \"Unable to execute, TCL interpreter is not reachable.\n\" > /dev/stderr" >> "${2}/mcu8051ide" || die
	chmod -v 0755 "${2}/mcu8051ide" || die
}

function update_msg_files() {
	cur_func="update_msg_files"
	print_info 0 "Updating translation files"

	tclsh "${SOURCE_DIR}/translations/tool.tcl" -t "${SOURCE_DIR}/translations/template.txt" || die
	for f in "${SOURCE_DIR}"/translations/*.msg; do
		if [ ! -e "$f" ]; then
			break
		fi
		print_info 1 "Updating $(basename "$f")"
		tclsh "${SOURCE_DIR}/translations/tool.tcl" -m "$f" || die
	done
	print_info 2 "Update complete."
}

function clear_source_dir() {
	cur_func="clear_source_dir"
	print_info 0 "Cleaning the source directory."
	for i in "${SOURCE_DIR}"/*~ "${SOURCE_DIR}"/*/*~ "${SOURCE_DIR}"/*/*/*~ "${SOURCE_DIR}"/*/*/*/*~; do
		if [ ! -f "$i" ]; then
			continue
		fi
		rm -fv "$i"
	done

	rm -fv "${SOURCE_DIR}/CMakeCache.txt"
	rm -fv "${SOURCE_DIR}/cmake_install.cmake"
	rm -fv "${SOURCE_DIR}/install_manifest.txt"
	rm -fv "${SOURCE_DIR}/Makefile"
	#rm -rfv "${SOURCE_DIR}/mcu8051ide"
	rm -rfv "${SOURCE_DIR}/CMakeFiles"
	find "${SOURCE_DIR}" -name .directory | while read f; do
		rm -rfv "${f}"
	done
	rm -rfv "${SOURCE_DIR}"/doc/handbook/*.{aux,lof,lot,log,out,toc,backup}
	rm -rfv "${SOURCE_DIR}/regression_tests/"*/results/*
	rm -rfv "${SOURCE_DIR}/doc/handbook/doc"
	rm -v "${SOURCE_DIR}"/demo/{lnk,rel,mem,map,bin,sym}

	for f in "${SOURCE_DIR}"/demo/*.c; do
		if [ -e "${f%%.c}.asm" ]; then
			rm -v "${f%%.c}.asm"
			rm -v "${f%%.c}.hex"
			rm -v "${f%%.c}"
		fi
	done

	find "${SOURCE_DIR}" -type d | while read f; do
		chmod -v 0755 "${f}"
	done
	find "${SOURCE_DIR}" -type f | while read f; do
		chmod -v 0644 "${f}"
	done
	for i in lib/main.tcl translations/tool.tcl pkgs/create_installation_packages.sh; do
		chmod -v 0755 "${SOURCE_DIR}/${i}"
	done
	print_info 2 "Cleanup complete."
}

function create_pdf_doc() {
	cur_func="create_pdf_doc"
	print_info 0 "Creating documentation .pdf files using LaTeX."
	cd "${SOURCE_DIR}/doc/handbook" || die
	for f in ./mcu8051ide.*.tex; do
		print_info 1 "Building $(basename "$f")"
		pdflatex "$f" || die
		pdflatex "$f" || die
	done
	cd "${SOURCE_DIR}" || die
	print_info 2 "Documentation build complete."
}

function remove_sandbox() {
	cur_func="remove_sandbox"
	print_info 0 "Removing the temporary work directory."
	rm -rfv "${WORK_DIR}" || die
	print_info 2 "Removal complete."
}

function finalize_sandbox() {
	cur_func="finalize_sandbox"
	print_info 0 "Finalizing creation of the temporary work directory."
	print_info 1 "Compressing the manual page."
	gzip -v "${WORK_DIR}/doc/man/mcu8051ide.1" || die

	print_info 1 "Removing .asm files generated by SDCC (for ASX8051 assembler) from the demo project."
	for f in "${WORK_DIR}"/demo/*.c; do
		if [ -e "${f%%.c}.asm" ]; then
			rm -v "${f%%.c}.asm"
			rm -v "${f%%.c}.hex"
			rm -v "${f%%.c}"
		fi
	done

	print_info 1 "Normalizing the demo project file."
	gawk '
		BEGIN {
			tag=""
		}
		/<graph/ {
			tag="graph"
		}
		/\/>/ {
			tag=""
		}
		/\<actual_line/ {
			gsub(/value=\"[0-9]*\"/, "value=\"1\"", $0);
		}
		/enabled=/ && (tag == "graph") {
			sub(/enabled=\"1\"/, "enabled=\"0\"", $0);
		}
		{
			gsub(/current_file=\"[0-9]*\"/, "current_file=\"0\"", $0);
			gsub(/read_only=\"0\"/, "read_only=\"1\"", $0);
			print($0);
		}
	' "${WORK_DIR}/demo/Demo project.mcu8051ide" > "${WORK_DIR}/demo/Demo project.mcu8051ide.tmp" || die
	mv -v "${WORK_DIR}/demo/Demo project.mcu8051ide.tmp" "${WORK_DIR}/demo/Demo project.mcu8051ide" || die
	chmod -v 0644 "${WORK_DIR}/demo/Demo project.mcu8051ide" || die

	print_info 2 "Creation of temporary work directory finalized."
}

function create_sandbox() {
	cur_func="create_sandbox"
	print_info 0 "Creating temporary work directory: ${WORK_DIR}"
	if [ -e "${WORK_DIR}" ]; then
		print_info 1 "Work directory already exist, removing it."
		remove_sandbox
	fi

	print_info 1 "Coping project files to the work directory."
	mkdir -v "${WORK_DIR}" || die

	for f in ChangeLog README TODO LICENSE mcu8051ide.desktop mcu8051ide.appdata.xml application-x-mcu8051ide.xml CMakeLists.txt mcu8051ide.png; do
		cp -v "${SOURCE_DIR}/${f}" "${WORK_DIR}" || die
	done
	chmod -v 0644 "${WORK_DIR}"/* || die

	print_info 1 "Directory: data."
	mkdir -v "${WORK_DIR}/data" || die
	chmod -v 0755 "${WORK_DIR}/data" || die
	cp -v "${SOURCE_DIR}"/data/*.{txt,dtd,xml} "${WORK_DIR}/data" || die
	chmod -v 0644 "${WORK_DIR}"/data/* || die

	print_info 1 "Directory: demo."
	mkdir -v "${WORK_DIR}/demo" || die
	chmod -v 0755 "${WORK_DIR}/demo" || die
	cp -v "${SOURCE_DIR}"/demo/*.{adf,lst,ihx,mcu8051ide,hashes,hex,vhw,vhc,wtc,asm,c,cdb} "${WORK_DIR}/demo" || die
	chmod -v 0644 "${WORK_DIR}"/demo/* || die

	print_info 1 "Directory: doc."
	mkdir -v "${WORK_DIR}/doc" || die
	mkdir -v "${WORK_DIR}/doc/man" || die
	mkdir -v "${WORK_DIR}/doc/handbook" || die
	mkdir -v "${WORK_DIR}/doc/handbook/img" || die
	chmod -v 0755 "${WORK_DIR}/doc" || die
	chmod -v 0755 "${WORK_DIR}/doc/man" || die
	chmod -v 0755 "${WORK_DIR}/doc/handbook" || die
	chmod -v 0755 "${WORK_DIR}/doc/handbook/img" || die
	cp -v "${SOURCE_DIR}/doc/man/mcu8051ide.1" "${WORK_DIR}/doc/man" || die
	cp -v "${SOURCE_DIR}"/doc/handbook/mcu8051ide.*.{tex,pdf} "${WORK_DIR}/doc/handbook" || die
	cp -v "${SOURCE_DIR}"/doc/handbook/img/*.png "${WORK_DIR}/doc/handbook/img" || die
	chmod -v 0644 "${WORK_DIR}/doc/man/mcu8051ide.1" || die
	chmod -v 0644 "${WORK_DIR}"/doc/handbook/*.{tex,pdf} || die
	chmod -v 0644 "${WORK_DIR}"/doc/handbook/img/*.png || die

	print_info 1 "Directory: hwplugins."
	mkdir -v "${WORK_DIR}/hwplugins" || die
	chmod -v 0755 "${WORK_DIR}/hwplugins" || die
	cp -v "${SOURCE_DIR}"/hwplugins/{plug-in_template.txt,README} "${WORK_DIR}/hwplugins" || die
	chmod -v 0644 "${WORK_DIR}"/hwplugins/* || die

	print_info 1 "Directory: translations."
	mkdir -v "${WORK_DIR}/translations" || die
	chmod -v 0755 "${WORK_DIR}/translations" || die
	cp -v "${SOURCE_DIR}"/translations/*.{txt,msg,tcl} "${WORK_DIR}/translations" || die
	cp -v "${SOURCE_DIR}"/translations/README "${WORK_DIR}/translations/" || die
	chmod -v 0644 "${WORK_DIR}/"translations/* || die
	chmod -v 0755 "${WORK_DIR}/translations/tool.tcl" || die

	print_info 1 "Directory: icons."
	mkdir -v "${WORK_DIR}/icons" || die
	chmod -v 0755 "${WORK_DIR}/icons" || die
	for d in 16x16 22x22 32x32 flag mcu other; do
		mkdir -v "${WORK_DIR}/icons/${d}" || die
		chmod -v 0755 "${WORK_DIR}/icons/${d}" || die
		cp -v "${SOURCE_DIR}"/icons/${d}/*.png "${WORK_DIR}"/icons/${d} || die
		chmod -v 0644 "${WORK_DIR}"/icons/${d}/* || die
	done

	print_info 1 "Directory: lib."
	mkdir -v "${WORK_DIR}/lib/" || die
	chmod -v 0755 "${WORK_DIR}/lib" || die
	cp -v lib/*.tcl "${WORK_DIR}/lib/" || die
	chmod -v 0644 "${WORK_DIR}"/lib/*.tcl || die
	chmod -v 0755 "${WORK_DIR}"/lib/main.tcl || die
	for d in bottompanel compiler editor lib pale simulator simulator/engine configdialogues dialogues leftpanel rightpanel utilities; do
		mkdir -v "${WORK_DIR}/lib/${d}" || die
		chmod -v 0755 "${WORK_DIR}/lib/${d}" || die
		cp -v "${SOURCE_DIR}"/lib/${d}/*.tcl "${WORK_DIR}/lib/${d}" || die
		chmod -v 0644 "${WORK_DIR}"/lib/${d}/*.tcl || die
	done
	cp -v "${SOURCE_DIR}/lib/list_of_files.txt" "${WORK_DIR}/lib/list_of_files.txt" || die
	chmod 0644 "${WORK_DIR}/lib/list_of_files.txt"

	print_info 1 "Directory: pkgs."
	mkdir -v "${WORK_DIR}/pkgs" || die
	chmod 0755 "${WORK_DIR}/pkgs" || die
	cp -v "${SOURCE_DIR}/pkgs/README" "${WORK_DIR}/pkgs" || die
	cp -v "${SOURCE_DIR}"/pkgs/*.sh "${WORK_DIR}/pkgs" || die
	chmod 0644 "${WORK_DIR}/pkgs/README" || die
	chmod 0755 "${WORK_DIR}"/pkgs/*.sh || die
	for d in Debian Gentoo RedHat Windows; do
		mkdir -v "${WORK_DIR}/pkgs/${d}" || die
		chmod 0755 "${WORK_DIR}/pkgs/${d}" || die
	done
	cp -v "${SOURCE_DIR}"/pkgs/Debian/control "${WORK_DIR}/pkgs/Debian/" || die
	chmod 0644 "${WORK_DIR}"/pkgs/Debian/* || die
	cp -v "${SOURCE_DIR}/pkgs/Gentoo/README" "${WORK_DIR}/pkgs/Gentoo/" || die
	cp -v "${SOURCE_DIR}"/pkgs/Gentoo/*.ebuild "${WORK_DIR}/pkgs/Gentoo/" || die
	chmod 0644 "${WORK_DIR}"/pkgs/Gentoo/* || die
	cp -v "${SOURCE_DIR}/pkgs/RedHat/mcu8051ide.spec" "${WORK_DIR}/pkgs/RedHat/" || die
	chmod 0644 "${WORK_DIR}"/pkgs/RedHat/* || die
	cp -v "${SOURCE_DIR}"/pkgs/Windows/*.{bat,ico,iss,txt,bmp} "${WORK_DIR}/pkgs/Windows" || die
	chmod 0644 "${WORK_DIR}"/pkgs/Windows/* || die

	print_info 1 "Directory: regression_tests."
	mkdir -v "${WORK_DIR}/regression_tests/" || die
	chmod -v 0755 "${WORK_DIR}/regression_tests" || die
	cp -v "${SOURCE_DIR}"/regression_tests/{README,rte.lib.sh} "${WORK_DIR}/regression_tests/" || die
	chmod -v 0644 "${WORK_DIR}"/regression_tests/* || die
	 # Assembler
	mkdir -v "${WORK_DIR}/regression_tests/assembler/" || die
	chmod -v 0755 "${WORK_DIR}/regression_tests/assembler/" || die
	cp -v "${SOURCE_DIR}"/regression_tests/assembler/*.awk "${WORK_DIR}/regression_tests/assembler/" || die
	cp -v "${SOURCE_DIR}"/regression_tests/assembler/{process_in_file,README,runtest} "${WORK_DIR}/regression_tests/assembler/" || die
	chmod -v 0755 "${WORK_DIR}/regression_tests/assembler/runtest"
	mkdir -v "${WORK_DIR}/regression_tests/assembler/results" || die
	chmod -v 0755 "${WORK_DIR}/regression_tests/assembler/results" || die
	mkdir -v "${WORK_DIR}/regression_tests/assembler/testcases" || die
	chmod -v 0755 "${WORK_DIR}/regression_tests/assembler/testcases" || die
	cp -v "${SOURCE_DIR}"/regression_tests/assembler/testcases/*.{in,asm,exp} "${WORK_DIR}/regression_tests/assembler/testcases/" || die
	 # Simulator
	mkdir -v "${WORK_DIR}/regression_tests/simulator/" || die
	chmod -v 0755 "${WORK_DIR}/regression_tests/simulator/" || die
	cp -v "${SOURCE_DIR}"/regression_tests/simulator/*.awk "${WORK_DIR}/regression_tests/simulator/" || die
	cp -v "${SOURCE_DIR}"/regression_tests/simulator/{README,runtest} "${WORK_DIR}/regression_tests/simulator/" || die
	chmod -v 0755 "${WORK_DIR}/regression_tests/simulator/runtest"
	mkdir -v "${WORK_DIR}/regression_tests/simulator/results" || die
	chmod -v 0755 "${WORK_DIR}/regression_tests/simulator/results" || die
	mkdir -v "${WORK_DIR}/regression_tests/simulator/testcases" || die
	chmod -v 0755 "${WORK_DIR}/regression_tests/simulator/testcases" || die
	cp -v "${SOURCE_DIR}"/regression_tests/simulator/testcases/*.{in,adf,exp} "${WORK_DIR}/regression_tests/simulator/testcases/" || die
	cp -v "${SOURCE_DIR}"/regression_tests/simulator/testcases/*.asm "${WORK_DIR}/regression_tests/simulator/testcases/" || printf "No .asm files found, but it's ok.\n"
}

function recheck_RTE() {
	cur_func="recheck_RTE"
	print_info 0 "Rerunning the regression tests to ensure that they still work."

	print_info 1 "Preparing directory."
	cp -Rv "${WORK_DIR}/regression_tests/" "${WORK_DIR}/regression_tests.tmp" || die

	print_info 1 "Testing assembler."
	bash "${WORK_DIR}/regression_tests.tmp/assembler/runtest" ${nc_opt_short} || die

	print_info 1 "Testing simulator."
	bash "${WORK_DIR}/regression_tests.tmp/simulator/runtest" ${nc_opt_short} || die

	print_info 1 "Cleaning up."
	rm -rfv "${WORK_DIR}/regression_tests.tmp"

	print_info 2 "Regression tests complete."
}

function detect_version() {
	cur_func="detect_version"
	ide_version=$(grep "set VERSION" "${SOURCE_DIR}/lib/main.tcl" | gawk '{gsub(/\"/,"",$3);print($3)}')
	print_info 1 "Detected version of the IDE: ${ide_version}"

	if ! gawk '/^[0-9]\.[0-9](\.[0-9])?$/ {exit 0} {die}' <<< "${ide_version}"; then
		die "This is not a valid version specification, aborting!"
	fi
}

function create_tarball() {
	cur_func="create_tarball"
	local -r PKG_NAME="mcu8051ide-${ide_version}.tar.gz"
	print_info 0 "Creating source code tarball."
	if [ -e "${PKG_DIR}/${PKG_NAME}" ]; then
		rm -v "${PKG_DIR}/${PKG_NAME}"
	fi
	mv -v "${WORK_DIR}" "${PKG_DIR}/mcu8051ide-${ide_version}" || die
	cd "${PKG_DIR}" || die
	tar cvfz "${PKG_NAME}" "mcu8051ide-${ide_version}" || die
	mv -v "${PKG_DIR}/mcu8051ide-${ide_version}" "${WORK_DIR}" || die

	results+=" ${COLOR[green]}*${COLOR[none]} ${PKG_DIR}/${PKG_NAME}\n"
	print_info 2 "Tarball successfully created: ${PKG_DIR}/${PKG_NAME}"
}

function create_pacman_package() {
	cur_func="create_pacman_package"

	print_info 0 "Creating pacman \"package\"."

	local -r PKG_NAME="Arch-PKGBUILD-mcu8051ide-${ide_version}.tar.gz"
	local -r TARBALL="${PKG_DIR}/mcu8051ide-${ide_version}.tar.gz"
	local -r MD5_SUM=$(md5sum -b "${TARBALL}" | gawk ' { print($1); exit(0) } ')
	local -r DIR="${WORK_DIR}/Arch-PKGBUILD"

	mkdir -v "${DIR}" || die
	gawk "
		/<0.0.0>/ {
			sub(/<0.0.0>/,\"${ide_version}\", \$0)
		}
		/<md5_sum>/ {
			sub(/<md5_sum>/,\"${MD5_SUM}\", \$0)
		}
		/<date>/ {
			sub(/<date>/,\"$(date +%F)\", \$0)
		}
		{
			print(\$0)
		}
	" "${SOURCE_DIR}/pkgs/Arch/PKGBUILD" > "${DIR}/PKGBUILD" || die
	cp -v "${SOURCE_DIR}/pkgs/Arch/README" "${DIR}/" || die
	chmod -v 0644 "${DIR}"/* || die
	cd "${DIR}" || die
	tar cvfz "${PKG_NAME}" PKGBUILD README || die
	mv -vf "${PKG_NAME}" "${PKG_DIR}/" || die
	rm -rfv "${DIR}" || die

	results+=" ${COLOR[green]}*${COLOR[none]} ${PKG_DIR}/${PKG_NAME}\n"
	print_info 2 "pacman \"package\" successfully created: ${PKG_DIR}/${PKG_NAME}"
}

function rm_sctar_files() {
	cur_func="rm_sctar_files"
	print_info 0 "Removing files needed only for the source code tarball."

	rm -v "${WORK_DIR}/lib/list_of_files.txt"
	rm -rfv "${WORK_DIR}/pkgs"

	print_info 2 "Files needed only for source code tarball removed."
}

function check_version() {
	cur_func="check_version"
	print_info 0 "Checking for correct version number in CMakeLists.txt, README, and mcu8051ide_win_setup.iss"

	# Check CMakeLists.txt
	if gawk "/^[ \t]*SET[ \t]*\([ \t]*mcu8051ide_version[ \t]+${ide_version}[ \t]*\)[ \t]*$/ {die}" "${SOURCE_DIR}/CMakeLists.txt"; then
		print_info 1 "Version number in CMakeLists.txt doesn't match the detected version (${ide_version}), correcting."

		gawk "/^[ \t]*SET[ \t]*\([ \t]*mcu8051ide_version[ \t]+[0-9]+\.[0-9]+(\.[0-9]+)?[ \t]*\)[ \t]*$/ {
				\$0=\"SET(mcu8051ide_version ${ide_version})\"
			}
			{
				print(\$0)
			}
		" "${SOURCE_DIR}/CMakeLists.txt" > "/tmp/CMakeLists.txt" || die
		mv "/tmp/CMakeLists.txt" "${SOURCE_DIR}/CMakeLists.txt" || die
	else
		print_info 1 "CMakeLists.txt is OK!"
	fi
	# Check README
	if gawk "/^MCU 8051 IDE v${ide_version}[ \t]*$/ {die}" "${SOURCE_DIR}/README"; then
		print_info 1 "Version number in README doesn't match the detected version (${ide_version}), correcting."

		gawk "/^MCU 8051 IDE v[0-9]+\.[0-9]+(\.[0-9]+)?[ \t]*$/ {
				\$0=\"MCU 8051 IDE v${ide_version}\"
			}
			{
				print(\$0)
			}
		" "${SOURCE_DIR}/README" > "/tmp/README" || die
		mv "/tmp/README" "${SOURCE_DIR}/README" || die
	else
		print_info 1 "README is OK!"
	fi
	# Check mcu8051ide_win_setup.iss
	if gawk "/^AppVerName=MCU[ \t]+8051[ \t]+IDE[ \t]+${ide_version}[ \t]*/ {die}" "${SOURCE_DIR}/pkgs/Windows/mcu8051ide_win_setup.iss"; then
		print_info 1 "Version number in ${SOURCE_DIR}/pkgs/Windows/mcu8051ide_win_setup.iss doesn't match the detected version (${ide_version}), correcting."

		gawk "
			/^AppVerName=MCU[ \t]+8051[ \t]+IDE[ \t]+[0-9]+\.[0-9]+(\.[0-9]+)?[ \t]*/ {
				\$0=\"AppVerName=MCU 8051 IDE ${ide_version}\r\" # <-- On MS Windows we want '\r' before '\n'
			}
			/\OutputBaseFilename=mcu8051ide-[0-9]+\.[0-9]+(\.[0-9]+)?-setup/ {
				\$0=\"OutputBaseFilename=mcu8051ide-${ide_version}-setup\"
			}
			{
				print(\$0)
			}
		" "${SOURCE_DIR}/pkgs/Windows/mcu8051ide_win_setup.iss" > "/tmp/mcu8051ide_win_setup.iss" || die
		mv "/tmp/mcu8051ide_win_setup.iss" "${SOURCE_DIR}/pkgs/Windows/mcu8051ide_win_setup.iss" || die
	else
		print_info 1 "mcu8051ide_win_setup.iss is OK!"
	fi

	print_info 2 "Version check complete."
}

function build_rpm_pkg() {
	cur_func="build_rpm_pkg"
	print_info 0 "Building RPM package."
	print_info 1 "Preparing to build RPM package."
	version=($(sed 's/\./ /g' <<< ${ide_version}))
	if [ -z "${version[2]}" ]; then
		version[2]=0
	fi
	version[2]=$(( ${version[2]} + 1 ))

	print_info 1 "Creating special tarball for the rpmbuild: mcu8051ide-${version[0]}.${version[1]}.tar.gz"
	cd "${PKG_DIR}" || die
	mv -v "${WORK_DIR}" "mcu8051ide-${version[0]}.${version[1]}" || die
	tar cvfz "mcu8051ide-${version[0]}.${version[1]}.tar.gz" "mcu8051ide-${version[0]}.${version[1]}" || die
	mv -v "mcu8051ide-${version[0]}.${version[1]}" "${WORK_DIR}" || die

	print_info 1 "Creating directory structure for rpmbuild."
	mkdir -v "${WORK_DIR}/rpmbuild" || die
	for d in BUILD  BUILDROOT  RPMS  SOURCES  SPECS  SRPMS; do
		mkdir "${WORK_DIR}/rpmbuild/${d}" || die
	done
	mv -v "mcu8051ide-${version[0]}.${version[1]}.tar.gz" "${WORK_DIR}/rpmbuild/SOURCES/" || die

	print_info 1 "Preparing the .spec file."
	gawk "
		/^Version:/ {
			\$0=\"Version: ${version[0]}.${version[1]}\"
		}
		/^Release:/ {
			\$0=\"Release: ${version[2]}\"
		}
		{
			print(\$0)
		}
	" "${SOURCE_DIR}/pkgs/RedHat/mcu8051ide.spec" > "${WORK_DIR}/rpmbuild/SPECS/mcu8051ide-${ide_version}.spec" || die

	print_info 1 "Running rpmbuild."
	local -r PKG_NAME="mcu8051ide-${version[0]}.${version[1]}-${version[2]}.noarch.rpm"
	if [ -e "${PKG_DIR}/${PKG_NAME}" ]; then
		rm -v "${PKG_DIR}/${PKG_NAME}"
	fi
	cd "${WORK_DIR}/rpmbuild" || die
	rpmbuild --define "_topdir ${WORK_DIR}/rpmbuild" -bb --target noarch "./SPECS/mcu8051ide-${ide_version}.spec" || die

	mv -v "${WORK_DIR}/rpmbuild/RPMS/noarch/${PKG_NAME}" "${PKG_DIR}" || die
	results+=" ${COLOR[green]}*${COLOR[none]} ${PKG_DIR}/${PKG_NAME}\n"

	print_info 2 "RPM package successfully created: ${PKG_DIR}/${PKG_NAME}"
}

function build_deb_pkg() {
	cur_func="build_deb_pkg"
	print_info 0 "Building Debian package:"

	print_info 1 "Creating basic directory structure."
	mkdir -v "${WORK_DIR}/mcu8051ide_debian" || die
	mkdir -v "${WORK_DIR}/mcu8051ide_debian/DEBIAN" || die
	mkdir -v "${WORK_DIR}/mcu8051ide_debian/usr" || die
	mkdir -v "${WORK_DIR}/mcu8051ide_debian/usr/bin" || die
	mkdir -v "${WORK_DIR}/mcu8051ide_debian/usr/share" || die
	for d in applications appdata man mcu8051ide pixmaps mime/packages; do
		mkdir -vp "${WORK_DIR}/mcu8051ide_debian/usr/share/${d}" || die
	done

	mkdir -v "${WORK_DIR}/mcu8051ide_debian/usr/share/man/man1" || die
	mkdir -vp "${WORK_DIR}/mcu8051ide_debian/usr/share/mcu8051ide/doc/handbook" || die
	chmod -vR 0755 "${WORK_DIR}/mcu8051ide_debian" || die

	print_info 1 "Creating program launcher."
	create_launcher "/usr/share/mcu8051ide/lib/" "${WORK_DIR}/mcu8051ide_debian/usr/bin/"

	print_info 1 "Coping program sources."
	cp -v "${WORK_DIR}/mcu8051ide.desktop" "${WORK_DIR}/mcu8051ide_debian/usr/share/applications/" || die
	cp -v "${WORK_DIR}/mcu8051ide.appdata.xml" "${WORK_DIR}/mcu8051ide_debian/usr/share/appdata/" || die
	cp -v "${WORK_DIR}/mcu8051ide.png" "${WORK_DIR}/mcu8051ide_debian/usr/share/pixmaps/" || die
	cp -v "${WORK_DIR}/application-x-mcu8051ide.xml" "${WORK_DIR}/mcu8051ide_debian/usr/share/mime/packages/" || die
	cp -v "${WORK_DIR}/doc/man/mcu8051ide.1.gz" "${WORK_DIR}/mcu8051ide_debian/usr/share/man/man1/" || die

	for i in data demo hwplugins icons lib translations LICENSE ChangeLog; do
		cp -vR "${WORK_DIR}/${i}" "${WORK_DIR}/mcu8051ide_debian/usr/share/mcu8051ide/" || die
	done
	cp -v "${WORK_DIR}"/doc/handbook/mcu8051ide.*.pdf "${WORK_DIR}/mcu8051ide_debian/usr/share/mcu8051ide/doc/handbook/" || die

	print_info 1 "Preparing the Debian control file and the md5sums file."
	# Compute MD5 hashes and generate the md5sums file
	cd "${WORK_DIR}/mcu8051ide_debian/"
	md5sum $(find . -type f | awk '/.\// {print(substr($0, 3))}') | tee "DEBIAN/md5sums"

	# Compute the installed size
	local -i total_size=$(ls -lR "${WORK_DIR}/mcu8051ide_debian/usr" | gawk '
		BEGIN {
			sum=0
		}
		END {
			print(int(sum/1024))	# <-- In kB
		}
		($5 != "") {
			sum+=$5
		}')
	# Automatically modify the control file
	gawk "
		/^Version:/ {
			\$0=\"Version: ${ide_version}\"
		}
		/^Installed-Size:/ {
			\$0=\"Installed-Size: ${total_size}\"
		}
		{
			print(\$0)
		}
	" "${SOURCE_DIR}/pkgs/Debian/control" > "${WORK_DIR}/mcu8051ide_debian/DEBIAN/control" || die

	local -r PKG_NAME="mcu8051ide-${ide_version}_all.deb"
	print_info 1 "Running dpkg-deb."
	if [ -e "${PKG_DIR}/${PKG_NAME}" ]; then
		rm -v "${PKG_DIR}/${PKG_NAME}"
	fi
	cd "${WORK_DIR}" || die
	dpkg-deb -b mcu8051ide_debian "${PKG_NAME}" || die
	mv -v "${WORK_DIR}/${PKG_NAME}" "${PKG_DIR}" || die

	results+=" ${COLOR[green]}*${COLOR[none]} ${PKG_DIR}/${PKG_NAME}\n"

	print_info 2 "Debian package successfully created: ${PKG_DIR}/${PKG_NAME}"
}

function build_freeBSD_pkg() {
	cur_func="build_deb_pkg"
	print_info 0 "Building freeBSD package:"

	local -r PKG_NAME="freeBSD-port-mcu8051ide-${ide_version}.tar.gz"

	print_info 1 "Creating basic directory structure."
	mkdir -v "${WORK_DIR}/freeBSD" || die
	mkdir -v "${WORK_DIR}/freeBSD/mcu8051ide" || die
	mkdir -v "${WORK_DIR}/freeBSD/share" || die
	for d in applications appdata man mcu8051ide pixmaps mime/packages; do
		mkdir -vp "${WORK_DIR}/freeBSD/share/${d}" || die
	done

	mkdir -v "${WORK_DIR}/freeBSD/share/man/man1" || die
	mkdir -vp "${WORK_DIR}/freeBSD/share/mcu8051ide/doc/handbook" || die
	chmod -vR 0755 "${WORK_DIR}/freeBSD" || die

	print_info 1 "Creating program launcher."

	print_info 1 "Coping program sources."
	cp -v "${WORK_DIR}/mcu8051ide.desktop" "${WORK_DIR}/freeBSD/share/applications/" || die
	cp -v "${WORK_DIR}/mcu8051ide.appdata.xml" "${WORK_DIR}/freeBSD/share/appdata/" || die
	cp -v "${WORK_DIR}/mcu8051ide.png" "${WORK_DIR}/freeBSD/share/pixmaps/" || die
	cp -v "${WORK_DIR}/application-x-mcu8051ide.xml" "${WORK_DIR}/freeBSD/share/mime/packages/" || die
	cp -v "${WORK_DIR}/doc/man/mcu8051ide.1.gz" "${WORK_DIR}/freeBSD/share/man/man1/" || die

	for i in data demo hwplugins icons lib translations LICENSE ChangeLog; do
		cp -vR "${WORK_DIR}/${i}" "${WORK_DIR}/freeBSD/share/mcu8051ide/" || die
	done
	cp -v "${WORK_DIR}"/doc/handbook/mcu8051ide.*.pdf "${WORK_DIR}/freeBSD/share/mcu8051ide/doc/handbook/" || die

	cd "${WORK_DIR}/freeBSD" || die
	find . -type f | sort | gawk '
		/\/pkg-plist$/ {
			next
		}
		{
			print(substr($0, 3, (length($0) - 2) ))
		}
	' | tee mcu8051ide/pkg-plist || die
	find . -type d | sort -r | gawk '
		/share\/mcu8051ide/ {
			printf("@dirrm %s\n", substr($0, 3, (length($0) - 2)) )
		}
	' | tee -a mcu8051ide/pkg-plist || die

	local -r tarball="mcu8051ide-${ide_version}.tar.gz"
	local -r md5_sum=$(md5sum -b "${PKG_DIR}/${tarball}" | gawk ' { print($1); exit(0) } ')
	local -r sha256_sum=$(sha256sum -b "${PKG_DIR}/${tarball}" | gawk ' { print($1); exit(0) } ')
	local -r tgz_size=$(wc -c "${PKG_DIR}/${tarball}" | gawk ' { print($1); exit(0) } ')

	printf "MD5 (${tarball}) = ${md5_sum}\n" > "${WORK_DIR}/freeBSD/mcu8051ide/distinfo"
	printf "SHA256 (${tarball}) = ${sha256_sum}\n" >> "${WORK_DIR}/freeBSD/mcu8051ide/distinfo"
	printf "SIZE (${tarball}) = ${tgz_size}\n" >> "${WORK_DIR}/freeBSD/mcu8051ide/distinfo"

	gawk "
		/<0.0.0>/ {
			sub(/<0.0.0>/,\"${ide_version}\", \$0)
		}
		/<date>/ {
			sub(/<date>/,\"$(date +%F)\", \$0)
		}
		{
			print(\$0)
		}
	" "${SOURCE_DIR}/pkgs/freeBSD/Makefile" > "${WORK_DIR}/freeBSD/mcu8051ide/Makefile" || die

	cp -v "${SOURCE_DIR}/pkgs/freeBSD/pkg-descr" "${WORK_DIR}/freeBSD/mcu8051ide/" || die
	cp -v "${SOURCE_DIR}/pkgs/freeBSD/README" "${WORK_DIR}/freeBSD/" || die
	local -r PKG_NAME="freeBSD-port-mcu8051ide-${ide_version}.tar.gz"
	cd "${WORK_DIR}/freeBSD/" || die
	tar cvfz "${PKG_NAME}" "README" "mcu8051ide" || die
	mv -fv "${PKG_NAME}" "${PKG_DIR}/" || die

	results+=" ${COLOR[green]}*${COLOR[none]} ${PKG_DIR}/${PKG_NAME}\n"
	print_info 2 "freeBSD port files successfully created: ${PKG_DIR}/${PKG_NAME}"
}

function recompile_demo_project() {
	cur_func="recompile_demo_project"
	print_info 0 "Recompiling the Demo project."

	for f in "${SOURCE_DIR}"/demo/*.asm; do
		if [ ! -e "${f%%.asm}.c" ]; then
			tclsh "${SOURCE_DIR}/lib/main.tcl" ${nc_opt_long} --no-bin --assemble "$f" || die "Cannot assemble file: $f"
		fi
	done

	print_info 2 "Demo project recompiled."
}

function build_freewrapped_package() {
	cur_func="build_freewrapped_package"
	print_info 0 "Creating wrapped package for MS Windows."

	local -r lib_pkg_dir="${SOURCE_DIR}/pkgs/Windows/lib_pkg_dir"
	local -r fwrp_dir="${SOURCE_DIR}/pkgs/Windows/freewrap"
	local -r fwrp="${fwrp_dir}/freewrap"
	local -r fwrpw="${fwrp_dir}/freewrap.exe"
	local autopath="libraries"

	print_info 1 "Preparing libraries to wrap:"
	mkdir -v "${WORK_DIR}/libraries" || die
	chmod -v 0755 "${WORK_DIR}/libraries" || die
	 # Bwidget:
	print_info 3 "Bwidget"
	bwidget_loaction=$(dirname $(locate pkgIndex.tcl | grep bwidget | grep '/usr'))
	if [ "${bwidget_loaction}" == "." ]; then
		die "Unable to find installed BWidget library, aborting!"
	fi
	mkdir -v "${WORK_DIR}/libraries/bwidget" || die
	chmod -v 0755 "${WORK_DIR}/libraries/bwidget" || die
	cp -vR "${bwidget_loaction}"/* "${WORK_DIR}/libraries/bwidget/" || die
	for f in "${WORK_DIR}"/libraries/bwidget/lang/*.rc; do
		printf "\n" >> $f || die
	done
	autopath+=" {libraries/bwidget}"
	 # tcllib/md5
	print_info 3 "tcllib/md5"
	md5_loaction=$(dirname $(locate pkgIndex.tcl | grep '/md5/' | grep '/usr'))
	if [ "${md5_loaction}" == "." ]; then
		die "Unable to find installed tcllib/md5 library, aborting!"
	fi
	mkdir -v "${WORK_DIR}/libraries/md5" || die
	chmod -v 0755 "${WORK_DIR}/libraries/md5" || die
	cp -vR "${md5_loaction}"/*.tcl "${WORK_DIR}/libraries/md5/" || die
	chmod -Rv 0644 "${WORK_DIR}"/libraries/md5/*.tcl || die
	autopath+=" {libraries/md5}"
	 # tdom:
	ver=0.8.3
	print_info 3 "tdom"
	mkdir -v "${WORK_DIR}/libraries/tdom" || die
	chmod -v 0755 "${WORK_DIR}/libraries/tdom" || die
	cp -vR "${lib_pkg_dir}"/tdom${ver}/*.{tcl,dll} "${WORK_DIR}/libraries/tdom/" || die
	chmod -Rv 0644 "${WORK_DIR}"/libraries/tdom/* || die
	autopath+=" {libraries/tdom}"
	 # Itcl3.4:
	print_info 3 "Itcl3.4"
	mkdir -v "${WORK_DIR}/libraries/itcl" || die
	chmod -v 0755 "${WORK_DIR}/libraries/itcl" || die
	cp -v "${lib_pkg_dir}"/Itcl3.4/{itcl34.dll,itcl.tcl} "${WORK_DIR}/libraries/itcl/" || die
	printf "package ifneeded Itcl 3.4 [list load \"${WORK_DIR}/libraries/itcl/itcl34.dll\"]" > "${WORK_DIR}/libraries/itcl/pkgIndex.tcl"
	chmod -Rv 0644 "${WORK_DIR}"/libraries/itcl/* || die
	autopath+=" {libraries/itcl}"
	 # TclX8.4:
	local -r ver="8.4"
	print_info 3 "TclX${ver}"
	mkdir -v "${WORK_DIR}/libraries/tclx${ver}" || die
	chmod -v 0755 "${WORK_DIR}/libraries/tclx${ver}" || die
	cp -v "${lib_pkg_dir}"/Tclx${ver}/*.{tcl,dll} "${WORK_DIR}/libraries/tclx${ver}/" || die
	printf "package ifneeded Tclx ${ver} [list load \"${WORK_DIR}/libraries/tclx${ver}/tclx84.dll\"]" > "${WORK_DIR}/libraries/tclx${ver}/pkgIndex.tcl"
	chmod -Rv 0644 "${WORK_DIR}"/libraries/tclx${ver}/* || die
	autopath+=" {libraries/tclx${ver}}"
	 # imgpng:
	print_info 3 "imgpng-1.4.0.4"
	mkdir -v "${WORK_DIR}/libraries/img_png" || die
	chmod -v 0755 "${WORK_DIR}/libraries/img_png" || die
	cp -v "${lib_pkg_dir}"/img_png1.4.0.4/*.dll "${WORK_DIR}/libraries/img_png/" || die
	printf "package ifneeded img::png 1.4.0.4 {\n\tload \"${WORK_DIR}/libraries/img_png/zlibtcl12503.dll\"\n\tload \"${WORK_DIR}/libraries/img_png/pngtcl143.dll\"\n\tload \"${WORK_DIR}/libraries/img_png/tkimg1404.dll\"\n\tload \"${WORK_DIR}/libraries/img_png/tkimgpng1404.dll\"\n\tpackage provide img::png 1.4.0.4\n}" > "${WORK_DIR}/libraries/img_png/pkgIndex.tcl"
	chmod -Rv 0644 "${WORK_DIR}"/libraries/img_png/* || die
	autopath+=" {libraries/img_png}"

	print_info 1 "Preparing MCU 8051 IDE files and libraries to wrap."
	mv -vf "${WORK_DIR}/data/tips.xml" "${WORK_DIR}/tips.xml" || die # We don't want this file wrapped in the Windows package
	true > "${WORK_DIR}/list_of_files_to_wrap.txt" || die
	for d in lib icons data libraries; do
		find "${WORK_DIR}/${d}" -type f | tee -a "${WORK_DIR}/list_of_files_to_wrap.txt" || die
	done

	print_info 1 "Modifying main.tcl to contain proper LIB_DIRNAME and AUTO_PATH_FOR_MS_WINDOWS."
	gawk "
		/<AIPCS:AUTO_PATH_FOR_MS_WINDOWS>/ {
			sub(/\"<AIPCS:AUTO_PATH_FOR_MS_WINDOWS>\"/, \"[list ${autopath}]\", \$0)
		}
		/<AIPCS:LIB_DIRNAME_SPECIFIC_FOR_MS_WINDOWS>/ {
			sub(/<AIPCS:LIB_DIRNAME_SPECIFIC_FOR_MS_WINDOWS>/, \"${WORK_DIR}/lib\", \$0)
		}
		{
			print(\$0)
		}
	" "${SOURCE_DIR}/lib/main.tcl" > "${WORK_DIR}/lib/main.tcl" || die
	chmod -v 0755 ${WORK_DIR}/lib/main.tcl || die

	print_info 1 "Running freewrap."
	cd "${WORK_DIR}" || die
	chmod -v 0755 "${fwrp}" || die
	"${fwrp}" lib/main.tcl -f list_of_files_to_wrap.txt -o mcu8051ide.exe -w "${fwrpw}" -i "${SOURCE_DIR}/pkgs/Windows/mcu8051ide.ico" 2>&1
	"${fwrp}" lib/external_command.tcl -o external_command.exe -w "${fwrpw}" -i "${SOURCE_DIR}/pkgs/Windows/exec.ico" 2>&1
	print_info 1 "Freewrap finished."

	if [ -e "${WORK_DIR}/win_pkg_files" ]; then
		printf "${WORK_DIR}/win_pkg_files directory (or file) already exists, removing."
		rm -rvf "${WORK_DIR}/win_pkg_files" || die
	fi
	mkdir -v "${WORK_DIR}/win_pkg_files" || die
	chmod 0755 "${WORK_DIR}/win_pkg_files" || die
	mv -vf "${WORK_DIR}/tips.xml" "${WORK_DIR}/data/tips.xml" || die # We didn't want this file wrapped in the Windows package
	mv -v "${WORK_DIR}"/*.exe "${WORK_DIR}/win_pkg_files/" || die
	mv -v "${WORK_DIR}/hwplugins" "${WORK_DIR}/win_pkg_files/" || die
	mv -v "${WORK_DIR}/data" "${WORK_DIR}/win_pkg_files/" || die
	mv -v "${WORK_DIR}/demo" "${WORK_DIR}/win_pkg_files/" || die
	mv -v "${WORK_DIR}/translations" "${WORK_DIR}/win_pkg_files/" || die
	mkdir -vp "${WORK_DIR}/win_pkg_files/doc/handbook" || die
	mv -v "${WORK_DIR}"/doc/handbook/*.pdf "${WORK_DIR}/win_pkg_files/doc/handbook" || die

	print_info 1 "Attempting to run the Inno Setup in Wine in order to create the Windows installation package."
	inno_setup_successful=0
	inno_setup=$(locate Compil32.exe | grep 'Inno Setup')
	if [ ! -z "$inno_setup" ]; then
		local response=""
		if (( ! ${options[inno]} )); then
			printf "Inno Setup program found, make sure that you have set Widnows drive W: to \"${SOURCE_DIR}\".\nDo you want to proceed? [yes] "
			read response
		fi
		if [[ "$response" == "" || "$response" == "y" || "$response" == "yes" ]]; then
			rm -v "${PKG_DIR}/mcu8051ide-${ide_version}-setup.exe"
			printf "Attempting to run the Inno Setup"
			wine "$inno_setup" /cc "W:\\mcu8051ide\\pkgs\\Windows\\mcu8051ide_win_setup.iss" && inno_setup_successful=1
		fi
	else
		printf "Inno Setup program not found."
	fi

	if [ -e "${PKG_DIR}/mcu8051ide-${ide_version}-setup.exe" ]; then
		results+=" ${COLOR[green]}*${COLOR[none]} ${PKG_DIR}/mcu8051ide-${ide_version}-setup.exe\n"
		print_info 2 "Windows package complete: ${PKG_DIR}/mcu8051ide-${ide_version}-setup.exe"
	else
		results+=" ${COLOR[green]}*${COLOR[none]} ${WORK_DIR}/win_pkg_files\n"
		print_info 2 "Windows package complete: ${WORK_DIR}/win_pkg_files"
	fi
}

function create_ebuild() {
	cur_func="create_ebuild"
	print_info 0 "Creating ebuild for Gentoo Linux."

	local -r PKG_NAME="Gentoo-ebuild-mcu8051ide-${ide_version}.tar.gz"
	if [ -e "${PKG_DIR}/${PKG_NAME}" ]; then
		rm -v "${PKG_DIR}/${PKG_NAME}"
	fi

	mkdir -v "${WORK_DIR}/gentoo-ebuild" || die
	gawk "
		/0\.0\.0/ {
			gsub(/0\.0\.0/, \"${ide_version}\", \$0)
		}
		{
			print(\$0)
		}
	" "${SOURCE_DIR}/pkgs/Gentoo/README" > "${WORK_DIR}/gentoo-ebuild/README" || die
	cp -v "${SOURCE_DIR}/pkgs/Gentoo/mcu8051ide.ebuild" "${WORK_DIR}/gentoo-ebuild/mcu8051ide-${ide_version}.ebuild" || die
	chmod -v 0644 "${WORK_DIR}"/gentoo-ebuild/* || die
	cd "${WORK_DIR}/gentoo-ebuild" || die
	tar cvfz "${PKG_NAME}" "README" "mcu8051ide-${ide_version}.ebuild" || die
	mv -v "${PKG_NAME}" "${PKG_DIR}" || die
	rm -rfv "${WORK_DIR}/gentoo-ebuild" || die
	results+=" ${COLOR[green]}*${COLOR[none]} ${PKG_DIR}/${PKG_NAME}\n"

	print_info 2 "Gentoo ebuild complete: ${PKG_DIR}/${PKG_NAME}"
}

function final_report() {
	cur_func="final_report"
	printf "\nProcess successfully finished, resulting packages are:\n${results}\n"
}

function create_final_readme() {
	local -r README_FILE="${PKG_DIR}/readme.txt"

	local source_pkg=
	local deb_pkg=
	local rpm_pkg=
	local ebuild_pkg=
	local arch_pkg=
	local windows_pkg=
	local bsd_pkg=

	if (( ${options[tar]} || ${options[arch]} )); then
		source_pkg="mcu8051ide-${ide_version}.tar.gz"
	fi
	if (( ${options[arch]} )); then
		arch_pkg="Arch-PKGBUILD-mcu8051ide-${ide_version}.tar.gz"
	fi
	if (( ${options[ebuild]} )); then
		ebuild_pkg="Gentoo-ebuild-mcu8051ide-${ide_version}.tar.gz"
	fi
	if (( ${options[rpm]} )); then
		rpm_pkg="mcu8051ide-${version[0]}.${version[1]}-${version[2]}.noarch.rpm"
	fi
	if (( ${options[deb]} )); then
		deb_pkg="mcu8051ide-${ide_version}_all.deb"
	fi
	if (( ${options[windows]} )); then
		windows_pkg="mcu8051ide-${ide_version}-setup.exe"
	fi
	if (( ${options[freeBSD]} )); then
		bsd_pkg="freeBSD-port-mcu8051ide-${ide_version}.tar.gz"
	fi

	if [ ! -z "${source_pkg}" ]; then
		printf "Source code package: %s\n" "${source_pkg}" > "${README_FILE}" || die
	fi
	printf "\n" >> "${README_FILE}" || die
	printf "Installation files\n" >> "${README_FILE}" || die
	printf "  - Linux systems\n" >> "${README_FILE}" || die
	if [ ! -z "${deb_pkg}" ]; then
		printf "    - Ubuntu, etc.:  %s\n" "${deb_pkg}" >> "${README_FILE}" || die
	fi
	if [ ! -z "${rpm_pkg}" ]; then
		printf "    - Fedora, etc.:  %s\n" "${rpm_pkg}" >> "${README_FILE}" || die
	fi
	if [ ! -z "${ebuild_pkg}" ]; then
		printf "    - Gentoo Linux:  %s\n" "${ebuild_pkg}" >> "${README_FILE}" || die
	fi
	if [ ! -z "${arch_pkg}" ]; then
		printf "    - Arch Linux:    %s\n" "${arch_pkg}" >> "${README_FILE}" || die
	fi
	if [ ! -z "${windows_pkg}" ]; then
		printf "  - Windows XP/7:    %s\n" "${windows_pkg}" >> "${README_FILE}" || die
	fi
	if [ ! -z "${bsd_pkg}" ]; then
		printf "  - freeBSD:         %s\n" "${bsd_pkg}" >> "${README_FILE}" || die
	fi
	printf "\n" >> "${README_FILE}" || die
	printf "In case you trouble with any of these files, or you have a suggestion how to\n" >> "${README_FILE}" || die
	printf "make them better, please write an email to the author of the project:\n" >> "${README_FILE}" || die
	printf "martin \DOT osmera \AT gmail \DOT com.\n" >> "${README_FILE}" || die

	results+=" ${COLOR[green]}*${COLOR[none]} ${README_FILE}\n"
}

function die() {
	printf "\n${COLOR[red]}!!!${COLOR[none]} ${COLOR[bold]}Function %s() failed.${COLOR[none]}\n" "${cur_func}"
	if [ ! -z "${1}" ]; then
		printf "${COLOR[red]}!!!${COLOR[none]} ${COLOR[bold]}Message: %s${COLOR[none]}\n" "${1}"
	fi
	exit 1
}

function print_info() {
	case "${1}" in
		0)
			printf "\n${COLOR[blue]}...${COLOR[none]}\n"
			printf "${COLOR[blue]}...${COLOR[none]} ${COLOR[bold]}%s${COLOR[none]}\n" "${2}"
			printf "${COLOR[blue]}...${COLOR[none]}\n\n"
			;;
		1)
			printf "\n${COLOR[yellow]}>>>${COLOR[none]} ${COLOR[bold]}%s${COLOR[none]}\n\n" "${2}"
			;;
		2)
			printf "\n${COLOR[green]}###${COLOR[none]}\n"
			printf "${COLOR[green]}###${COLOR[none]} ${COLOR[bold]}%s${COLOR[none]}\n" "${2}"
			printf "${COLOR[green]}###${COLOR[none]}\n\n"
			;;
		3)
			printf "\n${COLOR[cyan]} * ${COLOR[none]} ${COLOR[bold]}%s${COLOR[none]}\n\n" "${2}"
			;;
		?)	die "Invalid level specification: ${1}"
			;;
	esac
}

function define_colors() {
	if (( ${options[nocolor]} == 0 )); then
		COLOR=(
			[none]="\033[m"		[red]="\033[1;31m"	[green]="\033[1;32m"
			[yellow]="\033[1;33m"	[blue]="\033[1;34m"	[purple]="\033[1;35m"
			[cyan]="\033[1;36m"	[bold]="\033[1m"
		)
	fi
}

function print_help() {
local -r help_message=$(cat << EOF
Script for automated creation of various installation packages, written for
MCU 8051 IDE. This software is distributed under the terms of GNU GPLv2 license.

This script is intended for ${COLOR[bold]}development purposes${COLOR[none]} concerning the MCU 8051 IDE
project, if have found a bug in this script, please contact its author:
Martin Ošmera <mailto:martin.osmera@gmail.com>.

${COLOR[bold]}Basic options:${COLOR[none]}
    ${COLOR[green]}-a${COLOR[none]}  Do it all, it's equivalent to "${COLOR[green]}-sfpomterdwic${COLOR[none]}"
    ${COLOR[green]}-n${COLOR[none]}  Disable color output.
    ${COLOR[green]}-h${COLOR[none]}  Print this message.

${COLOR[bold]}Advanced options:${COLOR[none]}
    ${COLOR[green]}-s${COLOR[none]}  Run tests:
        ${COLOR[blue]}a)${COLOR[none]} check whether all programs required to run this script are available,
        ${COLOR[blue]}b)${COLOR[none]} check for presence libraries required by MCU 8051 IDE,
        ${COLOR[blue]}c)${COLOR[none]} run regression test.
    ${COLOR[green]}-f${COLOR[none]}  Check and fix version number in README, etc. files.
    ${COLOR[green]}-p${COLOR[none]}  Rebuild PDF documentation files.
    ${COLOR[green]}-o${COLOR[none]}  Rebuild demonstration project.
    ${COLOR[green]}-m${COLOR[none]}  Update translation files and the translation template.
    ${COLOR[green]}-t${COLOR[none]}  Create source code tarball.
    ${COLOR[green]}-e${COLOR[none]}  Create tarball with Portage ebuild (for Gentoo Linux).
    ${COLOR[green]}-r${COLOR[none]}  Create RPM package.
    ${COLOR[green]}-d${COLOR[none]}  Create Deb package.
    ${COLOR[green]}-x${COLOR[none]}  Create pacman package (for Arch Linux).
    ${COLOR[green]}-w${COLOR[none]}  Create Windows .exe files.
    ${COLOR[green]}-i${COLOR[none]}  Automatically run Inno Setup in Wine in order to build Windows
        installation package.
    ${COLOR[green]}-c${COLOR[none]}  Clean up the source directory structure, i.e. remove redundant files.
    ${COLOR[green]}-j${COLOR[none]}  Create readme.txt file explaining which package is for what.

${COLOR[bold]}Examples of usage:${COLOR[none]}
  ${COLOR[blue]}*${COLOR[none]} ${SCRIPT_NAME} ${COLOR[green]}-a${COLOR[none]}
      -- Simply do everything we can, recommended way of usage.

  ${COLOR[blue]}*${COLOR[none]} ${SCRIPT_NAME} ${COLOR[green]}-c${COLOR[none]}
      -- Don't build anything, just clean up the source directory.

  ${COLOR[blue]}*${COLOR[none]} ${SCRIPT_NAME} ${COLOR[green]}-mop${COLOR[none]}
      -- Update translations (${COLOR[green]}-m${COLOR[none]}), rebuild the Demo project (${COLOR[green]}-o${COLOR[none]}), rebuild PDF
         documentation (${COLOR[green]}-p${COLOR[none]}).

  ${COLOR[blue]}*${COLOR[none]} ${SCRIPT_NAME} ${COLOR[green]}-r${COLOR[none]}
      -- Skip all tests, rebuilds, etc., and build RPM package right away. This is
         strongly unrecommended.

${COLOR[bold]}Notes:${COLOR[none]}
  ${COLOR[blue]}*${COLOR[none]} If you are about to create Windows installer, ${COLOR[bold]}read the README file first!${COLOR[none]}
  ${COLOR[blue]}*${COLOR[none]} The order of operations is fixed, i.e. it is not affected by the order of
    provided command line switches.
  ${COLOR[blue]}*${COLOR[none]} When using the ${COLOR[green]}-w${COLOR[none]} switch, the script becomes interactive, to avoid that
    either use the switch along with the ${COLOR[green]}-i${COLOR[none]} switch, or don't use it at all.
  ${COLOR[blue]}*${COLOR[none]} Resulting packages will be created in the same directory as this script is
    located.
  ${COLOR[blue]}*${COLOR[none]} Location from which the script is run does not affect operations of the
    script in any way.
  ${COLOR[blue]}*${COLOR[none]} In case of an error, some temporary files or directories might remain at the
    location of this script. To get rid of them, you might use:
    "${SCRIPT_NAME} ${COLOR[green]}-c${COLOR[none]}".
  ${COLOR[blue]}*${COLOR[none]} This script counts on that you have already properly installed MCU 8051 IDE.
EOF
)
printf "${help_message}\n\n"
}

function_touch_all() {
	find "${SOURCE_DIR}" -type f | while read f; do
		touch --no-create "$f"
	done
}

function main() {
	cd "$(dirname "${0}")"

	PKG_DIR="$(pwd)"
	SOURCE_DIR="${PKG_DIR}/.."
	WORK_DIR="${PKG_DIR}/installation_sandbox"
	SCRIPT_NAME="$(basename "${0}")"

	local invalid_options=""

	if [ "$#" == "0" ]; then
		print_help
		exit 1
	fi

	while getopts ":acdefhijkmnoprstwx" opt; do
		case "$opt" in
			h) options[help]=1;;
			n) options[nocolor]=1;;
			s) options[tests]=1;;
			f) options[version]=1;;
			p) options[pdf]=1;;
			o) options[demo]=1;;
			m) options[msg]=1;;
			t) options[tar]=1;;
			e) options[ebuild]=1;;
			r) options[rpm]=1;;
			d) options[deb]=1;;
			x) options[arch]=1;;
			w) options[windows]=1;;
			c) options[clear]=1;;
			i) options[inno]=1;;
			j) options[readme]=1;;
			k) options[freeBSD]=1;;
			a) options[tests]=1
			   options[version]=1
			   options[pdf]=1
			   options[demo]=1
			   options[msg]=1
			   options[tar]=1
			   options[ebuild]=1
			   options[rpm]=1
			   options[deb]=1
			   options[arch]=1
			   options[windows]=1
			   options[inno]=1
			   options[readme]=1
			   options[freeBSD]=1
			   options[clear]=1 ;;
			?) invalid_options+=" ${OPTARG}";;
		esac
	done
	define_colors

	if (( ${options[nocolor]} )); then
		nc_opt_long="--nocolor"
		nc_opt_short="-n"
	fi

	if [ ! -z "$invalid_options" ]; then
		for opt in $invalid_options; do
			printf "${COLOR[reg]}ERROR:${COLOR[none]} Invalid option: %s\n" "${opt}" > /dev/stderr
		done

		printf "\n"
		print_help
		exit 1
	fi

	if (( ${options[help]} )); then
		print_help
		exit 0
	fi

	print_info 1 "Changing current directory to: ${SOURCE_DIR}"
	cd "${SOURCE_DIR}" || die

	function_touch_all
	detect_version
	if (( ${options[tests]} )); then
		basic_tests
	fi
	if (( ${options[version]} )); then
		check_version
	fi
	if (( ${options[pdf]} )); then
		create_pdf_doc
	fi
	if (( ${options[demo]} )); then
		recompile_demo_project
	fi
	if (( ${options[msg]} )); then
		update_msg_files
	fi
	create_sandbox
	if (( ${options[tests]} )); then
		recheck_RTE
	fi
	finalize_sandbox
	if (( ${options[tar]} || ${options[arch]} || ${options[freeBSD]} )); then
		create_tarball
	fi
	rm_sctar_files
	if (( ${options[arch]} )); then
		create_pacman_package
	fi
	if (( ${options[ebuild]} )); then
		create_ebuild
	fi
	if (( ${options[rpm]} )); then
		build_rpm_pkg
	fi
	if (( ${options[deb]} )); then
		build_deb_pkg
	fi
	if (( ${options[freeBSD]} )); then
		build_freeBSD_pkg
	fi
	if (( ${options[windows]} )); then
		build_freewrapped_package
	fi
	if (( ${options[clear]} )); then
		clear_source_dir
	fi
	if (( ${options[readme]} )); then
		create_final_readme
	fi
	remove_sandbox
	final_report
}

main "$@"
