#!/bin/bash

#  backup MM modules  config


base=$HOME/MagicMirror
saveDir=$HOME/MM_backup
default_user=temp
user_name=$default_user
email=$user_name@somemail.com
default_email=$email
logfile=$base/installers/backup.log
push=false

# is this a mac
mac=$(uname -s)

if [ $mac == 'Darwin' ]; then
	cmd=greadlink
else
	cmd=readlink
fi
msg_prefix='updating'
#script_dir=$(dirname $($cmd -f "$0"))

#OPTIND=1 # Reset if getopts used previously
remote=
next_tagnumber=1

beginswith() {
  l=$(expr length "$2")
  leading="${1:0:$l}"
	case $2 in
		$leading):
			true
			;;
		*):
		  false
		  ;;
	esac

}

check_for_push(){
	if [ $push == true ]; then
		if [ "$repo." == "." ]; then
			# repo not connected to git
				if [ "$reponame." == "." ]; then
					echo to push, we need the repo name | tee -a $logfile
					echo see the help for the -r parm
					exit 2
				else
					if [ "$user_name" != $default_user ]; then
						cd $saveDir
						echo adding the git repmote https://github.com/$user_name/$reponame.git | tee -a $logfile
						git remote add origin https://github.com/$user_name/$reponame.git
						cd -
					else
						echo "you requested to push the local backup repository to github, but didn't specify the username" | tee -a $logfile
						exit 3
					fi
				fi
		else
			if [ "$(cd $saveDir && git config user.email)." == "." -a "$user_name" == $default_user ]; then
				echo  we will need the github userid | tee -a $logfile
				echo see the help for the -u parm
				exit 3
			else
				if [ "$(cd $saveDir && git config user.email)." == "." -a "$email." == $default_email ]; then
					echo   we will need the github user email | tee -a $logfile
					echo see the help for the -e parm
					exit 4
				fi
			fi
		fi
	else
		# if not push, but repo specified
		if [ "$repo." != "." ]; then
			echo "you specified a github repository name , but didn't request push" | tee -a $logfile
			read -p "do you want to save the results of this backup to github now? (Y/n)?" choice
			choice="${choice:-Y}"
			choice=${choice,,}
			echo user selection for push now is $choice >>$logfile
			if [ $choice == "y" ]; then
				push=true
				check_for_push
			fi
		fi
	fi

}

process_args(){
local OPTIND

#r=${1:0:1}
#echo "$r='$r'"
#if [ "$r." != '-.' ]; then
#echo "Illegal option '$1'"
	#exit 3
#fi
while getopts ":hs:b:m:r:u:e:p" opt
do
    case $opt in
    	# help

	   	 h)	echo
			echo $0 takes optional parameters
			echo
			echo -e "\t -s MagicMirror_dir"
			echo -e	"\t\tdefault $base"
			echo
			echo -e "\t -b backup_dir "
			echo -e	"\t\tdefault $saveDir"
			echo
			echo -e "\t -m backup message "
			echo -e	"\t\t any message (in quotes) that you would like to attach to this change for later info"
			echo -e	"\t\tdefault none"
			echo
			echo -e "\t -p auto push to github (will need repo name, username,  user password or token"
			echo -e	"\t\tdefault false"
			echo
			echo -e "\t -r github repository name (reponame)"
			echo -e	"\t\ttypically https://github.com/username/reponame.git"
			echo -e	"\t\tdefault output of git remote -v (if set)"
			echo -e "\t\t -r overrides the git remote setting"
			echo
			echo -e "\t -u github username"
			echo -e	"\t\tdefault none"
			echo
			echo -e	"\t\tdefault none"
			exit 1
	 	;;
    		s)
		# source MagicMirror folder
      			b=$(echo $OPTARG | xargs)
			if [ -d $HOME/$b ]; then
				base=$HOME/$b
			else
				if [ -d $b ]; then
					base=$b
				else
					echo unable to find Source folder $OPTARG | tee -a $logfile
					exit 2
				fi
			fi
			logfile=$base/installers/backup.log
			echo source MagicMirror folder is $base | tee -a $logfile
    		;;
    		b)
		# backup folder
		  full_path=false
		  b=$(echo $OPTARG | xargs)
		  if [ "$b." != "." ]; then
			  if beginswith "$b" "/"; then
			  	full_path=true
			  fi
				if [ -d $HOME/$b -a $full_path == false ]; then
					saveDir=$HOME/$b
				else
					echo checking for backup folder $b | tee -a $logfile
					if [ -d $b ]; then
						echo backup folder $b exists | tee -a $logfile
						saveDir=$b
					else
						if [ $full_path == false ]; then
							echo folder doesn\'t exist, creating backup folder $HOME/$b | tee -a $logfile
		 					saveDir=$HOME/$b
		 				else
		 					echo folder doesn\'t exist, creating backup folder $b | tee -a $logfile
		 					saveDir=$b
		 				fi
					fi
				fi
				echo backup folder is $saveDir | tee -a $logfile
			else
				echo no folder was specified for backup | tee -a $logfile
				exit 4
			fi
    		;;
   		m)
			# message on the git tag
			msg=""
			mparm=${@:$OPTIND}
			if [[ ${mparm:0:1} != "-" ]];then
	        		msg=$(echo ${@:$OPTIND}| cut -d' ' -f1)
	        		OPTIND=$((OPTIND+1))
			fi
    		;;
    		r)
			# github repo name or url
			repo=$OPTARG
			# check for fulll url specified, we only want the name
			IFS='/'; repoIN=($OPTARG); unset IFS;
			# if there were slashes
			if [ ${#repoIN[@]} -gt 1 ]; then
				# get the last element of split array
				index=${#repoIN[@]}
				# get the  name
				repot=${repoIN[$((index -1))]}
				# user is one array element earlier
				# get the user name from the URL
				useru=${repoIN[$(($index-2))]}
				# check for '.git'
				IFS='.'; repoN=($repot); unset IFS;
				# get just the name
				reponame=${repoN[0]}

				# if we already processed the -u parm
				if [ $user_name != $default_user ]; then
					# and the url username is not the same
					if [ $useru != $user_name ]; then
						echo "username specified with -u $user_name doesn't match the user in the github repo $useru, aborting" | tee -a $logfile
						exit 6
					fi
				else
					# no -u parm, taken from repo url
					user_name=$useru
				fi
			else
				repo_name=$(echo $repo | tr -d [[:blank:]])
			fi
		;;
    	p)
			# push requested
			push=true
			# ignore the repo name , get the one from the save folder, if the folder exists and remote is set
			if [ -d $saveDir ]; then
				configured_repo=$(cd $saveDir 2>/dev/null && git remote -v 2>/dev/null| grep fetch -m1 | awk '{print $2}')
				if [ "$configured_repo." != "." ]; then
					repo=$configured_repo
					reponame=$repo
				fi
			fi
		;;
		u)
			# username
			#echo username=$OPTARG
			user_name=$(echo $OPTARG | tr -d [:blank:])
		;;
		e)
			# email
			email=$OPTARG
		;;
		    \?) echo "Illegal option '-$OPTARG'"  && exit 3
	 ;;
    esac
done
 shift $((OPTIND-1))
}

# if this script was started directly then arg0 is 'mm_backup.sh', else it is the first argument provided (oops) 
if [[ "$0" == *.sh ]]; then 
  process_args "$@"
else
  if [ $# -ge 1 ]; then 
  	process_args "$0 $@"
  else
    process_args "$0"
  fi
fi

date +"backup starting  - %a %b %e %H:%M:%S %Z %Y" >>$logfile

if [ ! -d $saveDir ]; then
	echo creating $saveDir | tee -a $logfile
	mkdir $saveDir 2>./make_error
	if [ $? -eq 0 ]; then
		cd $saveDir
		git init &>/dev/null
		git symbolic-ref HEAD refs/heads/main
		cd - >/dev/null
		msg_prefix='creating'
	else
		echo unable to create $saveDir $(cat ./make_error)
		rm ./make_error
		exit 1
	fi
else
	if [ ! -d $saveDir/.git ]; then
		echo using $savedir | tee -a $logfile
		cd $saveDir
		echo "creating local git repo" | tee -a $logfile
		# create local repo
		git init &>/dev/null
		git symbolic-ref HEAD refs/heads/main
		cd - >/dev/null
	fi
fi
check_for_push

repo_list=$saveDir/module_list

echo $msg_prefix folder $saveDir | tee -a $logfile
#copy config.js
cp -p $base/config/config.js $saveDir
# copy custom.css, no error if not found
cp -p $base/css/custom.css $saveDir 2>/dev/null


	SAVEIFS=$IFS   # Save current IFS
#if [ $mac != 'Darwin' ]; then	
	IFS=$'\n'
#else  
#    IFS=
#fi 
# get the installed module list
# split putput on new lines, not spaces
modules=($(find $base/modules -maxdepth 1 -type d | grep -v default | xargs -I % echo "%"))
echo $modules 

# if there is a modules list, erase it, creating new
if [ ${#modules[@]} -gt 0 ]; then
	if [ -e $repo_list ]; then
		echo will create new $repo_list | tee -a $logfile
		rm $repo_list >/dev/null
		touch $repo_list
	fi

	# loop thru the modules discovered
	for module in "${modules[@]}"
	do
		# if its not the base modules folder
		if [ "$module" != "$base/modules" ]; then

			# change to the that module folder
			cd "$module"
			    echo Backing up for $module | tee -a $logfile
				# if it has a git repo, then it was cloned
				if [ -d ".git" ]; then
					# get the remote repo url
				    repo1=$(git remote -v | grep fetch -m1 | awk '{ print $2}')
				    # just the module name, not the path
				    mname=$(echo $module |awk -F/ '{print $NF}')
				    if [[ "$repo1" == *"$mname"* ]]; then
					    echo -e "found module $mname \n\t installed from $repo1" | tee -a $logfile
						r=$(curl --head -L --silent --write-out "%{http_code}" --output /dev/null $repo1)
						if [ $r -eq 200 ]; then 
							# save it to the file
							echo $repo1 >>$repo_list
							cd $module
							exclude=""
							if [ -e "ls_exclude" ]; then
							  exclude="-X ls_exclude"
							fi  
							#IFS=$'\n'
							#untracked=$(git ls-files $exclude --other | grep -v / | grep -v package-lock.json | grep -v package.json| grep -v node_modules)
							untracked=($(git add -A -n | grep -v node_modules/ | grep -v .git/ | grep -v package-lock.json | grep -v package.json | grep -v install.log| grep add | awk '{print $2}'| tr -d "'" | xargs -I % echo "%"))

							if [ "$untracked." != "." ]; then
							    echo untracked files for module $module = "$untracked" >> $logfile
								# if the folder doesn't exist
								if [ ! -d $saveDir/$mname ]; then
									# create it.
									mkdir $saveDir/$mname 2>/dev/null
								fi
								# copy the untracked(extra)  files to the backup for this module
								for f in "${untracked[@]}"
								do
								   # if the file path has a slash, there is a directory
								   if echo "$f" | grep -q "/"; then
								      #  loop thru and create the directories too, then copy
								      dirname $f | while read path;do mkdir -p "$saveDir/$mname/$path"; done && cp -p $f $saveDir/$mname/$f
								   else
								   	  # just a file, copy it
									  cp -p $f $saveDir/$mname
								   fi								   
								done 

							else
								echo -e "\e[91m module $repo cloned to unique folder name $mname not backed up \e[90m"
							fi														
							cd - >/dev/null
						else 
							echo remote URL not found $repo1 | tee -a $logfile
						fi
						# reset the echo ansi code back to default						
						tput init 2>/dev/null
						echo
				    fi
				else
           			    echo -e "\e[91m module $module was not cloned from github, so no link can be saved, not backed up \e[90m"
			            tput init 2>/dev/null
				    echo
				fi
			# back to the current folder
			cd - >/dev/null
		fi
	done
	if [ -e $repo_list ]; then 
		savefile=temp
		cat $repo_list | sort -t/ -k5 >$savefile
		rm $repo_list
		mv $savefile $repo_list
	fi 
	#if [ $mac != 'Darwin' ]; then
		IFS=$SAVEIFS
	#fi
fi

cd $saveDir
# check for local info on username  email so commits work
#  get the git userid , if any
if [ "$(git config user.email)." == "." ]; then
	# git info not set
	if [ "$user_name." == "." ]; then
		# prompt for users name
		git config --local user.name $user_name
	else	
		git config --local user.name $user_name
	fi
	if [ "$email." == "." ]; then
		# prompt for email address
		git config --local user.email $email
	else
		git config --local user.email $email
	fi
#else
#	echo no  user name or email set, required to save changes to git, please see the -u and -e parameters | tee -a $logfile
#	exit 3
fi

# add all the changed files
git add .
# commit them to the local repo
git commit -m "updated on $(date) $msg"
	# check for any new named tags
	#last_tag=$(git tag | grep -v origin | sort -nr | head -n1)
	# last_tag=$(git for-each-ref --sort=creatordate --format '%(refname)'  | grep tags | grep -v - | awk -F/ {'print $3'} | sort -r -g | head -n1)
	# if we found some then we have the highest number
	#if [ "$last_tag." != "." ]; then
  #	next_tagnumber=$((last_tag+1))
	#fi
	# lets check  rename any old date named tags
	if [ $mac != 'Darwin' ]; then
		SAVEIFS=$IFS   # Save current IFS
		IFS=$'\n'
	fi
	# get the last local tag
	last_local_tag=$(git tag |  sort -nr | head -n1)
	# get the last remote tag
	if [ $(git remote -v | grep -m1 origin) ]; then 
		remote_tag=$(git ls-remote --tags origin | grep -v "{}" | tr '/' ' ' | sort -k 4nr | head -n1 | awk '{print $NF}')
		# if they are not equal
		if [ "$last_local_tag" != "$remote_tag" ]; then
			# tags are not equal, host wins
			# is remote not set
			if [ "$remote_tag." != "."  ]; then
					next_tagnumber=$remote_tag
			else
			# if local not set
				if [ "$last_local_tag." != "." ]; then
						next_tagnumber=$last_local_tag
				else
						next_tagnumber=0
				fi
			fi
		else
			echo tags match >>$logfile
			next_tagnumber=$last_local_tag
			# if tag numbers are equal, nothing to do
		fi
	else 	
	  next_tagnumber=$last_local_tag
	fi
	# increment to next
	next_tagnumber=$((next_tagnumber+1))

# set the tag use the message
git tag -a $next_tagnumber -m "backup on $(date) $msg"
echo backup completed, see the git repo at $saveDir| tee -a $logfile
remote=false
# should we push now?
if [ "$push." == "." ]; then
	# no, tell user to do it
	echo "because you didn't request push"
	echo recommended you "git push --tags" from this folder \($saveDir\) to backup your repo on github | tee -a $logfile
	echo see "https://github.com/new"
	echo to learn how to create a repo on github and the commands to sync your local system to the github repo
else
	# yes push
	cd $saveDir
	# did they specify the repo
	if [ "$reponame."  != "." ]; then
		remote=true
		# no, is it set already?
		repo=$(git remote -v 2>/dev/null| grep fetch -m1 | awk '{ print $2}')
		# no, need to prompt for repo name
		if [ "$repo."  == "." ]; then
			# remote not set yet
			#  name not specified
			# need to prompt
			# repo
			# if we had their userid, we could get the list of repos to pick from
			git remote add origin "https://github.com/$user_name/$reponame.git"
			git branch -M main
			repo=$(git remote -v| grep fetch -m1 | awk '{ print $2}')
		fi
		#	git remote add origin https://github.com/$user_name/$reponame.git
		#	git branch -M main
		#fi
		git push -u origin main refs/tags/$next_tagnumber >>$logfile
	fi

fi
echo see this link for how to fetch tags for restore
echo https://devconnected.com/how-to-list-git-tags/
echo or run the list_tags.sh command from this repo

cd - >/dev/null

date +"backup ended  - %a %b %e %H:%M:%S %Z %Y" >>$logfile