#!/usr/bin/env bash

# Typical usage: cd src; ../development/tools/header_check.sh

# file header_check.sh
# This file is part of LyX, the document processor.
# Licence details can be found in the file COPYING.

# author Scott Kostyshak

# Full author contact details are available in file CREDITS

# Description:

# All .cpp and .h files in the current directory and subdirectories
# are checked to see which include statements could be omitted without
# causing a build error. Many of these omissions would not be desired.
# For example, currently if you don't include Undo.h in Undo.cpp, there
# is no error because Undo.h is included in Cursor.h which is included
# in Undo.cpp. But clearly we do want to include Undo.h in Undo.cpp.

# The results are stored in header_check.sh.log

set -u

LOG_FILE="$(basename $0).log"

# For only standard headers:
# PATTERN='^#include <'
# For all headers:
  PATTERN='^#include'

# Exclude common headers with regex
# (e.g. 'debug.h' will exclude 'support/debug.h')
# LyX was compiled on exotic environments and these sometimes
# require headers not needed on win/linux. So check the logs before
# deleting "redundant" standard libraries, Qt headers or includes around
# various ifdefs...
EXCLUDE='\(debug.h\|cstdio\|config.h\)'

NCORES=$(grep "CPU" /proc/cpuinfo | wc -l)

function BUILD_FN ()
{
	PREFIX=''

	# This is not a clean make.
	make -j${NCORES} 2>/dev/null 1>/dev/null
	ERROR_CODE=$?


	# The sed regex is more strict than it needs to be.
	if (( ERROR_CODE != 0 )); then
		# Use just one core, so we don't mix outputs
		IFS='' ERROR_OUTPUT=$(make 2>&1)
		# Without the grep, ERROR_OUTPUT might contain messages such as:
		# 2885 translated messages, 2169 fuzzy translations, 1356 untranslated messages.
		ERROR_OUTPUT=$(echo "${ERROR_OUTPUT}" | grep -i "error: ")
	
		cppORh=$(echo "${ERROR_OUTPUT}" | head -n 1 | \
			sed 's/.*\.\(cpp\|h\):[0-9]\+:[0-9]\+: error: .*/\1/')
		if [ "${cppORh}" = "cpp" ]; then
			PREFIX='suspicious: '
		elif [ "${cppORh}" != "h" ]; then
			echo -e "Warning: the error was not parsed correctly."\
				"\nThe following string was expected to be"\
				"'.cpp' or '.h': \n ${cppORh}" >&2
			echo ERROR_OUTPUT: "${ERROR_OUTPUT}"
			echo cppORh: "${cppORh}"
		fi
	fi
	return "${ERROR_CODE}"
}

echo Making the tree first...
make -j${NCORES} 2>&1 >/dev/null || exit

echo "BUILD_FN exited without error after removing the following include statements invididually:" > "${LOG_FILE}" \
|| { echo "ERROR: could not create log file, ${LOG_FILE}"; exit 1; }

find -regex ".*\(cpp\|h\)$" |  grep -vE "frontends/qt/ui_|frontends/qt/moc_" | sort |
while read FILE_
do
	FILE_COPY=$( tempfile )
	cp "${FILE_}" "${FILE_COPY}" \
		|| { echo "ERROR: bu copy failed" >&2; exit 1; }
	echo -n "processing ${FILE_}..."
	grep "${PATTERN}" "${FILE_}" | \
	while read INCLUDE
	do
		echo -n ${INCLUDE},
		if echo "${INCLUDE}" | grep -q -v "${EXCLUDE}"; then
			cp "${FILE_COPY}" "${FILE_}" \
				|| { echo "ERROR: restore copy failed" >&2; exit 1; }
			sed -i "s@${INCLUDE}@@" "${FILE_}"

			BUILD_FN
			BUILD_FN_RET=$?
			if [ "${BUILD_FN_RET}" = 0 ]; then
				echo "${FILE_}::${INCLUDE}" >> "${LOG_FILE}"
			elif [ -n "${PREFIX}" ]; then
				if [ ${FILE_:(-2):2} == .h ]; then
					echo "${PREFIX}${FILE_}::${INCLUDE}" >> "${LOG_FILE}"
				fi
			fi
		fi
	done
	echo 
	cp "${FILE_COPY}" "${FILE_}"
done