#!/usr/bin/env bash
set -eu

export LC_ALL=C.UTF-8

# This script creates / updates the _mod.qc / _mod.qh / _mod.inc files based on
# the qc / qh files present in the qcsrc folder.

cd "${0%/*}" # Move to qcsrc/tools
cd .. # Move to qcsrc

ROOT="$PWD/"

MOD=_mod

function hash() {
	git hash-object "$1"
}

function print_ifdef() {
	local filename="$1"
	local pathtofile="$2"
	local filetype="$3"
	local outputfile="${MOD}.$filetype"
	local currentqc="$4"  # Current ifdef QC VM type
	local nextqc="${5-NONE}" # Next ifdef QC VM type

	# End previous ifdef if required
	if [ "$currentqc" != "$nextqc" ] \
	&& [ "$currentqc" != "NONE" ]
	then
		printf "#endif\n" >> "$outputfile"
	fi

	# Start new ifdef if required
	if [ "${nextqc-}" != "NONE" ] \
	&& [ "$currentqc" != "$nextqc" ]
	then
		printf "#ifdef %s\n" "$nextqc" >> "$outputfile"
	fi

	# Update
	currentqc="$nextqc"

	# Include the file
	if [ "$currentqc" != "NONE" ]
	then
		# Indent if inside an ifdef block
		printf "\t#include <%s>\n" "$pathtofile$filename" >> "$outputfile"
	else
		printf   "#include <%s>\n" "$pathtofile$filename" >> "$outputfile"
	fi

	# "Return" the current (potentially changed) ifdef QC VM type
	echo "$currentqc"
}

function genmod() {
	# use context to work around cmake issue #12619
	CTX="${PWD#"$ROOT"}/"

	if [ -f "${MOD}.inc" ]
	then
		oldHashC="$(hash ${MOD}.inc)"
		oldTimeC="$(stat -c "%Y" ${MOD}.inc)"
	fi
	if [ -f "${MOD}.qh" ]
	then
		oldHashH="$(hash ${MOD}.qh)"
		oldTimeH="$(stat -c "%Y" ${MOD}.qh)"
	fi

	echo "// $(basename "$0") autogenerated file; do not modify" > "${MOD}.inc"
	echo "// $(basename "$0") autogenerated file; do not modify" > "${MOD}.qh"

	ifdef_inc="NONE" # Can be either CSQC, SVQC, MENUQC, or NONE
	ifdef_qh="NONE"

	# Dr. Jaska: TODO: replace ls with something else
	# LSP note: "Use find instead of ls to better handle non-alphanumeric filenames."
	# Dr. Jaska: find without some configuration would prefix everything with ./ which is likely unwanted
	for f in $(ls | sed -e "s/^cl_//" -e "s/^sv_//" -e "s/^ui_//" | sort -u)
	do
		# skip all files which aren't .qc files
		if [[ "$f" != *.qc ]]; then continue; fi

		# Print the following line:
		#
		# #include <file.q{c,h}>
		#
		# file.qc into _mod.inc
		# file.qh into _mod.qh
		if [[ -f "$f"          ]]; then ifdef_inc=$(print_ifdef "$f"          "$CTX" "inc" "$ifdef_inc"); fi
		if [[ -f "${f%.qc}.qh" ]]; then ifdef_qh=$( print_ifdef "${f%.qc}.qh" "$CTX" "qh"  "$ifdef_qh" ); fi

		# Print the following template:
		#
		# #ifdef {CS,SV,MENU}QC
		# 	#include <file.q{c,h}>
		# #endif
		#
		# CSQC
		# cl_file.qc into _mod.inc
		# cl_file.qh into _mod.qh
		if [[ -f "cl_$f"          ]]; then ifdef_inc=$(print_ifdef "cl_$f"          "$CTX" "inc" "$ifdef_inc" "CSQC"); fi
		if [[ -f "cl_${f%.qc}.qh" ]]; then ifdef_qh=$( print_ifdef "cl_${f%.qc}.qh" "$CTX" "qh"  "$ifdef_qh"  "CSQC");  fi
		# SVQC
		# sv_file.qc into _mod.inc
		# sv_file.qh into _mod.qh
		if [[ -f "sv_$f"          ]]; then ifdef_inc=$(print_ifdef "sv_$f"          "$CTX" "inc" "$ifdef_inc" "SVQC"); fi
		if [[ -f "sv_${f%.qc}.qh" ]]; then ifdef_qh=$( print_ifdef "sv_${f%.qc}.qh" "$CTX" "qh"  "$ifdef_qh"  "SVQC");  fi
		# MENUQC
		# ui_file.qc into _mod.inc
		# ui_file.qh into _mod.qh
		if [[ -f "ui_$f"          ]]; then ifdef_inc=$(print_ifdef "ui_$f"          "$CTX" "inc" "$ifdef_inc" "MENUQC"); fi
		if [[ -f "ui_${f%.qc}.qh" ]]; then ifdef_qh=$( print_ifdef "ui_${f%.qc}.qh" "$CTX" "qh"  "$ifdef_qh"  "MENUQC");  fi
	done
	if [ "$ifdef_inc" != "NONE" ]; then printf "#endif\n" >> "${MOD}.inc"; fi
	if [ "$ifdef_qh"  != "NONE" ]; then printf "#endif\n" >> "${MOD}.qh";  fi

	declare -l rec=1

	if [[ -f "_all.inc" ]]
	then
		rec=0
	fi

	for f in *
	do
		if [ -d "$f" ]
		then
			(cd -- "$f" && genmod)
			if [[ $rec == 1 ]]
			then
				rec=2
				echo >> ${MOD}.inc
				echo >> ${MOD}.qh
			fi
			if [[ $rec != 0 ]]
			then
				declare -l mod=_mod

				if [[ -f "$f/_all.inc" ]]
				then
					mod=_all
				fi

				echo "#include <${CTX}$f/${mod}.inc>" >> "${MOD}.inc"
				echo "#include <${CTX}$f/${mod}.qh>"  >> "${MOD}.qh"
			fi
		fi
	done

	newHashC="$(hash ${MOD}.inc)"

	if [[ "$newHashC" == "$oldHashC" ]]
	then
		touch -d @"$oldTimeC" "${MOD}.inc"
	fi

	newHashH="$(hash ${MOD}.qh)"

	if [[ "$newHashH" == "$oldHashH" ]]
	then
		touch -d @"$oldTimeH" "${MOD}.qh"
	fi
}

(cd lib; genmod)
(cd common; genmod)
(cd ecs; genmod)
(cd client; genmod)
(cd server; genmod)
(cd menu; genmod)
