#!/bin/bash
#
# Copyright(c) 2012-2022 Intel Corporation
# SPDX-License-Identifier: BSD-3-Clause
#

MISSING_TOOLS=0

check_util() {
	which $1 &> /dev/null
	if [ $? -ne 0 ]
	then
		echo >&2 "Error: missing '$1' utility"
		MISSING_TOOLS=1
	fi
}

check_util dirname
check_util realpath
check_util basename
check_util awk
check_util python3
check_util sed
check_util make
check_util gcc
check_util lsblk

SCRIPTPATH=`dirname $0`
SCRIPTPATH=`realpath $SCRIPTPATH`
SUBMODULES=(
	"ocf"
)

for SUBMOD in ${SUBMODULES[@]}; do
	if ! ls -A "$SCRIPTPATH/$SUBMOD/"* &>/dev/null; then
		SUBMODULES_MISSING+="'$SUBMOD' "
	fi
done
if [ "$SUBMODULES_MISSING" ]; then
	echo "Error: missing submodules: ${SUBMODULES_MISSING}" >&2
	echo "Please run 'git submodule update --init' and try again!" >&2
	MISSING_TOOLS=1
fi

if [ ! -e /lib/modules/$(uname -r)/build/ &> /dev/null ] && [ "$KERNEL_DIR" == "" ]
then
	echo >&2 "Error: missing kernel headers and/or kernel devel"
	MISSING_TOOLS=1
fi

`python3 -c "import argparse" &> /dev/null`
if [ $? -ne 0 ]
then
	echo >&2 "Error: missing argparse python module"
	MISSING_TOOLS=1
fi

if [ ! -f /usr/include/libelf.h ]; then
	KERNEL_CONFIG=$(find /usr/src/ -type d -name "*$(uname -r)")/.config
	if [ -f "$KERNEL_CONFIG" ]; then
		if grep ^CONFIG_UNWINDER_ORC=[Yy] "$KERNEL_CONFIG" &>/dev/null; then
			echo "Error: CONFIG_UNWINDER_ORC=y option is set in your kernel,"\
			"please install libelf-dev, libelf-devel or elfutils-libelf-devel" >&2
			MISSING_TOOLS=1
		fi
	elif [ "$MISSING_TOOLS" -eq 0 ]; then
		# Print this warning only if there is no missing tools, to not confuse the user
		# that installing libelf-dev might help with the lack of needed utilities.
		echo "Warning: unable to find kernel config" >&2
		echo -e "If configure ends with an error, you may need to install"\
		"libelf-dev, libelf-devel or elfutils-libelf-devel\n" >&2
	fi
fi

if [ "$MISSING_TOOLS" -ne "0" ]
then
	exit 1
fi

# Run version generator with 'build' flag to
# indicate that we are in the build process
(cd tools && ./cas_version_gen.sh build)
if [ $? -ne 0 ]; then
	echo "Error: failed to obtain CAS version" >&2
	exit 1
fi

CONFIG_FILES=`ls $SCRIPTPATH/configure.d/*.conf | sort`
FILES_COUNT=`echo $CONFIG_FILES | wc -w`

CONFIG_FILE=$SCRIPTPATH/"config.out"

generate_config() {
	rm -f ${CONFIG_FILE}
	touch ${CONFIG_FILE}
	n_cores=$(nproc)

	# Compile each test module in background
	echo "Preparing configuration"
		for file in $CONFIG_FILES; do
			# $1 - Action to be performed
			# $2 - File with stored configuration
			# $3 - Name of called script (since script is running as subprocess
			#		it has to be passed explicitly)
			source $file "check" "$CONFIG_FILE" "$file" &

			# Prevent spawning more subprocesses than CPU available
			while [ $(ps --no-headers -o pid --ppid=$$ | wc -w) -ge $n_cores ] ; do
				sleep 1
			done
	done

	# Wait for all compilation processes to finish
	wait

	grep "X" ${CONFIG_FILE} &> /dev/null
	if [ $? -eq 0 ] ; then
		echo "ERROR! Following steps failed while preparing config:"
		grep "X" ${CONFIG_FILE} | cut -f1 -d ' '
		exit 1
	fi
}

generate_header() {
	rm -f $SCRIPTPATH/modules/generated_defines.h
	# Configs starting with '1_' have to be put as first in header
	FIRST=$(echo $CONFIG_FILES | tr ' ' '\n' | grep '1_')
	SECOND=$(echo $CONFIG_FILES | tr ' ' '\n' | grep '2_')

	echo "Configuring OpenCAS"
	for file in $FIRST; do
		CONF=$(cat ${CONFIG_FILE} | grep $(basename $file) | cut -d' ' -f2)
		source $file "apply" "$CONF" "$file"
	done

	for file in $SECOND; do
		CONF=$(cat ${CONFIG_FILE} | grep $(basename $file) | cut -d' ' -f2)
		source $file "apply" "$CONF" "$file"
	done
}

if [ -z "$1" ]; then
	generate_config
else
	CONFIG_FILE=$(realpath $1)
	if [ $? -ne 0 ] ; then
		echo "Invaild path to config file!"
		exit 1
	fi
fi

generate_header
