#!/bin/bash

#     _             _     _ _  ___ _       _
#    / \   _ __ ___| |__ (_) |/ (_) |_ ___| |__   ___ _ __
#   / _ \ | '__/ __| '_ \| | ' /| | __/ __| '_ \ / _ \ '_ \
#  / ___ \| | | (__| | | | | . \| | || (__| | | |  __/ | | |
# /_/   \_\_|  \___|_| |_|_|_|\_\_|\__\___|_| |_|\___|_| |_|
#
# Copyright 2014-2015 Łukasz "JustArchi" Domeradzki
# Contact: JustArchi@JustArchi.net
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#    http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

set +e

# Initial variables
VERSION="1.0" # Unused
TEMPDIR="TEMP"
TOOLSDIR="tools"
TOOLS=(which whoami basename dirname gcc java perl sed cut wget od wc cpio zip unzip tar)
XDALINK="http://forum.xda-developers.com/showthread.php?t=2597220"
GITHUBLINK="https://github.com/JustArchi/ArchiKitchen.git"
AUTOUPDATE="1" # Defines if we should turn on auto updates, if available
GITHUBBRANCH="master"
NEEDEDGIT="1.8"

ACTIVE_PROJECT=""
ARCH="unknown"
CUSER="$(whoami)"

ALIGN=4
FULLPERFORMANCE=1
CBIN="" # Ramdisk compression method
DBIN="" # Ramdisk decompression method

META_INF="META-INF/com/google/android"
UPDATER_SCRIPT_HEAD="updater-script-00_HEAD" # Unused
UPDATER_SCRIPT_SYMLINKS="updater-script-10_SYMLINKS"
UPDATER_SCRIPT_PERMISSIONS="updater-script-20_PERMISSIONS"
UPDATER_SCRIPT_EXEC="updater-script-80_EXEC" # Unused
UPDATER_SCRIPT_USER="updater-script-85_USER" # Unused
UPDATER_SCRIPT_KERNEL="updater-script-90_KERNEL"
UPDATER_SCRIPT_MODEM="updater-script-91_MODEM"
UPDATER_SCRIPT_TAIL="updater-script-99_TAIL" # Unused

#  _____                 _   _
# |  ___|   _ _ __   ___| |_(_) ___  _ __  ___
# | |_ | | | | '_ \ / __| __| |/ _ \| '_ \/ __|
# |  _|| |_| | | | | (__| |_| | (_) | | | \__ \
# |_|   \__,_|_| |_|\___|\__|_|\___/|_| |_|___/
#

### CORE ###

# Waits for user action
PRESS_ENTER() {
	read -p "Press [Enter] key to continue..."
}

PRINT_LINE() {
	echo "--------------------------------------------------------------------------------"
}

# Executes commands given in arguments as root
ROOT_EXECUTE() {
	if [[ "$CUSER" = "root" ]]; then
		$@ # Yes, we must break on spaces in this case
	else
		echo "Root access is required! $@"
		if [[ ! -z "$(which sudo)" ]]; then
			sudo $@ # Yes, we must break on spaces in this case
		else
			su -c $@ # Yes, we must break on spaces in this case
		fi
	fi
}

# Compares two versions
VERSION_LESS_THAN() {
	# $1 - Input version
	# $2 - Compared version
	# Returns true if $1 < $2, false otherwise
	if [[ "$1" != "$2" && "$(echo -e "$1\n$2" | sort -V | head -n 1)" = "$1" ]]; then
		return 0
	else
		return 1
	fi
}

# Changes matching word to another one
SED_CHANGE_WORD() {
	# $1 - What we're changing
	# $2 - To what we're changing
	# $3 - File location for that
	# $4 - Unique delimiter (optional)
	if [[ -z "$4" ]]; then
		sed -i 's/'"$1"'/'"$2"'/g' "$3"
	else
		sed -i 's'"$4""$1""$4""$2""$4"'g' "$3"
	fi
}

# Removes all lines which match the word
GREP_DELETE_WORD() {
	# $1 - What we're deleting
	# $2 - File location for that
	grep -v "$1" "$2" > "$2.tmp" && mv -f "$2.tmp" "$2"
}

# Performs cleaning of files/folders based on given blacklist
BLACKLIST_CLEAN() {
	# $1 - target cleaning list
	# $2 - target folder
	mkdir -p "$ACTIVE_PROJECT/$2"
	if [[ -f "files/$1/clean.txt" ]]; then
		while read line; do
			if [[ -z "$line" || "$line" = \#* ]]; then
				continue
			fi
			local TARGETS="$(echo "$line" | awk '{print $1}' | cut -d '"' -f2)"
			case "$TARGETS" in
				/*) ;;
				*.apk)
					TARGETS="$(echo "$TARGETS" | rev | cut -d'.' -f2- | rev)"
					TARGETS="/system/app/$TARGETS /system/app/$TARGETS.apk /system/app/$TARGETS.odex /system/priv-app/$TARGETS /system/priv-app/$TARGETS.apk /system/priv-app/$TARGETS.odex"
				;;
				*.jar)
					TARGETS="$(echo "$TARGETS" | rev | cut -d'.' -f2- | rev)"
					TARGETS="/system/framework/$TARGETS.jar /system/framework/$TARGETS.odex"
				;;
				*.so) TARGETS="/system/lib/$TARGETS" ;;
			esac
			for TARGET in $TARGETS; do
				local TARGETDIR="$ACTIVE_PROJECT/$2$(dirname "$TARGET")"
				mkdir -p "$TARGETDIR"
				if [[ -e "$ACTIVE_PROJECT"$TARGET ]]; then
					echo "Cleaning $(basename "$ACTIVE_PROJECT$TARGET")"
				fi
				mv -f "$ACTIVE_PROJECT"$TARGET "$TARGETDIR" >/dev/null 2>&1 # Yes, we must detect wildcards here
			done
		done < "files/$1/clean.txt"
	fi
}

# Restores previously cleaned files/folders
BLACKLIST_CLEAN_RESTORE() {
	# $1 - target folder
	cp -R "$ACTIVE_PROJECT/$1"/* "$ACTIVE_PROJECT"
	rm -rf "$ACTIVE_PROJECT/$1"
}

# Deletes files/folders based on given blacklist
BLACKLIST_REMOVE() {
	# $1 - target remove list
	if [[ -f "files/$1/remove.txt" ]]; then
		while read line; do
			if [[ -z "$line" || "$line" = \#* ]]; then
				continue
			fi
			local TARGETS="$(echo "$line" | awk '{print $1}' | cut -d '"' -f2)"
			case "$TARGETS" in
				/*) ;;
				*.apk)
					TARGETS="$(echo "$TARGETS" | rev | cut -d'.' -f2- | rev)"
					TARGETS="/system/app/$TARGETS /system/app/$TARGETS.apk /system/app/$TARGETS.odex /system/priv-app/$TARGETS /system/priv-app/$TARGETS.apk /system/priv-app/$TARGETS.odex"
				;;
				*.jar)
					TARGETS="$(echo "$TARGETS" | rev | cut -d'.' -f2- | rev)"
					TARGETS="/system/framework/$TARGETS.jar /system/framework/$TARGETS.odex"
				;;
				*.so) TARGETS="/system/lib/$TARGETS" ;;
			esac
			for TARGET in $TARGETS; do
				if [[ -e "$ACTIVE_PROJECT"$TARGET ]]; then
					echo "Removing $(basename "$ACTIVE_PROJECT$TARGET")"
				fi
				rm -rf "$ACTIVE_PROJECT"$TARGET >/dev/null 2>&1 # Yes, we must detect wildcards here
			done
		done < "files/$1/remove.txt"
	fi
}

# Gives user choice in choosing one thing from a few
PICK_ONE() {
	# $1 - A folder with subdirectories, which are offered as a choice
	PICKCHOICE="" # This must be a global variable
	while [[ -z "$PICKCHOICE" ]]; do
		PRINT_BANNER
		echo "Currently available for selection:"
		PRINT_LINE
		find "$1" -mindepth 1 -maxdepth 1 -type d | sort | while read line; do
			basename "$line"
		done
		PRINT_LINE
		echo
		echo "Type any of above or 'x' to abort"
		read -p "Your choice: " PICKCHOICE
		if [[ "$PICKCHOICE" = "x" ]]; then
			PICKCHOICE=""
			return
		fi
		if [[ ! -d "$1/$PICKCHOICE" ]]; then
			echo "Wrong selection"
			PICKCHOICE=""
			PRESS_ENTER
		else
			return 0
		fi
	done
}


# Tries to mount chosen file
TRY_MOUNT() {
	# $1 - File to mount
	# $2 - Directory to mount file into
	echo "Trying to mount $(basename "$1")"
	ROOT_EXECUTE "modprobe loop"
	mkdir -p "$2"
	echo "Stage 1: Mounting with automatic filesystem..."
	ROOT_EXECUTE "mount -t auto -o loop $1 $2"
	if [[ $? -eq 0 ]]; then
		echo "Success!"
		return 0
	fi
	echo "Failed!"
	ROOT_EXECUTE "umount $2"
	echo "Stage 2: Checking if image is in special sparse ext4 format available for conversion..."
	if [[ "$(od -A n -h -N 5 "$1" | sed 's/ //g')" = "ff3aed260001" ]]; then
		echo "Yes it is!"
		if [[ ! -x "$TEMPDIR/simg2img" ]]; then
			echo "Compiling simg2img..."
			gcc -O2 "$TOOLSDIR/simg2img/sparse_crc32.c" "$TOOLSDIR/simg2img/simg2img.c" -o "$TEMPDIR/simg2img"
		fi
		echo "Converting sparse image to image..."
		./$TEMPDIR/simg2img "$1" "$1".simg2img
		if [[ $? -ne 0 ]]; then
			echo "Conversion failed"
			PRESS_ENTER
		else
			mv -f "$1".simg2img "$1"
			echo "Mounting converted image..."
			ROOT_EXECUTE "mount -t auto -o loop $1 $2"
			if [[ $? -eq 0 ]]; then
				echo "Success!"
				return 0
			fi
		fi
		echo "Failed!"
	else
		echo "It doesn't look like sparse ext4 file"
	fi
	echo "Sorry, all stages failed, we're not able to extract files from this image in any implemented way"
	echo "Either it's not a valid partition image, or we don't know how to mount it"
	PRESS_ENTER
	return 1
}

# Removes ACTIVE_PROJECT
DEL_PROJECT() {
	echo "Cleaning $ACTIVE_PROJECT"
	rm -rf "$ACTIVE_PROJECT"
	ACTIVE_PROJECT=""
}

# Creates new project
SET_NEWPROJECT() {
	PRINT_BANNER
	echo "Before you begin, you must specify what kind of the project you want to create"
	echo
	echo "b - Create a Bare Bones project"
	echo "i - Create a ZIP-flashable ROM from stock partition image(s)"
	echo "z - Create a ZIP-flashable ROM from other ZIP-flashable ROM"
	echo
	read -p "Which choice describes your case? [B/i/z]: " CHOICE
	case "$CHOICE" in
		i|I) NEWPROJECT_STOCK ;;
		z|Z) NEWPROJECT_ZIP ;;
		*) NEWPROJECT_BARE ;;
	esac
}

# Sets ACTIVE_PROJECT
SET_PROJECT() {
	echo
	echo "You currently don't have any active project set"
	echo "You can open any project you've created in the past or create a new one:"
	echo
	echo "n - Create a new project"
	echo "e - Use existing project"
	echo "x - Exit"
	read -p "Your choice: " CHOICE
	case "$CHOICE" in
		n|N) SET_NEWPROJECT ;;
		e|E) SET_OLDPROJECT ;;
		*) exit 0 ;;
	esac
}

# Sets old project as active one
SET_OLDPROJECT() {
	PRINT_BANNER
	local COUNT=0
	local LASTFOUND=""
	echo "Searching for projects you've created in the past..."
	echo "=-=-=-=-=-=-=-=-="
	while read line; do
		((COUNT++))
		LASTFOUND="$line"
		basename "$LASTFOUND"
	done < <(find . -type d -iname "PROJECT_*") # Avoid a subshell, because we must remember variables
	echo "=-=-=-=-=-=-=-=-="
	echo "Found total of $COUNT projects"
	if [[ "$COUNT" -eq 1 ]]; then
		ACTIVE_PROJECT="$(basename "$LASTFOUND")" # If we have only one project, there's nothing to choose from, so we can save some precious seconds
		return 0
	fi
	echo "Write a name of any from the projects detected above or 'x' to go back"
	read -p "Your selected project: " CHOICE
	case "$CHOICE" in
		x|X) return ;;
		*)
			CHOICE="$(basename "$CHOICE")"
			if [[ -d "$CHOICE" ]]; then
				ACTIVE_PROJECT="$CHOICE"
			else
				echo "Invalid selection"
				PRESS_ENTER
			fi
		;;
	esac
}

# Creates a new bare project
NEWPROJECT_BARE() {
	ACTIVE_PROJECT="PROJECT_"
	ACTIVE_PROJECT+="$(date '+%m%d%y_%H%M%S')"
	mkdir -p "$ACTIVE_PROJECT/system"
	BUILD_META_INF
	BUILD_UPDATER_SCRIPT
}

# Creates a new stock image-based project
NEWPROJECT_STOCK() {
	echo "To create a ROM from stock partition images, make sure that you have:"
	echo
	echo "[REQUIRED] system.img - Partition image for /system partition"
	echo "[REQUIRED] boot.img - Raw kernel image for boot block"
	echo "[OPTIONAL] cache.img - Partition image for /cache partition"
	echo "[OPTIONAL] modem.bin - Raw modem image for modem block"
	echo
	echo "Please notice that some ROMs may have other requirements, for example having cache.img as mandatory and not optional"

	local READY=0
	while [[ $READY -eq 0 ]]; do
		echo
		echo "Please fill a path for your system.img file"
		echo "Potential candidates:"
		echo "=-=-=-=-=-=-=-=-="
		find base_drops/ -type f -iname "*system*"
		echo "=-=-=-=-=-=-=-=-="
		read -p "system.img: " SYSTEMIMG

		echo
		echo "Please fill a path for your boot.img file"
		echo "Potential candidates:"
		echo "=-=-=-=-=-=-=-=-="
		find base_drops/ -type f -iname "*boot*"
		echo "=-=-=-=-=-=-=-=-="
		read -p "boot.img: " BOOTIMG

		echo
		echo "Please fill a path for your cache.img file. Leave empty if you don't have one"
		echo "Potential candidates:"
		echo "=-=-=-=-=-=-=-=-="
		find base_drops/ -type f -iname "*cache*"
		echo "=-=-=-=-=-=-=-=-="
		read -p "cache.img: " CACHEIMG

		echo
		echo "Please fill a path for your modem.bin file. Leave empty if you don't have one"
		echo "Potential candidates:"
		echo "=-=-=-=-=-=-=-=-="
		find base_drops/ -type f -iname "*modem*"
		echo "=-=-=-=-=-=-=-=-="
		read -p "modem.bin: " MODEMIMG

		if [[ -f "$SYSTEMIMG" && -f "$BOOTIMG" ]] && ([[ -z "$CACHEIMG" || -f "$CACHEIMG" ]]) && ([[ -z "$MODEMIMG" || -f "$MODEMIMG" ]]); then
			READY=1
		else
			echo "Some of your files do not exist"
			PRESS_ENTER
		fi
	done

	ACTIVE_PROJECT="PROJECT_$(date '+%m%d%y_%H%M%S')"
	echo "Creating $ACTIVE_PROJECT"
	mkdir -p "$ACTIVE_PROJECT/system"

	# KERNEL
	cp "$BOOTIMG" "$ACTIVE_PROJECT/boot.img"

	# SYSTEM
	cp "$SYSTEMIMG" "$ACTIVE_PROJECT/system.img"
	TRY_MOUNT "$ACTIVE_PROJECT/system.img" "/tmp/ArchiKitchenLOOP" || (DEL_PROJECT; return 1)
	echo "Extracting everything from mounted system partition..."
	ROOT_EXECUTE "cp -R /tmp/ArchiKitchenLOOP/* $ACTIVE_PROJECT/system/"
	ROOT_EXECUTE "umount /tmp/ArchiKitchenLOOP"
	rm -f "$ACTIVE_PROJECT/system.img"

	# CACHE
	if [[ ! -z "$CACHEIMG" ]]; then
		cp "$CACHEIMG" "$ACTIVE_PROJECT/cache.img"
		TRY_MOUNT "$ACTIVE_PROJECT/cache.img" "/tmp/ArchiKitchenLOOP"
		if [[ -f "/tmp/ArchiKitchenLOOP/recovery/sec_csc.zip" ]]; then
			echo "Found common Samsung sec_csc.zip file, extracting it and merging with the project"
			ROOT_EXECUTE "unzip -q /tmp/ArchiKitchenLOOP/recovery/sec_csc.zip -d $ACTIVE_PROJECT/"
		else
			echo "Could not detect any known cache format"
			echo "This is typical when cache doesn't contain any valuable files, such as sec_csc.zip in case of Samsung ROMs"
			echo "Extract everything you need from /tmp/ArchiKitchenLOOP before going to the next step"
			PRESS_ENTER
		fi
		ROOT_EXECUTE "umount /tmp/ArchiKitchenLOOP"
		rm -f "$ACTIVE_PROJECT/cache.img"
	fi

	# MODEM
	if [[ ! -z "$MODEMIMG" ]]; then
		cp "$MODEMIMG" "$ACTIVE_PROJECT/modem.bin"
	fi

	# Fix permissions
	ROOT_EXECUTE "chown -hR $CUSER.$CUSER $ACTIVE_PROJECT"
	ROOT_EXECUTE "chmod -R 755 $ACTIVE_PROJECT"

	# Generate required files
	rm -rf "$ACTIVE_PROJECT/META-INF" # In case we have any bloat from sec_csc.zip or similar
	BUILD_META_INF
	BUILD_UPDATER_SCRIPT
	PRESS_ENTER
	SET_KERNEL
	SET_MODEM
}

# Creates a new zip-based project
NEWPROJECT_ZIP() {
	NEWPROJECT_BARE # TODO
}

# Sets kernel
SET_KERNEL() {
	if [[ -f "$ACTIVE_PROJECT/boot.img" ]] && ([[ "$(grep -qi "boot.img" "$ACTIVE_PROJECT/$META_INF/updater-script"; echo $?)" -ne 0 || "$(grep -qi "/tmp/invalid_kernel_path" "$ACTIVE_PROJECT/$META_INF/updater-script"; echo $?)" -eq 0 ]]); then
		PRINT_BANNER
		echo "WARNING! Kernel has been found but there's no path in the current updater-script"
		echo "This is typical when you're converting stock image partition to ZIP-flashable ROM"
		local MODEL="$(grep -i "ro.product.device=" "$ACTIVE_PROJECT/system/build.prop" | head -n 1 | cut -d'=' -f2)"
		if [[ -z "$MODEL" ]]; then
			echo "ERROR: Could not detect ROM model, setting of kernel failed"
			PRESS_ENTER
			return 1
		fi
		echo
		echo "Detected ROM model: $MODEL"
		if [[ -f "product/$MODEL/KERNEL" ]]; then
			KERNELPATH="$(cat "product/$MODEL/KERNEL")"
			echo "Based on detected ROM model and our little database, your kernel path should be: $KERNELPATH"
		else
			echo "This model does not yet exist in our database. Please fill your kernel path manually"
			echo
			echo "Example for I9300/m0 (Samsung Galaxy S3): /dev/block/mmcblk0p5"
			echo "Example for N9005/hlte (Samsung Note 3): /dev/block/mmcblk0p14"
			echo "Example for E960/mako (LG Nexus 4): /dev/block/platform/msm_sdcc.1/by-name/boot"
			echo
			echo "MAKE SURE THAT THE PATH IS CORRECT, OVERWRITING WRONG PATHS MAY LEAD TO SOFT AND HARD BRICKS"
			read -p "Kernel path for your device: " KERNELPATH
		fi
		SED_CHANGE_WORD "/tmp/invalid_kernel_path" "$KERNELPATH" "$ACTIVE_PROJECT/$META_INF/$UPDATER_SCRIPT_KERNEL" "^"
		echo
		echo "The final effect is:"
		echo "=-=-=-=-=-=-=-=-="
		cat "$ACTIVE_PROJECT/$META_INF/$UPDATER_SCRIPT_KERNEL"
		echo
		echo "=-=-=-=-=-=-=-=-="
		echo "Make sure that the command is correct"
		echo "If you need to apply any changes to the generated command, please edit $ACTIVE_PROJECT/$META_INF/$UPDATER_SCRIPT_KERNEL before going to the next step"
		PRESS_ENTER
	fi
}

# Sets modem
SET_MODEM() {
	if [[ -f "$ACTIVE_PROJECT/modem.bin" ]] && ([[ "$(grep -qi "modem.bin" "$ACTIVE_PROJECT/$META_INF/updater-script"; echo $?)" -ne 0 || "$(grep -qi "/tmp/invalid_modem_path" "$ACTIVE_PROJECT/$META_INF/updater-script"; echo $?)" -eq 0 ]]); then
		PRINT_BANNER
		echo "WARNING! Modem has been found but there's no path in the current updater-script"
		echo "This is typical when you're converting stock image partition to ZIP-flashable ROM"
		local MODEL="$(grep -i "ro.product.device=" "$ACTIVE_PROJECT/system/build.prop" | head -n 1 | cut -d'=' -f2)"
		if [[ -z "$MODEL" ]]; then
			echo "ERROR: Could not detect ROM model, setting of modem failed"
			PRESS_ENTER
			return 1
		fi
		echo "Detected ROM model: $MODEL"
		if [[ -f "product/$MODEL/MODEM" ]]; then
			MODEMPATH="$(cat "product/$MODEL/MODEM")"
			echo "Based on detected ROM model and our little database, your modem path should be: $MODEMPATH"
		else
			echo "This model does not yet exist in our database. Please fill your modem path manually"
			echo "Please notice that some models are not supporting flashing a modem via recovery, in such case you should use generic 'NULL' word in this question"
			echo
			echo "Example for I9300/m0 (Samsung Galaxy S3): /dev/block/mmcblk0p7"
			echo "Example for N9005/hlte (Samsung Note 3): NULL"
			echo "Example for E960/mako (LG Nexus 4): /dev/block/platform/msm_sdcc.1/by-name/modem"
			echo
			echo "MAKE SURE THAT THE PATH IS CORRECT, OVERWRITING WRONG PATHS MAY LEAD TO SOFT AND HARD BRICKS"
			read -p "Modem path for your device: " MODEMPATH
		fi
		if [[ "$MODEMPATH" = "NULL" ]]; then
			echo "It looks like your device does not support flashing a modem through recovery, your modem path is NULL"
			rm -f "$ACTIVE_PROJECT/modem.bin" "$ACTIVE_PROJECT/$META_INF/$UPDATER_SCRIPT_MODEM"
		else
			SED_CHANGE_WORD "/tmp/invalid_modem_path" "$MODEMPATH" "$ACTIVE_PROJECT/$META_INF/$UPDATER_SCRIPT_MODEM" "^"
			echo
			echo "The final effect is:"
			echo "=-=-=-=-=-=-=-=-="
			cat "$ACTIVE_PROJECT/$META_INF/$UPDATER_SCRIPT_MODEM"
			echo
			echo "=-=-=-=-=-=-=-=-="
			echo "Make sure that the command is correct"
			echo "If you need to apply any changes to the generated command, please edit $ACTIVE_PROJECT/$META_INF/$UPDATER_SCRIPT_MODEM before going to the next step"
		fi
		PRESS_ENTER
	fi
}

# Creates generic META-INF
BUILD_META_INF() {
	mkdir -p "$ACTIVE_PROJECT/$META_INF"
	cp product/_generic/update-binary "$ACTIVE_PROJECT/$META_INF/update-binary"
	for UPDATER_SCRIPT in "product/_generic/updater-scripts/"*; do
		cp "$UPDATER_SCRIPT" "$ACTIVE_PROJECT/$META_INF/"
	done
}

# Merges updater-scripts from $1 to our ACTIVE_PROJECT
UPDATER_SCRIPT_ADD() {
	local FOLDER="$1"
	local FILE=""
	for UPDATER_SCRIPT in "$FOLDER/updater-script-"*; do
		FILE="$(basename "$UPDATER_SCRIPT")"
		{
			echo # This is to ensure that we have a new line BEFORE appending"
			cat "$UPDATER_SCRIPT"
			echo # This is to ensure that we have a new line AFTER appending"
		} >> "$ACTIVE_PROJECT/$META_INF/$FILE"
		sed -i '/^$/d' "$ACTIVE_PROJECT/$META_INF/$FILE" # This removes safety lines added above
	done
}

# Reverts merge of updater-scripts from $1 in our ACTIVE_PROJECT
UPDATER_SCRIPT_DEL() {
	local FOLDER="$1"
	local FILE=""
	for UPDATER_SCRIPT in "$FOLDER/updater-script-"*; do
		# TODO: I know that this is slow and inefficient way, however at least I can prove that it's stable and secure
		# If anybody manages to delete lines from $ACTIVE_PROJECT/$META_INF/$FILE, which exist in $UPDATER_SCRIPT, please contribute! :)
		# Unfortunately I failed using sed, so I'm out of better ideas :(
		FILE="$(basename "$UPDATER_SCRIPT")"
		echo -n "" > "$ACTIVE_PROJECT/$FILE"
		while read line; do
			if [[ "$(grep -q "$line" "$UPDATER_SCRIPT"; echo $?)" -eq 1 ]]; then
				echo "$line" >> "$ACTIVE_PROJECT/$FILE"
			fi
		done < "$ACTIVE_PROJECT/$META_INF/$FILE"
		mv -f "$ACTIVE_PROJECT/$FILE" "$ACTIVE_PROJECT/$META_INF/$FILE"
	done
}

# Builds final updater-script from our segments
BUILD_UPDATER_SCRIPT() {
	local HEADER=""
	echo -n "" > "$ACTIVE_PROJECT/$META_INF/updater-script"
	for UPDATER_SCRIPT in "$ACTIVE_PROJECT/$META_INF/updater-script-"*; do
		HEADER="# $(basename "$UPDATER_SCRIPT")"
		{
			echo # This is to ensure that we have a new line BEFORE appending"
			echo "$HEADER"
			cat "$UPDATER_SCRIPT"
			echo # This is to ensure that we have a new line AFTER appending"
		} >> "$ACTIVE_PROJECT/$META_INF/updater-script"
	done
	sed -i '/^$/d' "$ACTIVE_PROJECT/$META_INF/updater-script" # This removes safety lines added above
	GREP_DELETE_WORD "/tmp/invalid" "$ACTIVE_PROJECT/$META_INF/updater-script" "^" # This is to ensure that we won't pollute our updater-script with invalid paths for kernel or modem
}

# Removes invalid generic permissions
FIX_PERMISSIONS() {
	echo "Right now you're using generic list of permissions based on multiple devices"
	echo "It's usually a good idea to remove invalid permissions, by invalid I mean permissions to non-existent files or folders"
	read -p "Do you want to remove invalid permissions? [Y/n]: " CHOICE
	case "$CHOICE" in
		n|N) ;;
		*)
			cp "$ACTIVE_PROJECT/$META_INF/$UPDATER_SCRIPT_PERMISSIONS" "$ACTIVE_PROJECT/updater-script-TEMP"
			rm -f "$ACTIVE_PROJECT/updater-script-TEMP-LIST"
			while read perm; do
				perm="$(echo "$perm" | cut -d'"' -f2)"
				if [[ -z "$perm" ]]; then
					continue
				elif [[ ! -e "$ACTIVE_PROJECT$perm" ]]; then
					echo "$perm" >> "$ACTIVE_PROJECT/updater-script-TEMP-LIST"
					grep -v "$perm" "$ACTIVE_PROJECT/updater-script-TEMP" > "$ACTIVE_PROJECT/updater-script-TEMP2"
					mv -f "$ACTIVE_PROJECT/updater-script-TEMP2" "$ACTIVE_PROJECT/updater-script-TEMP"
				fi
			done < "$ACTIVE_PROJECT/$META_INF/$UPDATER_SCRIPT_PERMISSIONS"
			if [[ ! -f "$ACTIVE_PROJECT/updater-script-TEMP-LIST" ]]; then
				echo "No invalid permissions found, your updater-script is clean!"
				rm -f "$ACTIVE_PROJECT/updater-script-TEMP"
			else
				echo "OK, permissions for following files have been removed from your updater-script: "
				echo "-=-= REMOVED PERMISSIONS START =-=-"
				cat "$ACTIVE_PROJECT/updater-script-TEMP-LIST"
				echo "-=-= REMOVED PERMISSIONS EOF =-=-"
				rm -f "$ACTIVE_PROJECT/updater-script-TEMP-LIST"
				mv -f "$ACTIVE_PROJECT/updater-script-TEMP" "$ACTIVE_PROJECT/$META_INF/$UPDATER_SCRIPT_PERMISSIONS"
			fi
			PRESS_ENTER
	esac
}

# Removes invalid generic symlinks, adds local ones
FIX_SYMLINKS() {
	echo "Right now you're probably using generic list of symlinks based on multiple devices"
	echo "It's usually a good idea to remove invalid symlinks, by invalid I mean symlinks to non-existent files or folders"
	read -p "Do you want to remove invalid symlinks? [Y/n]: " CHOICE
	case "$CHOICE" in
		n|N) ;;
		*)
			cp "$ACTIVE_PROJECT/$META_INF/$UPDATER_SCRIPT_SYMLINKS" "$ACTIVE_PROJECT/updater-script-TEMP"
			rm -f "$ACTIVE_PROJECT/updater-script-TEMP-LIST"
			local SYMLINKDIR=""
			while read SYMLINK; do
				SYMLINKDIR="$(dirname "$(echo "$SYMLINK" | cut -d'"' -f4)")"
				SYMLINK="$(echo "$SYMLINK" | cut -d'"' -f2)"
				# If symlink is empty, continue
				if [[ -z "$SYMLINK" ]]; then
					continue
				# If symlink is absolute symlink and doesn't start with /system, continue, we can't track directories like /firmware or /data
				elif [[ "$SYMLINK" == /* && "$SYMLINK" != /system* ]]; then
					continue
				# We may have relative symlink such as /system/bin/dd -> toolbox, or absolute symlink such as /system/bin/busybox -> /system/xbin/buysbox
				elif [[ ! -e "$ACTIVE_PROJECT$SYMLINKDIR/$SYMLINK" && ! -e "$ACTIVE_PROJECT$SYMLINK" ]]; then
					echo "$SYMLINK" >> "$ACTIVE_PROJECT/updater-script-TEMP-LIST"
					grep -v "$SYMLINK" "$ACTIVE_PROJECT/updater-script-TEMP" > "$ACTIVE_PROJECT/updater-script-TEMP2"
					mv -f "$ACTIVE_PROJECT/updater-script-TEMP2" "$ACTIVE_PROJECT/updater-script-TEMP"
				fi
			done < "$ACTIVE_PROJECT/$META_INF/$UPDATER_SCRIPT_SYMLINKS"
			if [[ ! -f "$ACTIVE_PROJECT/updater-script-TEMP-LIST" ]]; then
				echo "No invalid symlinks found, your updater-script is clean!"
				rm -f "$ACTIVE_PROJECT/updater-script-TEMP"
			else
				echo "OK, symlinks for following files have been removed from your updater-script: "
				echo "-=-= REMOVED SYMLINKS START =-=-"
				cat "$ACTIVE_PROJECT/updater-script-TEMP-LIST"
				echo "-=-= REMOVED SYMLINKS EOF =-=-"
				rm -f "$ACTIVE_PROJECT/updater-script-TEMP-LIST"
				mv -f "$ACTIVE_PROJECT/updater-script-TEMP" "$ACTIVE_PROJECT/$META_INF/$UPDATER_SCRIPT_SYMLINKS"
			fi
			PRESS_ENTER
			echo
	esac

	echo "We can also add local symlinks from your project, these are available only if your project is based on stock image and contains symlinks inside"
	echo "It's usually a very good idea to add local symlinks, if they're available, in worst case we won't be able to find anything"
	read -p "Do you want to include local symlinks? [Y/n]: " CHOICE
	case "$CHOICE" in
		n|N) ;;
		*)
			local TARGET=""
			local REALPATH=""
			rm -f "$ACTIVE_PROJECT/updater-script-TEMP-LIST" "$ACTIVE_PROJECT/updater-script-TEMP-FOUNDSYMLINKS"
			local MAGIC="0"
			find "$ACTIVE_PROJECT/" -type l | sort | while read SYMLINK; do
				TARGET="$(readlink "$SYMLINK")"
				if [[ "$MAGIC" -eq 0 ]]; then
					# Find proper path
					for ((I=1; MAGIC==0; I++)); do
						if [[ "$(echo "$SYMLINK" | cut -d'/' -f$I)" = "$ACTIVE_PROJECT" ]]; then
							MAGIC="$((I+1))" # We found where ACTIVE_PROJECT is, so now we can set MAGIC right for the next folder
						fi
					done
				fi
				REALPATH="/"
				REALPATH+="$(echo "$SYMLINK" | cut -d'/' -f$MAGIC-)"
				echo "symlink(\"$TARGET\", \"$REALPATH\");" >> "$ACTIVE_PROJECT/updater-script-TEMP-FOUNDSYMLINKS"
				echo "$REALPATH -> $TARGET" >> "$ACTIVE_PROJECT/updater-script-TEMP-LIST"
			done
			if [[ ! -f "$ACTIVE_PROJECT/updater-script-TEMP-LIST" ]]; then
				echo "No local symlinks found, it looks like your build is not based on stock image or local symlinks have been added already"
			else
				echo "Found symlinks:"
				echo "-=-= ADDED SYMLINKS START =-=-"
				cat "$ACTIVE_PROJECT/updater-script-TEMP-LIST"
				echo "-=-= ADDED SYMLINKS EOF =-=-"
				rm -f "$ACTIVE_PROJECT/updater-script-TEMP-LIST"
				PRESS_ENTER
				echo "We managed to find local symlinks. Therefore, if the list is complete we don't need to include all generic symlinks, but just found ones"
				echo "This will result in exact 1:1 copy of all symlinks which are available in system.img, without adding extra ones"
				echo "It's usually a very good idea to keep only found symlinks instead of the whole list, but you may also want to append them to the generic databse instead of making 1:1 copy"
				read -p "Do you want to include only symlinks that were found? [Y/n]: " CHOICE
				case "$CHOICE" in
					n|N) echo "OK, your symlinks have been appended to the generic list"; cat "$ACTIVE_PROJECT/updater-script-TEMP-FOUNDSYMLINKS" >> "$ACTIVE_PROJECT/$META_INF/$UPDATER_SCRIPT_SYMLINKS"; rm -f "$ACTIVE_PROJECT/updater-script-TEMP-FOUNDSYMLINKS" ;;
					*) echo "OK, updater-script now uses only symlinks that were found"; mv -f "$ACTIVE_PROJECT/updater-script-TEMP-FOUNDSYMLINKS" "$ACTIVE_PROJECT/$META_INF/$UPDATER_SCRIPT_SYMLINKS"
				esac
			fi
			PRESS_ENTER
			echo
	esac

	echo "Please wait..."
	# Remove duplicated symlinks and sort them
	sort -u < "$ACTIVE_PROJECT/$META_INF/$UPDATER_SCRIPT_SYMLINKS" > "$ACTIVE_PROJECT/updater-script-TEMP"
	mv -f "$ACTIVE_PROJECT/updater-script-TEMP" "$ACTIVE_PROJECT/$META_INF/$UPDATER_SCRIPT_SYMLINKS"

	# Remove local symlinks, we don't need them to pollute our ROM
	find "$ACTIVE_PROJECT/" -type l -delete

	# Remove empty lines, if any
	sed -i '/^$/d' "$ACTIVE_PROJECT/$META_INF/$UPDATER_SCRIPT_SYMLINKS"
}

# Extracts the kernel
KERNEL_EXTRACT() {
	if [[ ! -d "$ACTIVE_PROJECT/kernel" ]]; then
		if [[ ! -x "$TEMPDIR/mkbootimg" ]]; then
			cd "$TOOLSDIR/mkbootimg"
			make
			if [[ ! -x mkbootimg || ! -x unpackbootimg ]]; then
				echo "ERROR! Something went wrong with compilation of mkbootimg!"
				PRESS_ENTER
				return 1
			fi
			mv mkbootimg "../../$TEMPDIR/mkbootimg"
			mv unpackbootimg "../../$TEMPDIR/unpackbootimg"
			make clean
			cd ../..
		fi

		if [[ ! -L "$TOOLSDIR/mtk-tools/mkbootimg" ]]; then
			rm -f "$TOOLSDIR/mtk-tools/mkbootimg"
			ln -s "../../$TEMPDIR/mkbootimg" "$TOOLSDIR/mtk-tools/mkbootimg"
		fi

		if [[ -f "$ACTIVE_PROJECT/boot.img" ]]; then
			mkdir -p "$ACTIVE_PROJECT/kernel"
			"$TEMPDIR/unpackbootimg" -i "$ACTIVE_PROJECT/boot.img" -o "$ACTIVE_PROJECT/kernel"
			mkdir -p "$ACTIVE_PROJECT/kernel/boot.img-ramdisk"
			if [[ -f "$ACTIVE_PROJECT/kernel/boot.img-ramdisk.gz" ]]; then
				# Detect compression algorithm
				if [[ "$(gunzip -t "$ACTIVE_PROJECT/kernel/boot.img-ramdisk.gz" >/dev/null 2>&1; echo $?)" -eq 0 ]]; then
					# GZIP
					CBIN="gzip -9"
					DBIN="gunzip -c"
				elif [[ "$(lzop -t "$ACTIVE_PROJECT/kernel/boot.img-ramdisk.gz" >/dev/null 2>&1; echo $?)" -eq 0 ]]; then
					# LZO
					CBIN="lzop -9"
					DBIN="lzop -dc"
				elif [[ "$(xz -t "$ACTIVE_PROJECT/kernel/boot.img-ramdisk.gz" >/dev/null 2>&1; echo $?)" -eq 0 ]]; then
					# XZ
					CBIN="xz -9"
					DBIN="xz -dc"
				elif [[ "$(lzma -t "$ACTIVE_PROJECT/kernel/boot.img-ramdisk.gz" >/dev/null 2>&1; echo $?)" -eq 0 ]]; then
					# LZMA
					CBIN="lzma -9"
					DBIN="lzma -dc"
				else
					echo "WARNING: Could not detect any known format of the ramdisk!"
					KERNEL_ABORT
					echo "INFO: Trying to unpack the kernel as MTK..."
					mkdir -p "$ACTIVE_PROJECT/kernel"
					cd "$ACTIVE_PROJECT/kernel"
					local MTK_PROBE="$(../../$TOOLSDIR/mtk-$TOOLSDIR/unpack-MTK.pl "../boot.img" >/dev/null 2>&1; echo $?)"
					cd ../..
					if [[ "$MTK_PROBE" -eq 0 ]]; then
						echo "INFO: Success!"
						CBIN="mtk"
						DBIN="mtk"
					else
						echo "ERROR: Could not find any valid method to unpack this kernel. Either it's not valid, or ArchiKitchen can't find out how to deal with it"
						KERNEL_ABORT
						PRESS_ENTER
						return 1
					fi
				fi
				echo "$CBIN" > "$ACTIVE_PROJECT/kernel/ArchiKitchen-compression-method" # Store for future use, if user decides to shut down the kitchen
				if [[ "$CBIN" != "mtk" && "$DBIN" != "mtk" ]]; then
					cd "$ACTIVE_PROJECT/kernel/boot.img-ramdisk"
					$DBIN ../boot.img-ramdisk.gz | cpio -i
					cd ../../..
				fi
			fi
		else
			echo "ERROR: No kernel could be found!"
			PRESS_ENTER
			return 1
		fi
	fi
}

# Repacks the kernel from previously extracted one
KERNEL_REPACK() {
	local EXTRA=()
	if [[ -d "$ACTIVE_PROJECT/kernel" ]]; then
		if [[ -d "$ACTIVE_PROJECT/kernel/boot.img-ramdisk" ]]; then
			if [[ -z "$CBIN" && -f "$ACTIVE_PROJECT/kernel/ArchiKitchen-compression-method" ]]; then
				CBIN="$(cat "$ACTIVE_PROJECT/kernel/ArchiKitchen-compression-method")" # Load compression method if we need it and have it stored
			elif [[ -z "$CBIN" ]]; then
				echo "ERROR: Can't decide which compression method to use!"
				KERNEL_ABORT
				PRESS_ENTER
				return 1
			fi
			local SUCCESS=1
			if [[ "$CBIN" != "mtk" ]]; then
				cd "$ACTIVE_PROJECT/kernel/boot.img-ramdisk"
				find . | cpio -o -H newc | $CBIN > ../boot.img-ramdisk-NEW.gz
				cd ../../..
				if [[ -f "$ACTIVE_PROJECT/kernel/boot.img-dtb" ]]; then
					EXTRA+=(--dt "$ACTIVE_PROJECT/kernel/boot.img-dtb")
				fi
				SUCCESS="$(
					"$TEMPDIR/mkbootimg" --kernel "$ACTIVE_PROJECT/kernel/boot.img-zImage" \
					--ramdisk "$ACTIVE_PROJECT/kernel/boot.img-ramdisk-NEW.gz" \
					--base "$(cat "$ACTIVE_PROJECT/kernel/boot.img-base")" \
					--cmdline "$(cat "$ACTIVE_PROJECT/kernel/boot.img-cmdline")" \
					--kernel_offset "$(cat "$ACTIVE_PROJECT/kernel/boot.img-kerneloff")" \
					--pagesize "$(cat "$ACTIVE_PROJECT/kernel/boot.img-pagesize")" \
					--ramdisk_offset "$(cat "$ACTIVE_PROJECT/kernel/boot.img-ramdiskoff")" \
					--tags_offset "$(cat "$ACTIVE_PROJECT/kernel/boot.img-tagsoff")" \
					"${EXTRA[@]}" \
					-o "$ACTIVE_PROJECT/kernel/temp.img" >/dev/null 2>&1
					echo $?
				)"
			else
				cd "$ACTIVE_PROJECT/kernel"
				SUCCESS="$(
					../../tools/mtk-tools/repack-MTK.pl -boot \
					boot.img-kernel.img \
					boot.img-ramdisk \
					temp.img >/dev/null 2>&1
					echo $?
				)"
				cd ../..
			fi
			if [[ "$SUCCESS" -eq 0 ]]; then
				mv "$ACTIVE_PROJECT/kernel/temp.img" "$ACTIVE_PROJECT/boot.img"
				KERNEL_ABORT # This is actually used for cleaning only
				return 0
			else
				echo "ERROR: Something went wrong! Error code: $SUCCESS"
				KERNEL_ABORT
				PRESS_ENTER
				return 1
			fi
		else
			echo "ERROR: Could not find the ramdisk!"
			KERNEL_ABORT
			PRESS_ENTER
			return 1
		fi
	fi
}

# Aborts kernel repacking - performs cleaning
KERNEL_ABORT() {
	rm -rf "$ACTIVE_PROJECT/kernel"
	rm -f "$ACTIVE_PROJECT/temp.img"
}

# Adds kernel's Init.d
INITD() {
	if [[ -f "$ACTIVE_PROJECT/kernel/boot.img-ramdisk/init.rc" ]]; then
		sed -i -e '0,/class_start /s//start sysinit\n\n    class_start /' "$ACTIVE_PROJECT/kernel/boot.img-ramdisk/init.rc"
		sed -i -e 's/service media /service sysinit \/system\/bin\/logwrapper \/system\/xbin\/busybox run-parts \/system\/etc\/init.d\n    disabled\n    oneshot\n\nservice media /' "$ACTIVE_PROJECT/kernel/boot.img-ramdisk/init.rc"
		cp -R files/initd/system/* "$ACTIVE_PROJECT/system/"
		UPDATER_SCRIPT_ADD "files/initd/updater-scripts"
	else
		echo "ERROR, no init.rc found?!"
		rm -rf kernel
		PRESS_ENTER
		return 1
	fi
}

# Builds ROM
BUILD() {
	local EXPERT=0
	for ARG in "$@"; do
		case "$ARG" in
			"EXPERT")
				EXPERT=1
		esac
	done
	if [[ "$EXPERT" -eq 0 ]]; then
		FIX_PERMISSIONS
		FIX_SYMLINKS
		BUILD_UPDATER_SCRIPT
		SED_CHANGE_WORD "313371337" "$(find "$ACTIVE_PROJECT/system" -type f | wc -l)" "$ACTIVE_PROJECT/$META_INF/updater-script" # This will change our temporary int in progress to a number of all files in system directory, making progress bar truly reliable
		PRESS_ENTER
		echo "Sometimes kitchen may produce an incorrect updater-script file, that's why you're asked to review updater-script and eventually fix it if needed BEFORE building ROM"
		echo "Updater-script is based on so-called 'segments' available in the same directory - $META_INF"
		echo "Are you ready?"
		PRESS_ENTER
		echo "-=-= UPDATER-SCRIPT START =-=-"
		cat "$ACTIVE_PROJECT/$META_INF/updater-script"
		echo "-=-= UPDATER-SCRIPT EOF =-=-"
		read -p "Are you REALLY sure that above updater-script is correct? ESPECIALLY block-based paths? [Y/n]: " CHOICE
		case "$CHOICE" in
			n|N)
				echo "OK, correct your updater-script and/or it's segments and come back when you're finished"
				PRESS_ENTER
				return 0
		esac
	fi
	local COMPLEVEL="1"
	echo
	echo "Which compression level do you want to use?"
	echo "0 - Store (fastest method, no compression at all)"
	echo "1 - Fastest (fastest type of compression, this is default suggested mode)"
	echo "9 - Best (slowest, maximum compression)"
	echo "You can also type any number between 0-9"
	read -p "CHOICE: " CHOICE
	case "$CHOICE" in
		[0-9]) COMPLEVEL="$CHOICE"
	esac
	cd "$ACTIVE_PROJECT"
	zip -ry -"$COMPLEVEL" "$ACTIVE_PROJECT.zip" . -x "$META_INF/updater-script-"*
	cd ..
	mkdir -p OUTPUT
	mv -f "$ACTIVE_PROJECT/$ACTIVE_PROJECT.zip" "OUTPUT/$ACTIVE_PROJECT.zip"
	echo "Done, your ROM is available in OUTPUT/$ACTIVE_PROJECT.zip"
	read -p "Rename it? [N/y]: " CHOICE
	case "$CHOICE" in
		y|Y)
			read -p "New name: " NAME
			mv -f "OUTPUT/$ACTIVE_PROJECT.zip" "OUTPUT/$NAME"
	esac
	echo "All done, your ROM should be ready!"
	echo "Thank you for using ArchiKitchen!"
	PRESS_ENTER
	exit 0
}

# Deodexes single file
DEODEX_FILE() {
	local ODEX="$(basename "$1")"
	local FILEDIR="$(dirname "$1")"
	local FILE="$(echo "$ODEX" | rev | cut -d'.' -f2- | rev)"
	local FILEEXTENSION=""
	# Find file that odex relates to
	for EXTENSION in "apk" "jar"; do
		if [[ -f "$FILEDIR/$FILE.$EXTENSION" ]]; then
			FILEEXTENSION="$EXTENSION"
			break
		fi
	done
	if [[ -z "$FILEEXTENSION" ]]; then
		echo "ERROR: Can't determine what $ODEX relates to!"
		return 1
	fi
	FILE="$FILE.$FILEEXTENSION"
	echo "Deodexing $FILE..."
	# If file already contains classes.dex, we should delete proper odex file only
	if [[ "$(unzip -l "$FILEDIR/$FILE" | grep -q "classes.dex"; echo $?)" -eq 0 ]]; then
		echo "INFO: $FILE contains classes.dex already, removing $ODEX"
		rm -f "$FILEDIR/$ODEX"
		return 0
	fi
	echo "Disassembling $ODEX..."
	rm -rf "$TEMPDIR/$ODEX"
	mkdir -p "$TEMPDIR/$ODEX"
	java -jar "$TOOLSDIR/smali/baksmali.jar" -a "$API" -d "$ACTIVE_PROJECT/system/framework" -x "$FILEDIR/$ODEX" -o "$TEMPDIR/$ODEX/DECOMPILED"
	if [[ $? -ne 0 || ! -d "$TEMPDIR/$ODEX/DECOMPILED" ]]; then
		echo "ERROR: Could not deodex $ODEX, aborting!"
		rm -rf "$TEMPDIR/$ODEX"
		PRESS_ENTER
		return 1
	fi
	echo "Assembling disassembled $ODEX into classes.dex..."
	java -jar "$TOOLSDIR/smali/smali.jar" -a "$API" -o "$TEMPDIR/$ODEX/classes.dex" "$TEMPDIR/$ODEX/DECOMPILED"
	if [[ $? -ne 0 || ! -f "$TEMPDIR/$ODEX/classes.dex" ]]; then
		echo "ERROR: Could not assemble disassembled $ODEX, aborting!"
		rm -rf "$TEMPDIR/$ODEX"
		PRESS_ENTER
		return 1
	fi
	echo "Packing back classes.dex into $FILE..."
	zip -jrq "$FILEDIR/$FILE" "$TEMPDIR/$ODEX/classes.dex"
	rm -f "$FILEDIR/$ODEX"
	rm -rf "$TEMPDIR/$ODEX"
	echo "SUCCESS: $FILE"
}

# Deodexes everything
DEODEX() {
	local API="$(grep "ro.build.version.sdk" "$ACTIVE_PROJECT/system/build.prop" | cut -d'=' -f2)"
	echo "Detected API level $API"
	echo "Usually you don't want to change this value"
	read -p "Change it? [N/y]: " CHOICE
	case "$CHOICE" in
		y|Y) read -p "Your selected API level: " API ;;
	esac
	case "$API" in
		[0-9]*) ;;
		*)
			echo "Sorry, it looks like API level is invalid"
			PRESS_ENTER
			return 1
	esac
	find "$ACTIVE_PROJECT" -type f -iname "*.odex" | while read ODEX; do
		DEODEX_FILE "$ODEX"
	done
	echo "Deodexing finished"
	PRESS_ENTER
	return 0
}

# Zipaligns single file
ZIPALIGN_FILE() {
	echo "Zipaligning $(basename "$1")..."
	"$ZIPALIGN" -f "$ALIGN" "$1" "$1.zipaligned" >/dev/null 2>&1 && mv -f "$1.zipaligned" "$1"
	return $?
}

# Zipaligns everything
ZIPALIGN() {
	if [[ "$FULLPERFORMANCE" -eq 1 ]]; then
		find "$ACTIVE_PROJECT/system" -type f -iname "*.apk" | (while read APK; do
			ZIPALIGN_FILE "$APK" &
		done
		wait)
	else
		find "$ACTIVE_PROJECT/system" -type f -iname "*.apk" | while read APK; do
			ZIPALIGN_FILE "$APK"
		done
	fi
	echo
	echo "Zipaligning finished!"
	PRESS_ENTER
}

# Adds or removes ArchiDroid's Init.d
ARCHIDROID_INITD() {
	if [[ ! -f "$ACTIVE_PROJECT/system/bin/debuggerd.real" ]]; then
		mv -f "$ACTIVE_PROJECT/system/bin/debuggerd" "$ACTIVE_PROJECT/system/bin/debuggerd.real"
		cp -R files/archidroid/initd/system/* "$ACTIVE_PROJECT/system/"
		UPDATER_SCRIPT_ADD "files/archidroid/initd/updater-scripts"
	else
		mv -f "$ACTIVE_PROJECT/system/bin/debuggerd.real" "$ACTIVE_PROJECT/system/bin/debuggerd"
		UPDATER_SCRIPT_DEL "files/archidroid/initd/updater-scripts"
	fi
	BUILD_UPDATER_SCRIPT
}

# Adds or removes root
ROOT() {
	if [[ ! -f "$ACTIVE_PROJECT/system/xbin/su" ]]; then
		if [[ -f "$ACTIVE_PROJECT/system/etc/install-recovery.sh" ]]; then
			mv "/system/etc/install-recovery.sh" "/system/etc/install-recovery-2.sh"
		fi
		mkdir -p "$ACTIVE_PROJECT/system/xbin"
		cp -R files/root/system/* "$ACTIVE_PROJECT/system/"
		cp -R "files/root/ARCH/$ARCH/"* "$ACTIVE_PROJECT/"
		cp "$ACTIVE_PROJECT/system/xbin/su" "$ACTIVE_PROJECT/system/xbin/daemonsu"
		mkdir -p "$ACTIVE_PROJECT/system/bin/.ext"
		cp "$ACTIVE_PROJECT/system/xbin/su" "$ACTIVE_PROJECT/system/bin/.ext/.su"
		if [[ -f "$ACTIVE_PROJECT/system/bin/mksh" ]]; then
			cp "$ACTIVE_PROJECT/system/bin/mksh" "$ACTIVE_PROJECT/system/xbin/sugote-mksh"
		else
			cp "$ACTIVE_PROJECT/system/bin/sh" "$ACTIVE_PROJECT/system/xbin/sugote-mksh"
		fi
		cp "$ACTIVE_PROJECT/system/xbin/su" "$ACTIVE_PROJECT/system/xbin/sugote"
		ln -s "/system/xbin/su" "$ACTIVE_PROJECT/system/bin/su"
		ln -s "/system/etc/install-recovery.sh" "$ACTIVE_PROJECT/system/bin/install-recovery.sh"
		UPDATER_SCRIPT_ADD "files/root/updater-scripts"
	else
		if [[ -f "$ACTIVE_PROJECT/system/etc/install-recovery-2.sh" ]]; then
			mv "$ACTIVE_PROJECT/system/etc/install-recovery-2.sh" "$ACTIVE_PROJECT/system/etc/install-recovery.sh"
		else
			rm -f "$ACTIVE_PROJECT/system/etc/install-recovery.sh"
		fi
		rm -f "$ACTIVE_PROJECT/system/bin/su" "$ACTIVE_PROJECT/system/etc/install-recovery.sh" "$ACTIVE_PROJECT/system/app/Superuser.apk" "$ACTIVE_PROJECT/system/xbin/su" "$ACTIVE_PROJECT/system/xbin/daemonsu" "$ACTIVE_PROJECT/system/bin/.ext/.su" "$ACTIVE_PROJECT/system/etc/init.d/99SuperSUDaemon" "$ACTIVE_PROJECT/system/etc/.installed_su_daemon" "$ACTIVE_PROJECT/system/xbin/sugote-mksh" "$ACTIVE_PROJECT/system/xbin/sugote"
		UPDATER_SCRIPT_DEL "files/root/updater-scripts"
	fi
	BUILD_UPDATER_SCRIPT
}

# Debloats or bloats ROM
DEBLOAT() {
	if [[ -d "$ACTIVE_PROJECT/bloatware" ]]; then
		echo "Restoring bloatware..."
		BLACKLIST_CLEAN_RESTORE "bloatware"
		echo "Done, bloatware restored"
	else
		local LINE=""
		while [[ -z "$LINE" ]]; do
			PRINT_BANNER
			echo "Before you begin debloating you should specify which cleaning list you want to use"
			echo
			echo "Currently available cleaning lists:"
			PRINT_LINE
			find "files/bloat" -mindepth 1 -maxdepth 1 -type d | sort | while read line; do
				basename "$line"
			done
			PRINT_LINE
			echo
			echo "Type any of detected lists above or 'x' to abort"
			read -p "Your list: " LIST
			PRINT_LINE
			if [[ "$LIST" = "x" ]]; then
				return
			fi
			if [[ ! -d "files/bloat/$LIST" ]]; then
				echo "Wrong selection"
				LINE=""
				PRESS_ENTER
			else
				BLACKLIST_REMOVE "bloat/$LIST"
				BLACKLIST_CLEAN "bloat/$LIST" "bloatware"
				PRESS_ENTER
				return
			fi
		done
	fi
	PRESS_ENTER
}

# Adds or removes busybox
BUSYBOX() {
	if [[ ! -f "$ACTIVE_PROJECT/system/xbin/busybox" ]]; then
		PRINT_BANNER
		echo "Busybox is a core provider for many standard GNU/Linux utilities"
		echo "Here you can specify which busybox you want to add"
		echo "Stericson's busybox is proven to be stable and work well on stock ROMs with no busybox"
		echo "On the other hand, CyanogenMod's busybox is more actively developed"
		echo
		echo "Please note that:"
		echo "* CyanogenMod's busybox doesn't work on x86 architecture. If you're cooking ROM for such device, stick with stericson's"
		echo "* CyanogenMod's busybox requires your device to be NEON-capable, typically CortexA9 and newer devices on armv7l"
		echo
		echo "If you don't know what to choose here, I strongly suggest to stick with stericson"
		PRESS_ENTER
		PICK_ONE "files/busybox/busybox"
		if [[ -z "$PICKCHOICE" ]]; then
			return 0
		fi
		cp -R "files/busybox/busybox/$PICKCHOICE/ARCH/$ARCH/"* "$ACTIVE_PROJECT/"
		ln -s "/system/xbin/busybox" "$ACTIVE_PROJECT/system/bin/busybox"
		if [[ -d "files/busybox/busybox/$PICKCHOICE/system" ]]; then
			cp -R "files/busybox/busybox/$PICKCHOICE/system/"* "$ACTIVE_PROJECT/system/"
		fi
		UPDATER_SCRIPT_ADD "files/busybox/updater-scripts"
	else
		rm -f "$ACTIVE_PROJECT/system/bin/busybox" "$ACTIVE_PROJECT/system/xbin/busybox"
		UPDATER_SCRIPT_DEL "files/busybox/updater-scripts"
	fi
	BUILD_UPDATER_SCRIPT
}

# Removes KNOX
REMOVE_KNOX() {
	echo "Removing KNOX..."
	BLACKLIST_REMOVE "knox"
	echo "Done, your ROM should not contain any KNOX apps/folders anymore"
	PRESS_ENTER
}

# Adds or removes insecure ADB
ADB() {
	if [[ -d "$ACTIVE_PROJECT/kernel/boot.img-ramdisk" ]]; then
		if [[ "$(grep -qi "ro.adb.secure=1" "$ACTIVE_PROJECT/kernel/boot.img-ramdisk/default.prop"; echo $?)" -eq 0 ]]; then
			SED_CHANGE_WORD "ro.adb.secure=1" "ro.adb.secure=0" "$ACTIVE_PROJECT/kernel/boot.img-ramdisk/default.prop"
			SED_CHANGE_WORD "ro.secure=1" "ro.secure=0" "$ACTIVE_PROJECT/kernel/boot.img-ramdisk/default.prop"
		else
			SED_CHANGE_WORD "ro.adb.secure=0" "ro.adb.secure=1" "$ACTIVE_PROJECT/kernel/boot.img-ramdisk/default.prop"
			SED_CHANGE_WORD "ro.secure=0" "ro.secure=1" "$ACTIVE_PROJECT/kernel/boot.img-ramdisk/default.prop"
		fi
	fi
}

# Prints banner
PRINT_BANNER() {
	clear
	echo "    _             _     _ _  ___ _       _"
	echo "   / \   _ __ ___| |__ (_) |/ (_) |_ ___| |__   ___ _ __"
	echo "  / _ \ | '__/ __| '_ \| | ' /| | __/ __| '_ \ / _ \ '_ \\"
	echo " / ___ \| | | (__| | | | | . \| | || (__| | | |  __/ | | |"
	echo "/_/   \_\_|  \___|_| |_|_|_|\_\_|\__\___|_| |_|\___|_| |_|"
	echo
	echo "Developed by JustArchi"
	echo "Original thread: $XDALINK"
	PRINT_LINE
}

# Prints status of the project
PRINT_PROJECT_STATUS() {
	ALLFINE=1
	if [[ -d "$ACTIVE_PROJECT/kernel" ]]; then
		ALLFINE=0
		echo "WARNING: Unpacked kernel found"
	fi
	if [[ ! -f "$ACTIVE_PROJECT/boot.img" ]]; then
		ALLFINE=0
		echo "WARNING: No boot.img found, ROM will not boot properly"
	fi
	if [[ ! -d "$ACTIVE_PROJECT/META-INF" ]]; then
		ALLFINE=0
		echo "WARNING: No META-INF folder found, this is not a ROM"
	fi
	echo -n "Project status: "
	if [[ "$ALLFINE" -eq 1 ]]; then
		echo "OK"
	else
		echo "WARNING"
	fi
	PRINT_LINE
}

# Prints status of the ROM
PRINT_ROM_STATUS() {
	echo -n "Architecture: ["
	if [[ "$ARCH" = "unknown" && -f "$ACTIVE_PROJECT/system/build.prop" ]]; then
		ARCH="$(grep -i "ro.product.cpu.abi=" "$ACTIVE_PROJECT/system/build.prop" | head -n 1 | cut -d'=' -f2)"
	fi
	echo "$ARCH]"
	echo

	echo -n "ArchiDroid Init.d? "
	if [[ ! -f "$ACTIVE_PROJECT/system/bin/debuggerd.real" ]]; then
		echo "[NO]"
	else
		echo "[YES]"
	fi
	echo -n "Debloated? "
	if [[ -d "$ACTIVE_PROJECT/bloatware" ]]; then
		echo "[YES]"
	else
		echo "[NO]"
	fi
	echo -n "Deodexed? "
	if [[ -f "$ACTIVE_PROJECT/system/framework/framework.odex" ]]; then
		echo "[NO]"
	else
		echo "[YES]"
	fi
	echo -n "Zipaligned? "
	if [[ -f "$ACTIVE_PROJECT/system/framework/framework-res.apk" && "$("$ZIPALIGN" -c "$ALIGN" "$ACTIVE_PROJECT/system/framework/framework-res.apk"; echo $?)" -eq 0 ]]; then
		echo "[YES]"
	else
		echo "[NO]"
	fi
	echo -n "Rooted? "
	if [[ ! -f "$ACTIVE_PROJECT/system/xbin/su" ]]; then
		echo "[NO]"
	else
		echo "[YES]"
	fi
	echo -n "Busybox? "
	if [[ ! -f "$ACTIVE_PROJECT/system/xbin/busybox" ]]; then
		echo "[NO]"
	else
		echo "[YES]"
	fi
	echo -n "KNOX? "
	if [[ -f "$ACTIVE_PROJECT/system/app/KNOXAgent.apk" ]]; then
		echo "[YES]"
	else
		echo "[NO]"
	fi
	if [[ -d "$ACTIVE_PROJECT/kernel/boot.img-ramdisk" ]]; then
		PRINT_LINE
		echo -n "ADB? "
		if [[ "$(grep -qi "ro.adb.secure=0" "$ACTIVE_PROJECT/kernel/boot.img-ramdisk/default.prop"; echo $?)" -eq 0 ]]; then
			echo "[INSECURE]"
		else
			echo "[SECURE]"
		fi
		echo -n "Kernel Init.d? "
		if [[ "$(grep -qi "sysinit" "$ACTIVE_PROJECT/kernel/boot.img-ramdisk/init.rc"; echo $?)" -eq 0 ]]; then
			echo "[YES]"
		else
			echo "[NO]"
		fi
	fi
	PRINT_LINE
}

# Prints available switches
PRINT_SWITCHES() {
	echo "adi   - Enable/Disable ArchiDroid Init.d (software debuggerd hook)"
	echo "bloat - Bloat/Debloat ROM"
	echo "r     - Enable/Disable Root"
	echo "b     - Enable/Disable Busybox"
	echo "-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-"
	echo "d     - Deodex Everything"
	echo "z     - Zipalign Everything"
	echo "knox  - Remove KNOX"
	echo "-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-"
	if [[ -d "$ACTIVE_PROJECT/kernel/boot.img-ramdisk" ]]; then
		echo "kr    - Repack kernel (apply all ramdisk changes)"
		echo "ka    - Abort repacking (abort all ramdisk changes)"
		echo
		echo "i     - Add Init.d Support (hardware kernel hook)"
		echo "adb   - Enable/Disable insecure ADB"
	elif [[ -f "$ACTIVE_PROJECT/boot.img" ]]; then
		echo "ku    - Unpack kernel (this enables more options!)"
	fi
	echo "-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-"
	echo "bb    - Build ROM (normal suggested mode)"
	echo "bbe   - Build ROM (expert mode, won't make any checks if your project is OK)"
	PRINT_LINE
	echo "ak    - Change ArchiKitchen settings"
	echo "x     - Exit"
	PRINT_LINE
}

# Prints settings of the kitchen
PAGE_SETTINGS() {
	while :; do
		PRINT_BANNER
		echo -n "Full performance: "
		if [[ "$FULLPERFORMANCE" -eq 1 ]]; then
			echo "[YES]"
		else
			echo "[NO]"
		fi
		PRINT_LINE
		echo "Full performance mode tries to finish common ArchiKitchen tasks ASAP"
		echo "This includes i.e. calling all job threads at once and waiting for them to"
		echo "finish instead of calling them one-by-one and blocking main thread"
		echo "Due to that, OS may become unresponsive when ArchiKitchen is performing a task"
		echo "Usually it's a good idea to keep it ON, unless you have a very good reason"
		echo "for forcing ArchiKitchen to run in a single-thread mode"
		PRINT_LINE
		echo "p	- Full performance switch"
		echo "x	- Go back"
		PRINT_LINE
		read -p "CHOICE: " CHOICE
		case "$CHOICE" in
			p|P)
				if [[ "$FULLPERFORMANCE" -eq 1 ]]; then
					FULLPERFORMANCE=0
				else
					FULLPERFORMANCE=1
				fi
				;;
			x|X) return 0
		esac
	done
}

# Auto-update feature of ArchiKitchen
CHECK_UPDATE() {
	if [[ -d ".git" && ! -z "$(which git)" ]]; then
		echo "Auto-update in progress..."
		local GITVERSION="$(git --version | cut -d' ' -f3)"
		if VERSION_LESS_THAN "$GITVERSION" "$NEEDEDGIT"; then
			echo
			echo "WARNING: Your git version is lower than the required!"
			echo "Your git version: $GITVERSION"
			echo "Required git version: $NEEDEDGIT"
			echo "Auto-update feature has been disabled, please update your git to latest version"
			PRESS_ENTER
			return 0
		fi
		echo "Checking network connection..."
		if [[ "$(wget --spider github.com >/dev/null 2>&1; echo $?)" -ne 0 ]]; then
			echo
			echo "WARNING: Could not connect to github.com, probably your network is down"
			echo "Auto-update feature has been disabled"
			PRESS_ENTER
			return 0
		fi
		local REPO="origin"
		local OLDHEAD="$(git rev-parse HEAD)"
		local CURBRANCH="$(git rev-parse --abbrev-ref HEAD)"
		if [[ "$CURBRANCH" != "$GITHUBBRANCH" ]]; then
			echo "You're currently using $CURBRANCH branch, and this is not the default $GITHUBBRANCH branch. Auto-update feature has been disabled"
			PRESS_ENTER
			return 0
		fi
		if [[ "$(git remote | grep -qi "$REPO"; echo $?)" -ne 0 ]]; then
			git remote add -t "$GITHUBBRANCH" -m "$GITHUBBRANCH" "$REPO" "$GITHUBLINK"
		fi
		echo "Fetching current version..."
		git fetch -q "$REPO" "$GITHUBBRANCH"
		local HEAD="$(git rev-parse "$REPO/$GITHUBBRANCH")"
		if [[ ! -z "$HEAD" && "$OLDHEAD" != "$HEAD" ]]; then
			echo "Found new version!"
			echo "Changelog:"
			echo "=========="
			git --no-pager log --abbrev-commit --decorate --date=relative --pretty=format:'%C(bold red)%h%Creset %C(bold green)(%cr)%Creset - %C(bold yellow)%s%Creset %C(bold blue)commited by%Creset %C(bold cyan)%an%Creset' "$OLDHEAD..$HEAD"
			echo # Beacause git log doesn't finish with newline
			echo "=========="
			git pull -q "$REPO" "$GITHUBBRANCH" >/dev/null 2>&1 || (echo; echo "WARNING: ArchiKitchen could not apply update due to conflicts, forced update mode will be used now. Please make proper backups if you need any of your past projects before going to the next step"; PRESS_ENTER; git reset -q --hard; git clean -qfd; git pull -q "$REPO" "$GITHUBBRANCH")
			echo "ArchiKitchen has been updated, it will now restart itself"
			PRESS_ENTER
			exec "$0"
		else
			echo "No new updates found"
			sleep 1
		fi
	fi
}

############################
#   ____ ___  ____  _____  #
#  / ___/ _ \|  _ \| ____| #
# | |  | | | | |_) |  _|   #
# | |__| |_| |  _ <| |___  #
#  \____\___/|_| \_\_____| #
#                          #
############################

PRINT_BANNER
echo "Please wait..."

# Cleaning
unset CROSS_COMPILE # We're not cross-compiling anything here and it may cause problems with some makefiles

# Before we begin, make sure that all our tools are available
if [[ "$(which "${TOOLS[@]}" >/dev/null; echo $?)" -ne 0 ]]; then
	MISSINGTOOLS=""
	for TOOL in "${TOOLS[@]}"; do
		if [[ -z "$(which $TOOL)" ]]; then
			MISSINGTOOLS+=" $TOOL"
		fi
	done
	echo "It looks like you don't have required tool(s):$MISSINGTOOLS"
	echo "This check was made through 'which' command"
	echo "Please install missing tool(s) and launch kitchen again"
	exit 1
fi
echo

# Check LONG_BIT for determining host architecture
HOSTARCH="$(getconf LONG_BIT)"
case "$HOSTARCH" in
	64) HOSTARCH="amd64" ;;
	32) HOSTARCH="i386" ;;
	*) HOSTARCH="amd64" ;; # Unknown, assume amd64
esac

# Set common tools
ZIPALIGN="./$TOOLSDIR/zipalign/$HOSTARCH/zipalign"

# Navigate to our folder, even if user didn't execute it from the root dir
cd "$(dirname "$0")"

# Check if symlink support is present
if [[ "$(ln -s archi archi.ln.test >/dev/null 2>&1; echo $?)" -ne 0 ]]; then
	echo "ERROR: Current kitchen location doesn't support symbolic links!"
	echo "Symbolic links cannot be used on Windows-based filesystems, such as FAT, NTFS, or VirtualBox shared folder mount on one of the previous"
	echo "You must use ArchiKitchen in native Linux location, such as /root, /home/username, /tmp, or any other mountpoint, which supports symbolic links"
	exit 1
else
	rm -f archi.ln.test
fi

# Create our temporary directory
mkdir -p "$TEMPDIR"

# Make sure our tools are executable
# This is only required if user downloaded zip and permissions are broken (f.e. due to moving files from windows => linux)
chmod -R 755 tools

# Parse args
for ARG in "$@"; do
	case "$ARG" in
		"t") AUTOUPDATE="0"; SET_OLDPROJECT ;; # Doesn't check for updates and automatically loads old project, for me to allow faster debugging and testing :)
	esac
done

# Check for updates
if [[ "$AUTOUPDATE" -eq 1 ]]; then
	CHECK_UPDATE
fi

while :; do
	PRINT_BANNER

	if [[ -z "$ACTIVE_PROJECT" ]]; then
		SET_PROJECT
		continue
	fi

	PRINT_PROJECT_STATUS
	PRINT_ROM_STATUS
	PRINT_SWITCHES
	read -p "CHOICE: " CHOICE
	case "$CHOICE" in
		ak|AK) PAGE_SETTINGS ;;
		adi|ADI) ARCHIDROID_INITD ;;
		bloat|BLOAT) DEBLOAT ;;
		r|R) ROOT ;;
		b|B) BUSYBOX ;;

		d|D) DEODEX ;;
		z|Z) ZIPALIGN ;;
		knox|KNOX) REMOVE_KNOX ;;

		i|I) INITD ;;
		adb|ADB) ADB ;;
		ku|KU) KERNEL_EXTRACT ;;
		kr|KR) KERNEL_REPACK ;;
		ka|KA) KERNEL_ABORT ;;
		bbe|BBE) BUILD "EXPERT" ;;
		bb|BB)
			if [[ "$ALLFINE" -eq 1 ]]; then
				BUILD
			else
				echo "ERROR: Can't build ROM in actual status, please check warings above and correct them!"
				PRESS_ENTER
			fi
			;;
		x|X) exit 0
	esac
done

exit 0
