#!/usr/bin/env sh

set -e

cd "$(dirname "$0")"

mode="${1}"
no_ask="${2}"
network="rtl8139"

qemu_with_flags() {
	if [ "${mode}" = "image" ] || [ "${mode}" = "image_debug" ]; then
		# TODO: Find out why kvm install is incredibly slow
		SDL_VIDEO_X11_DGAMOUSE=0 qemu-system-i386 -no-reboot -vga std -smp "$(nproc)" -serial mon:stdio -rtc base=localtime -m 256M -net nic,model=${network},macaddr=42:42:42:42:42:42 -net user "$@"
	else
		SDL_VIDEO_X11_DGAMOUSE=0 qemu-system-i386 -no-reboot -vga std -serial stdio -rtc base=localtime -m 256M -net nic,model=${network},macaddr=42:42:42:42:42:42 -net user "$@"
	fi
}

make_genext2fs() {
	if [ "$(genext2fs -V | awk '{print $2}')" = "1.4.2" ]; then
		echo "genext2fs is already the newest version"
	else
		if [ "$no_ask" != "-y" ]; then
			printf "Melvix requires the newest genext2fs version, would you like to install it? [y/n] "
			read -r answer
		fi
		if [ "$answer" != "${answer#[Yy]}" ] || [ "$no_ask" = "-y" ]; then
			echo "Building genext2fs..."
			git clone --quiet https://github.com/bestouff/genext2fs.git >/dev/null
			cd genext2fs >/dev/null
			git checkout --quiet 000e369 >/dev/null
			mv README.md README >/dev/null
			touch ChangeLog >/dev/null
			bash autogen.sh >/dev/null
			./configure >/dev/null
			sudo make install >/dev/null
			cd .. >/dev/null
			rm -rf genext2fs >/dev/null
			echo "Success!"
		else
			echo "This probably won't compile..."
		fi
	fi
}

make_cross() {
	if [ ! -d "./cross/" ]; then
		# Create directory
		mkdir -p cross
		cd cross
		DIR=$(pwd)

		# Get sources
		mkdir "${DIR}/src" && cd "${DIR}/src"
		echo "Downloading..."
		curl -sSL "https://ftp.gnu.org/gnu/binutils/binutils-2.34.tar.xz" | tar xJ
		curl -sSL "https://ftp.gnu.org/gnu/gcc/gcc-9.3.0/gcc-9.3.0.tar.xz" | tar xJ

		# Prepare compiling
		mkdir -p "${DIR}/opt/bin"
		export PREFIX="${DIR}/opt"
		export TARGET=i686-elf
		export PATH="$PREFIX/bin:$PATH"

		# Compile binutils
		mkdir "${DIR}/src/build-binutils" && cd "${DIR}/src/build-binutils"
		../binutils-2.34/configure --target="$TARGET" --prefix="$PREFIX" --with-sysroot --disable-nls --disable-werror
		make
		make install

		# Compile GCC
		mkdir "${DIR}/src/build-gcc" && cd "${DIR}/src/build-gcc"
		../gcc-9.3.0/configure --target="$TARGET" --prefix="$PREFIX" --disable-nls --enable-languages=c,c++ --without-headers
		make all-gcc
		make all-target-libgcc
		make install-gcc
		make install-target-libgcc

		cd "${DIR}/.."
	else
		cd cross
		DIR=$(pwd)
		export PREFIX="${DIR}/opt"
		export TARGET=i686-elf
		export PATH="$PREFIX/bin:$PATH"
		cd ..
	fi
}

make_build() {
	rm -rf ./disk/bin/ ./disk/
	mkdir -p build/ disk/bin/ disk/

	echo "Building..."
	cd build/
	cmake .. >/dev/null
	make
	cd ..

	# Copy files
	nasm src/entry.asm -f bin -o disk/boot.bin
	cp build/melvix.bin disk/

	# Create disk image
	make_genext2fs
	/usr/local/bin/genext2fs -B 1024 -d disk/ -U -N 1024 -b 65536 build/disk.img
	dd if=disk/boot.bin of=build/disk.img conv=notrunc

	printf "Build finshed successfully!\n\n"
}

make_test() {
	qemu_with_flags -hdb build/disk.img
}

make_debug() {
	qemu_with_flags -display none -hdb build/disk.img -s -S &
	gdb "$(pwd)"/build/melvix.bin -ex 'target remote localhost:1234'
	killall qemu-system-i386
}

make_disasm() {
	objdump -drwC -Mintel build/kernel.bin --visualize-jumps=color | less -R
}

make_sync() {
	rm tags compile_commands.json
	ctags -R --exclude=.git --exclude=build --exclude=iso --exclude=cross .
	mkdir -p build
	cd build
	cmake .. >/dev/null
	mv compile_commands.json ..
	cd ..
}

make_tidy() {
	shfmt -w ./run
	find ./src -type f -regex '.*\.\(c\|h\)' -exec clang-format -i {} \;
	# This may or may not work
	find ./src -type f -print0 | xargs -0 -l -i sh -c '[ -n "$(tail -c1 {})" ] && printf "\n" >> {}'
}

make_clean() {
	rm -rf ./disk/bin/ ./disk/boot/ ./build/
}

if [ "${mode}" = "cross" ]; then
	make_cross
elif [ "${mode}" = "build" ]; then
	make_cross
	make_clean
	make_build
elif [ "${mode}" = "clean" ]; then
	make_clean
elif [ "${mode}" = "test" ]; then
	make_cross
	make_build
	make_sync &
	make_test
elif [ "${mode}" = "debug" ]; then
	make_cross
	make_build
	make_sync &
	make_debug
elif [ "${mode}" = "again" ]; then
	make_test
elif [ "${mode}" = "disasm" ]; then
	make_cross
	make_build
	make_disasm
elif [ "${mode}" = "sync" ]; then
	make_sync
elif [ "${mode}" = "tidy" ]; then
	make_tidy
elif [ "${mode}" = "" ]; then # TODO: Prevent code duplication in build script via functions?
	make_cross
	make_build
	make_sync &
	make_test
else
	echo "Please use the following syntax:"
	echo "./run {cross | build | clean | test | disasm | sync | tidy} [-y]"
	echo "The default option is 'test'"
fi