#!/bin/bash

### Linux .jar Update Script for ProfitTrailer
### LAST UPDATED 20 Feb 2020

### Place this script in the root folder where all your individual bot folders are and then execute it.
### For simplicity each ProfitTrailer.jar file should be nested exactly one subfolder.
### Example 
### /var
###     /opt
###         /btc bot
###         /eth bot
###         linux-update.sh
### cd to the directory you have it in e.g cd /var/opt
### execute using ./linux-update.sh to downlaod the latest github release

### OPTIONS ###    ./linux-update.sh option1 option2
### This script can be executed with some optional parameters 
### auto      - automaticlaly upgrade without any confirmation to the latest version
### noupdate  - do not update the script from github
### betaurl   - Enter the url to a profitTrailer Zip file to update to that beta version without confirmation e.g https://domain.com.ProfitTrailer-2.3.2.zip

### INSTALL DEPENDENCIES ###

### Check if unzip is installed ###
if ! [ -x "$(command -v unzip)" ]; then
	echo "Unzip is not installed, Installing now..."
	sudo apt install unzip
	
	if ! [ -x "$(command -v unzip)" ]; then
		echo
		echo "$(tput setaf 1)Something went wrong.... $(tput sgr0)"
		exit
	else
		echo $(tput setaf 2)
		echo "Unzip Installed"
		echo $(tput sgr0)
	fi
fi

### Check if curl is installed ###
if ! [ -x "$(command -v curl)" ]; then
	echo "Curl is not installed, Installing now..."
	sudo apt install curl
	
	if ! [ -x "$(command -v curl)" ]; then
		echo
		echo "$(tput setaf 1)Something went wrong.... $(tput sgr0)"
		exit
	else
		echo $(tput setaf 2)
		echo "Curl Installed"
		echo $(tput sgr0)
	fi
fi

### Set all child processes to this locale language to prevent rev from breaking
export LC_ALL='en_US.UTF-8'

###Get the directory and filename of the script###
DIR=$(dirname "$(readlink -f "$0")")
script=$(basename "$0")

### Update linux-update script unless noupdate option is used###
if [[ ! "$@" == *"noupdate"* ]]; then
	### download update.sh from github. -s silent -O output to a file ###
	curl -s https://raw.githubusercontent.com/taniman/profit-trailer/master/update.sh -O > /dev/null
	### Check if the file is newer ###
	### Get line containing LAST UPDATED (line 4 typically) ###
	### -i ignore case, -m 1 match only first instance ###
	olddate=$(grep -i -m 1 'updated' "$DIR"/"$script")
	newdate=$(grep -i -m 1 'updated' update.sh)
	if [[ ! $olddate == $newdate ]]; then
		mv -f update.sh "$DIR"/"$script" 2>/dev/null
		chmod +x "$DIR"/"$script"
		if [[ ! $1 ]]; then
			exec "$DIR"/"$script"
		else
			exec "$DIR"/"$script" "$@"
		fi
	### Remove the downloaded update.sh if it is not the only copy ###
	elif [[ ! "$script" == "update.sh" ]]; then
		rm -rf update.sh
	fi
	
else
	echo
	echo "Skipped script update"
	sleep 2
	
fi
### Clear screen and print header ###
clear
echo $(tput setaf 3)
echo "##################################################"
echo "          ProfitTrailer Update Script            "
echo "##################################################"
echo $(tput sgr0)

### LOAD PREVIOUS CONFIG ###

### If no previous config can be found enter setup automatically ###
if [ ! -f "$DIR"/updatescript/name.txt ]; then
	skipsetup=N
	echo "$(tput setaf 2)No Previous Setup Found - Entering Setup $(tput sgr0)"
	echo
else
	echo Loading from saved setup...
	echo
	### load arrary of app names/ID/pid saved previously ###
	mapfile -t name < "$DIR"/updatescript/name.txt
	for i in $(seq ${#name[*]}); do
		[[ ${name[$i-1]} = $name ]]
	done
	
	### count number of instances in the arrary (exclude header by subtracting 1) ###
	PTinstances="$((${#name[@]}-1))"
	
	### load arrary of paths saved previously ###
	mapfile -t path < "$DIR"/updatescript/path.txt
	for ((i=1; i<=PTinstances; i++)); do
		[[ ${path[$i-1]} = $path ]]
		### check that the directories actually exist and an empty string is not provided ###
		if [[ -d "${path[$i]}" ]] && [[ -n "${path[$i]}" ]]; then
		continue
		else
			echo "$(tput setaf 1)Path for instance $i does no exist. Setup required. $(tput sgr0)"
			skipsetup=N
		fi
	done
	
	if [[ ! $skipsetup == "N" ]]; then
		### print out the arrays as a table for user to check ###
		### pad the columns by 8 places for legibility %-8s\n ###
		echo "$(tput setaf 6)Your current configuration is: $(tput sgr0)"
		paste <(printf "%-8s\n" "${name[@]}") <(printf "%-8s\n" "${path[@]}")
		if [[ "$@" == *"auto"* || "$@" == *"ProfitTrailer"* ]]; then
			skipsetup=Y
		else
			echo
			read -p "Do you wish to proceed with this configuration? (Y/N) " skipsetup
		fi
	fi
fi

### SETUP ###
clear
if [[ $skipsetup == "n" ]] || [[ $skipsetup == "N" ]]; then

	### Set proceed variable to No, causing loop until user confirms proceed later ###
	proceed=N

	echo $(tput setaf 3)
	echo "##################################################"
	echo "                      Setup"
	echo "##################################################"
	echo $(tput sgr0)
	
	while [[ $proceed == "N" ]] || [[ $proceed == "n" ]]; do
		### wipe arrays clean then set the header for each array ###
		name=()
		path=()
		name[0]=Name/ID
		path[0]=Path
		
		### show user their current pm2 instances to assist with setup ###
		pm2 list
		echo
		read -p "How many ProfitTrailer Bots do you want to update? " PTinstances
		echo
		### ask user for the name and path of each instance they wish to update ###
		for ((i=1; i<=$PTinstances; i++)); do
			### use the lack of profittrailer.jar to loop through setup.
			while [[ ! -f "${path[$i]}"/ProfitTrailer.jar ]]; do
				read -p "What is the PM2 App name/ id for instance $i? " newname
				### use grep, sed and cut to find the field the pm2 process path is in. Future PM2 updates might break this and need changing ###
				rename=$(pm2 info "$newname" | grep 'exec cwd' | sed -n '1p' | cut -d '/' -f 2-)
				### remove any leading or trailing spaces or tabs and also column bars from pm2 output by reversing and cutting ###
				nowhitespace=$(echo "$rename" | xargs | rev | cut -d ' ' -f 2- | rev )
				path[$i]=/"$nowhitespace"
				
				### if user entered only a number (pm2 ID) store the app name instead.	###
				### dunno why but if you alter the below echo and then structure it literally breaks the if statement ###
				if [[ $newname =~ "^[0-9]+$" ]]
				echo
				then
					### use grep, sed and cut to find the field the pm2 process name is in. Future PM2 updates might break this and need changing ###
					rename=$(pm2 info "$newname" | grep 'name' | sed -n '1p' | cut -d ' ' -f 9-)
					### remove any leading or trailing spaces or tabs ###
					nowhitespace=$(echo "$rename" | xargs)
					name[$i]=$nowhitespace
				fi

				### If no directory exists for the given pm2 process or nothing is entered, ask again ###
				if [[ ! -d "${path[$i]}" ]] || [[ -z "${path[$i]}" ]]; then
					echo "$(tput setaf 1)Path for instance $i does not exist. Try again... $(tput sgr0)"
				### If the directory does not contain the ProfitTrailer.jar file, confirm intentions ###
				elif [[ ! -f "${path[$i]}"/ProfitTrailer.jar ]]; then
					read -p "$(tput setaf 1)Path for instance $i (${path[$i]}) does not contain ProfitTrailer.jar. Do you wish to use it anyway? (Y/N) $(tput sgr0)" empty
					if [[ $empty == "y" ]] || [[ $empty == "Y" ]] || [[ $empty == "yes" ]] || [[ $empty == "Yes" ]]; then
						break	
					fi
				fi
			done
		done
		
		### print out the arrays as a table for user to check ###
		### %-8s pads the columns to make it appear correctly ###
		echo "$(tput setaf 6)The configuration entered is: $(tput sgr0)"
		paste <(printf "%-8s\n" "${name[@]}") <(printf "%-8s\n" "${path[@]}")
		echo
		read -p "Is this correct? (Y/N) " proceed
		echo
		
		### If something else is entered ask for a new answer ### 
		while [[ ! $proceed == "y" ]] && [[ ! $proceed == "Y" ]] && [[ ! $proceed == "n" ]] && [[ ! $proceed == "N" ]]; do
			echo Please Try Again...
			read -p "Is this correct? (Y/N) " proceed
			echo
		done


		if [[ $proceed == "Y" ]] || [[ $proceed == "y" ]]; then
			### optional step to save the setup for next time ###
			read -p "Do you wish to save this setup? (Y/N) " savetofile
			
			### If something else is entered ask for a new answer ### 
			while [[ ! $savetofile == "y" ]] && [[ ! $savetofile == "Y" ]] && [[ ! $savetofile == "n" ]] && [[ ! $savetofile == "N" ]]; do
			echo Please Try Again...
			read -p "Do you wish to save this setup? (Y/N) " savetofile
			echo
			done
			
			if [[ $savetofile == "Y" ]] || [[ $savetofile == "y" ]]; then
				### create the folder for the config if necessary ###
				mkdir -p "$DIR"/updatescript
				### print each array to a file, one element per row ###
				printf "%s\n" "${name[@]}" > "$DIR"/updatescript/name.txt
				printf "%s\n" "${path[@]}" > "$DIR"/updatescript/path.txt
				echo $(tput setaf 2)
				echo Configuration Saved
				echo $(tput sgr0)
			else
				echo $(tput setaf 2)
				echo Configuration Not Saved
				echo $(tput sgr0)
			fi
		else
			echo $(tput setaf 3)
			echo Starting setup again... 
			echo $(tput sgr0)
		fi
	done

elif [[ ! $skipsetup == "y" ]] && [[ ! $skipsetup == "Y" ]]; then
	echo $(tput setaf 1)
	echo Process Aborted.... 
	echo $(tput sgr0)
	exit
fi

### DOWNLOAD AND INSTALL ###

### Get latest Version number
latest=$(curl -s https://api.github.com/repos/taniman/profit-trailer/releases | grep tag_name | cut -d '"' -f 4 | sed -n '1p')
current=$(unzip -p "${path[1]}"/ProfitTrailer.jar  META-INF/MANIFEST.MF | grep Implementation-Version | cut -d ' ' -f 2)
url=$(curl -s https://api.github.com/repos/taniman/profit-trailer/releases | grep browser_download_url | cut -d '"' -f 4 | sed -n '1p')

### Break the current version into SemVer segments ###
IFS='.' read -a version_parts <<< "$current"
major=${version_parts[0]}
minor=${version_parts[1]}
### Strip Beta Version if required ###
patch=$(echo ${version_parts[2]} | cut -d '-' -f 1)

clear
echo $(tput setaf 3)
echo "##################################################"
echo "                      Update"
echo "##################################################"
echo $(tput sgr0)
echo
echo " The current version is $(tput setaf 6) $current $(tput sgr0)"
echo " Latest release is version $(tput setaf 6) $latest $(tput sgr0)"


if ! [[ "$@" == *"auto"* || "$@" == *"/ProfitTrailer-"* ]]; then
	echo
	echo "Please select an option below: (1-7)"


	### Loop through the selection menu until a valid version and url is found ###
	while [[ $exists == *"404 Not Found"* ]] || [[ -z $exists ]]; do
		
		if [[ $major == "2" ]] && [[ $minor == "2" ]] && [[ ! $patch == "12" ]]; then
			echo $(tput setaf 3)
			echo "CAUTION!"
			echo "You need to update to 2.2.12 and run the bot before updating to $latest"
			echo $(tput sgr0)
			echo "Select Choose Specific Version (5) from the options below and enter 2.2.12 when prompted"
		elif [[ $major == "2" ]] && [[ $minor == "1" ]] && [[ ! $patch == "30" ]] || [[ $major == "2" ]] && [[ $minor == "0" ]]; then
			echo $(tput setaf 3)
			echo "CAUTION!"
			echo "You need to update to 2.1.30 and run the bot before updating to $latest"
			echo $(tput sgr0)
			echo "Select Choose Specific Version (5) from the options below and enter 2.1.30 when prompted"
		fi	
		
		### Use options menu to select the version number of the desired download. Also allow Beta Url to be entered ###
		options=("Latest Release" "Increment Major Version" "Increment Minor Version" "Increment Patch Version" "Choose Specific Version" "Beta Patch" "Exit")
		select opt in "${options[@]}"
		do
			case "$opt" in
				"Latest Release")
					version=$latest
					break
					;;
				"Increment Major Version")
					newmajor=$((major + 1))
					version="$newmajor.0.0"
					break
					;;
				"Increment Minor Version")
					newminor=$((minor + 1))
					version="$major.$newminor.0"
					break
					;;
				"Increment Patch Version")
					newpatch=$((patch + 1))
					version="$major.$minor.$newpatch"
					break
					;;
				"Choose Specific Version")
					### Regex for x.x.x ###
					rx='^([0-9]+\.){2}(\*|[0-9]+)$'
					read -p "Please enter the version you wish to update to: " version
					while [[ ! $version =~ $rx ]]; do
						echo "Enter the version number in the format (x.x.x)"
						read -p "Please enter the version you wish to update to: " version
						echo
					done
					break
					;;
				"Beta Patch")
					echo 
					read -p "Enter the full url to the Beta Zip file: " download
					echo
					version=$(echo $download | rev | cut -d'/' -f 1 | rev | sed 's/\(.*\).zip/\1/' | sed 's/\(.*\).jar/\1/' | rev | sed 's/\(.*\)-reliarTtiforP/\1/' | rev)
					break
					;;
				"Exit")
					echo $(tput setaf 1)
					echo Process Aborted.... 
					echo $(tput sgr0)
					exit
					;;
			esac
		done
		
		### If the download URL was not set (Beta patch) set it now and adjust it if necessary for the selected version ###	
		if [ -z "$download" ]; then
			download=${url//$latest/$version}
		fi

		### get the http status of the url to determine if it is a real link or not ###
		exists=$(curl -Is $download | head -1)
		if [[ $exists == *"404 Not Found"* ]]; then
			download=
			echo $(tput setaf 1)
			echo "Download URL for $version does not exist or is not reachable."
			echo $(tput sgr0)
			echo "Please select an option below: (1-7)"
		fi
	done

	echo
	echo " Updating to version $(tput setaf 6) $version $(tput sgr0)"
	echo
	read -p "Do you want to continue? (Y/N) " continue
	echo

	### If something else is entered ask for a new answer ### 
	while [[ ! $continue == "y" ]] && [[ ! $continue == "Y" ]] && [[ ! $continue == "n" ]] && [[ ! $continue == "N" ]]; do
		echo Please Try Again...
		read -p "Do you want to continue? (Y/N) " continue
		echo
	done
### If auto parameter or beta url was used as an argument, skip the menu and update to the latest release ###
else
	continue=Y
	version=$latest
	for arg in "$@"; do
		if [[ $arg == *"http"* ]]; then
			download=$arg
			version=$(echo $download | rev | cut -d'/' -f 1 | rev | sed 's/\(.*\).zip/\1/' | sed 's/\(.*\).jar/\1/' | rev | sed 's/\(.*\)-reliarTtiforP/\1/' | rev)
		fi	
	done
	echo
	secs=$((10))
	while [ $secs -gt 0 ]; do
	   echo -ne " Updating to version $(tput setaf 6)$version$(tput sgr0) in $secs\033[0K seconds...\r"
	   sleep 1
	   : $((secs--))
	done
fi	

if [[ $continue == "y" ]] || [[ $continue == "Y" ]]; then
   
	### Download & extract latest version of PT ###
	echo
	echo "$(tput setaf 2) === Downloading ProfitTrailer $version === $(tput sgr0)"
	### -q for quiet to minimise output but --progress-bar to give us a progress bar ###
	curl $download -L -O --progress-bar
	echo
	echo "$(tput setaf 2) === Extracting download === $(tput sgr0)"
	### unzip the jar file only from the zip. -q for quiet, -j to prevent extracting directories ###
	unzip -q -j -o ProfitTrailer-$version.zip '*jar'
	
	### Set loc variable to No, If user ends up running this script from within a Bot folder we wont delete their jar file ###
	loc=N
	
	### Stop each BOT and Copy ProfitTrailer.jar to each instance, then restart it ###
	for ((i=1; i<=PTinstances; i++)); do

		### Get the current status of the process ####
		status=$(pm2 info "${name[$i]}" | grep 'status' | sed -n '1p' | cut -d '/' -f 2-)
		
		### If the user is running this script inside their bots folder we avoid deleting the jar during cleanup ###
		if [[ $DIR == "${path[$i]}" ]]; then
			loc=Y
		fi

		echo
		echo "$(tput setaf 2) === Stopping ${name[$i]} === $(tput sgr0)"
		pm2 stop "${name[$i]}"
		echo
		echo "$(tput setaf 2) === Replacing jar file === $(tput sgr0)"
		cp ProfitTrailer.jar "${path[$i]}"
		mkdir -p "$DIR"/updatescript/"$(date +%m%d_%H%M)"/"${name[$i]}"
		cp "${path[$i]}"/data/ptdb.db "$DIR"/updatescript/"$(date +%m%d_%H%M)"/"${name[$i]}"/ptdb.db
		echo
		echo "$(tput setaf 2) === Restarting ${name[$i]} === $(tput sgr0)"

		### Reload only if process was online ###
		if [[ $status = *online* ]]; then
			pm2 reload "${name[$i]}"
			echo "$(tput setaf 2) === Pausing 30 seconds while ${name[$i]} loads === $(tput sgr0)"
			sleep 30
		fi
	done
#clear			
	### Remove downloaded Files ###
	echo
	echo "$(tput setaf 2) === Cleaning up === $(tput sgr0)"
	
	if [[ $loc == "Y" ]]; then
		rm -rf ProfitTrailer-$version*.zip
	else
		rm -rf ProfitTrailer-$version*.zip ProfitTrailer.jar
	fi
	
	### Remove all but the 5 most recent backups ###
	if [ "$(ls -ld "$DIR"/updatescript/* | wc -l)" -gt 5 ]
	then
		ls -dt "$DIR"/updatescript/*/ | tail -n +6 | xargs -d "\n" rm -r
		echo "Removed old backups from updatescript folder."
	fi

	echo $(tput setaf 3)
	echo "##################################################"
	echo "     Finished updating to ProfitTrailer $version"
	echo "##################################################"
	echo $(tput sgr0)
	
	### Present a summary of pm2 at the end ###
	pm2 status
	echo       
else
	echo $(tput setaf 1)
	echo Process Aborted.... 
	echo $(tput sgr0)
	exit
fi
