#!/bin/bash

# ----------------------------------------------------------
# base setup

# export or set ROCKCHIP_DEVICE_DIR in .rockchip_device.mk
# to build image for different combos

KERNEL_VER=5.10
KERNEL_DIR=kernel-${KERNEL_VER}

UBOOT_DIR=u-boot

# lunched combo
PRODUCT=${TARGET_PRODUCT}
VARIANT=${TARGET_BUILD_VARIANT}

source build/envsetup.sh
true ${PRODUCT:="aosp_nanopi3"}
true ${VARIANT:="userdebug"}

#----------------------------------------------------------
# local functions

MAKE="make -j$(nproc)"

start_time=$(date +"%s")

FA_ShowTime() {
	local ret=$1
	local end_time=$(date +"%s")
	local tdiff=$(($end_time-$start_time))
	local hours=$(($tdiff / 3600 ))
	local mins=$((($tdiff % 3600) / 60))
	local secs=$(($tdiff % 60))
	local ncolors=$(tput colors 2>/dev/null)
	if [ -n "$ncolors" ] && [ $ncolors -ge 8 ]; then
		color_failed=$'\E'"[0;31m"
		color_success=$'\E'"[0;32m"
		color_reset=$'\E'"[00m"
	else
		color_failed=""
		color_success=""
		color_reset=""
	fi
	echo
	if [ $ret -eq 0 ] ; then
		echo -n "${color_success}#### make completed successfully "
	else
		echo -n "${color_failed}#### make failed to build some targets "
	fi
	if [ $hours -gt 0 ] ; then
		printf "(%02g:%02g:%02g (hh:mm:ss))" $hours $mins $secs
	elif [ $mins -gt 0 ] ; then
		printf "(%02g:%02g (mm:ss))" $mins $secs
	elif [ $secs -gt 0 ] ; then
		printf "(%s seconds)" $secs
	fi
	echo " ####${color_reset}"
	echo
	return $ret
}

FA_RunCmd() {
	[ "$V" = "1" ] && echo "+ ${@}"
	eval $@ || exit $?
}

function usage()
{
	echo "Usage: $0 [ARGS]"
	echo
	echo "Options:"
	echo "  -a         build Android"
	echo "  -B         build U-Boot"
	echo "  -K         build Linux kernel"
	echo
	echo "  -F, --all  build all (U-Boot, kernel, Android)"
	echo "  -M         make rockdev image"
	echo "  -u         generate update.img"
	echo
	echo "  -h         show this help message and exit"
	exit 1
}

function parse_args()
{
	[ -z "$1" ] && usage;
	TEMP=`getopt -o "aBKFMOuh" --long "all,clang,ota" -n "$SELF" -- "$@"`
	if [ $? != 0 ] ; then exit 1; fi
	eval set -- "$TEMP"

	while true; do
		case "$1" in
			-a ) BUILD_ANDROID=true;    shift 1;;
			-B ) BUILD_UBOOT=true;      shift 1;;
			-K ) BUILD_KERNEL=true;     shift 1;;
			-O|--ota)
				 BUILD_OTA=true;        shift 1;;
			-F|--all)
				 BUILD_UBOOT=true;
				 BUILD_KERNEL=true;
				 BUILD_ANDROID=true;
				 shift 1;;
			--clang)
				 BUILD_KERNEL_WITH_CLANG=true;
				 shift 1;;
			-M ) MAKE_RKDEV_IMG=true;   shift 1;;
			-u ) GEN_UPDATE_IMG=true;   shift 1;;

			-h ) usage; exit 1 ;;
			-- ) shift; break  ;;
			*  ) echo "invalid option $1"; usage; return 1 ;;
		esac
	done
}

#----------------------------------------------------------
function check_android_ab() {
	true
}

function build_uboot() {
	local UBOOT_CFG=$(get_build_var PRODUCT_UBOOT_CONFIG)

	check_android_ab
	true ${UBOOT_CFG:=nanopi6}

	cd ${UBOOT_DIR} && {
		FA_RunCmd ./make.sh ${UBOOT_CFG}
		ret=$?
		FA_ShowTime $ret
		cd - >/dev/null
	}
}

function setup_clang() {
	echo $PATH | grep clang-r416183b >/dev/null && return 0
	true ${ANDROID_BUILD_TOP:=$(pwd)}
	local CLANG=$ANDROID_BUILD_TOP/prebuilts/clang/host/linux-x86/clang-r416183b
	export PATH=$CLANG/bin:$PATH
}

function build_kernel() {
	local KERNEL_CFG=$(get_build_var PRODUCT_KERNEL_CONFIG)
	local KERNEL_IMG=$(get_build_var PRODUCT_KERNEL_DTS)

	true ${KERNEL_CFG:=nanopi6_android_defconfig}
	true ${KERNEL_IMG:=nanopi6-images}

	if [ "${KERNEL_VER}" = "5.10" ] ; then
		echo "Force use clang and llvm to build ${KERNEL_DIR}"
		BUILD_KERNEL_WITH_CLANG=true
	fi
	if [ "$BUILD_KERNEL_WITH_CLANG" = true ] ; then
		ADDON_ARGS="CROSS_COMPILE=aarch64-linux-gnu- LLVM=1 LLVM_IAS=1"
		setup_clang
	fi

	cd ${KERNEL_DIR} && {
		FA_RunCmd ${MAKE} ARCH=arm64 ${ADDON_ARGS} ${KERNEL_CFG}
		FA_RunCmd ${MAKE} ARCH=arm64 ${ADDON_ARGS} ${KERNEL_IMG}
		ret=$?
		declare -F make >/dev/null || FA_ShowTime $ret
		cd - >/dev/null
		[ -d "$OUT" ] || return 0
	}

	# repack v2 boot
	if [ "$BUILD_ANDROID" != "true" ]; then
		echo "Repacking header 2 boot.img: "
		local BOOT_CMDLINE=`get_build_var BOARD_KERNEL_CMDLINE`
		local SECURITY_LEVEL=`get_build_var PLATFORM_SECURITY_PATCH`
		local IMAGE_PATH=rockdev/Image-${PRODUCT}
		local REL_OUT=$(realpath $OUT --relative-to=.)
		local RAMDISK_IMG=$OUT/ramdisk.img

		if [ "$(get_build_var BOARD_USES_RECOVERY_AS_BOOT)" = true ]; then
			RAMDISK_IMG=$OUT/ramdisk-recovery.img
		fi
		if [ -n "${TARGET_BUILD_VARIANT}" ]; then
			BOOT_CMDLINE+=" buildvariant=${TARGET_BUILD_VARIANT}"
		fi

		FA_RunCmd cp -af $KERNEL_DIR/arch/arm64/boot/Image $OUT/kernel
		[ -f $OUT/dtb.img ] && DTB_IMG_ARGS="--dtb $OUT/dtb.img"

		mkbootimg --kernel $OUT/kernel \
			--ramdisk ${RAMDISK_IMG} ${DTB_IMG_ARGS} \
			--cmdline "$BOOT_CMDLINE" \
			--os_version 12 --os_patch_level $SECURITY_LEVEL \
			--header_version 2 \
			--second $KERNEL_DIR/resource.img \
			--output $REL_OUT/boot.img &&
			cp -av $REL_OUT/boot.img ${IMAGE_PATH}/boot.img
	fi
}

function build_android() {
	true ${BUILD_NUMBER:=$(date +"6%y%m%d")$(($(date +"%H")/4))}
	export BUILD_NUMBER

	FA_RunCmd lunch ${PRODUCT}-${VARIANT}

	clean_prop_target "$(cat ./out/soong/build_number.txt 2>/dev/null)"
	FA_RunCmd ${MAKE} $*
}

function make_rockdev_img() {
	if [ -z ${TARGET_PRODUCT} ]; then
		FA_RunCmd lunch ${PRODUCT}-${VARIANT}
	fi

	FA_RunCmd ./mkimage.sh
	ret=$?

	[ "$BUILD_OTA" = true ] && copy_ota_images
	FA_ShowTime $ret
}

function build_ota() {
	echo "generate ota package"
	local OTA_FULL=$TARGET_PRODUCT-ota-${BUILD_NUMBER}.zip
	local OTA_PATH=rockdev/otapackage
	local ota_build_number=$(cat $OTA_PATH/build_number.txt 2>/dev/null)
	local ota_target_start=$TARGET_PRODUCT-target_files-${ota_build_number}.zip
	local ota_target_build=$TARGET_PRODUCT-target_files-${BUILD_NUMBER}.zip

	build_android dist
	ret=$?

	mkdir -p $OTA_PATH
	FA_RunCmd "cp out/dist/${ota_target_build} $OTA_PATH/ -f"
	FA_RunCmd "cp out/dist/${OTA_FULL} $OTA_PATH/ -f"

	if [ "$BUILD_NUMBER" != "$ota_build_number" ] &&
	   [ -f $OTA_PATH/${ota_target_start} ] &&
	   [ -f $OTA_PATH/${ota_target_build} ]; then
		ota_from_target_files -v \
			-i $OTA_PATH/${ota_target_start} \
			   $OTA_PATH/${ota_target_build} \
			   $OTA_PATH/ota-update-${BUILD_NUMBER}.zip
		cp device/friendlyelec/nanopi3/gen_ota_json.sh $OTA_PATH/ -f
	fi

	FA_RunCmd "cp ./out/soong/build_number.txt $OTA_PATH/ -f"
	FA_ShowTime $ret
}

function clean_prop_target() {
	[ "$BUILD_NUMBER" == "$1" ] && return 0

	FA_RunCmd "rm -f $OUT/obj/ETC/system_build_prop_intermediates/build.prop"
	FA_RunCmd "rm -f $OUT/odm/etc/build.prop"
	FA_RunCmd "rm -f $OUT/product/build.prop"
	FA_RunCmd "rm -f $OUT/system/build.prop"
	FA_RunCmd "rm -f $OUT/vendor/build.prop"
	FA_RunCmd "rm -f $OUT/recovery/root/default.prop"
	FA_RunCmd "rm -f $OUT/recovery/root/prop.default"
}

function copy_ota_images() {
	local IMAGE_PATH=rockdev/Image-${PRODUCT}
	local target_files=$OUT/obj/PACKAGING/target_files_intermediates

	echo -n "copy mass production super.img for OTA..."
	FA_RunCmd "cp -f $OUT/obj/PACKAGING/super.img_intermediates/super.img $IMAGE_PATH/"
	echo "done."
}

function gen_update_img() {
	echo "generate update.img"
	local PACK_TOOL_DIR=RKTools/linux/Linux_Pack_Firmware
	local IMAGE_PATH=rockdev/Image-${PRODUCT}
	local UPDATE_GEN=rockdev/update_gen

	[ -d ${IMAGE_PATH} ] || make_rockdev_img
	[ -f ${IMAGE_PATH}/update.img ] && rm -vf ${IMAGE_PATH}/update.img

	mkdir -p $PACK_TOOL_DIR/rockdev/Image/
	FA_RunCmd "cp ${IMAGE_PATH}/* $PACK_TOOL_DIR/rockdev/Image/ -f"

	check_android_ab
	cd $PACK_TOOL_DIR/rockdev && {
		./mkupdate.sh $TARGET_BOARD_PLATFORM Image
		ret=$?
		FA_ShowTime $ret
		cd - >/dev/null
	}

	mv $PACK_TOOL_DIR/rockdev/update.img $IMAGE_PATH/
	rm $PACK_TOOL_DIR/rockdev/Image -rf
}

#----------------------------------------------------------

parse_args $@

[ "$BUILD_UBOOT"    = true ] && build_uboot
[ "$BUILD_KERNEL"   = true ] && build_kernel
[ "$BUILD_ANDROID"  = true ] && build_android
[ "$BUILD_OTA"      = true ] && build_ota
[ "$MAKE_RKDEV_IMG" = true ] && make_rockdev_img
[ "$GEN_UPDATE_IMG" = true ] && gen_update_img