APP_SDK_NAME="NielsenNoAdAppSDK" #NielsenAppSDK, NielsenNoAdAppSDK, NielsenNoIdAppSDK, VRIAppSDK, NielsenTVOSAppSDK, NielsenNoAdTVOSAppSDK, NielsenNoIdTVOSAppSDK, NielsenAGFAppSDK, NielsenAGFNoAdAppSDK, NielsenAGFNoIdAppSDK, NielsenAGFTVOSAppSDK, NielsenAGFNoAdTVOSAppSDK, NielsenAGFNoIdTVOSAppSDK
DISTRIBUTOR="GlobalNoAd" #Global, GlobalNoAd, GlobalNoId, VRI, AGF, AGFNoAd, AGFNoId
BUNDLE_NAME="NielsenAppApi" #NielsenAppApi, AppApi, NielsenTVAppApi
APP_SDK_VERSION='8.2.0.0' #5.1.1.29, 6.0.0.4, 6.1.0.1

CACHE_LIFETIME=604800

BUNDLE_PATH="$APP_SDK_NAME/$BUNDLE_NAME.framework"
README_FILE="$APP_SDK_NAME-ReadMe.md"
PODFILE_PATH="../Podfile"
BASE_URL="https://raw.githubusercontent.com/nielsendigitalsdk/nielsenappsdk-ios-dynamic/master"
README_URL="$BASE_URL/$APP_SDK_NAME-ReadMe.md"
LAST_UPDATE_TIMESTAMP_FILE="$APP_SDK_NAME-LastUpdate.timestamp"

NIELSEN_APP_SDK_DEFINITION_PATTERN="s/^[[:space:]]*(pod[[:space:]]+'$APP_SDK_NAME'[[:space:]]*(,[[:space:]]*(:)?.*[[:space:]]*$|[[:space:]]*$))/\1/p"
NIELSEN_APP_SDK_VERSION_DEFINITION_PATTERN="s/.*,[[:space:]]*'([[:space:]]*(>|<|=|<=|>=|~>)?[[:space:]]*[[:digit:]]+(\.[[:digit:]]+)*)'.*/\1/p"
NIELSEN_APP_SDK_SIGN_PATTERN="s/^(>|<|=|<=|>=|~>).*/\1/p"
NIELSEN_APP_SDK_VERSION_NUMBER_PATTERN="s/([[:digit:]]+(\.[[:digit:]]+)*)/\1/p"

RELEASE_VERSION_PATTERN="s/^[[:space:]]*Release[[:space:]]*([[:digit:]]+(\.[[:digit:]]+)*)[[:space:]]*\([[:digit:]]+-[[:digit:]]+-[[:digit:]]+\)[[:space:]]*$/\1/p"

COMPARE_RESULT_EQ=0
COMPARE_RESULT_ASC=1
COMPARE_RESULT_DESC=2

SUCCESS=1
FAILURE=0

README_UPDATE_STATUS_CACHED=2
README_UPDATE_STATUS_UPDATED=1
README_UPDATE_STATUS_FAILED=0

SDK_UPDATE_STATUS_FAILED=0
SDK_UPDATE_STATUS_UPDATED=1
SDK_UPDATE_STATUS_NOT_NEEDED=2

TARGET_WATCHOS=3
TARGET_MACOS=2
TARGET_TVOS=1
TARGET_IPHONEOS=0

UPDATE_TO_MAJOR="UPDATE_TO_MAJOR"
UPDATE_TO_GLOBAL="UPDATE_TO_GLOBAL"
UPDATE_TO_SPECIFIC="UPDATE_TO_SPECIFIC"

VERSION_ND=""
VERSION_EQ="="
VERSION_GT=">"
VERSION_GE=">="
VERSION_LT="<"
VERSION_LE="<="

#################
VERSION_TW="~>" # APPLIES ONLY FOR MAJOR VERSIONS
#################
#"~> 5.1.1.29" -> [5.1.1.29; 6.0.0.0)
#"~> 6.0.0.3"  -> [6.0.0.3; 7.0.0.0)
#"~> 6.0"  -> 	  [6.0.0.0; 7.0.0.0)


###################################
###SCRIPT SPECIFIC FILE MANAGING###
###################################

shouldGetGlobalReadMeFromTheServer() {
	if isFileExist "$LAST_UPDATE_TIMESTAMP_FILE" && isFileExist "$README_FILE";
	then
		local creationTime=$(lastUpdateTimestampFromFile "$LAST_UPDATE_TIMESTAMP_FILE")
		local currentTime=$(date +%s)
		local lifetime=$((currentTime - creationTime))
		[ $lifetime -ge $CACHE_LIFETIME ];
	else
		true;
	fi
}

lastUpdateTimestampFromFile() {
	local content="$(fileContent "$1" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')"
	local currentTime=$(date +%s)

	if [ ! -z "$content" -a "$content" != " " ];
	then
		if [[ "$content" =~ ^[0-9]{10}$ ]];
		then
			echo $content
		else
			echo $((currentTime - CACHE_LIFETIME - 1));
		fi
	else
		echo $((currentTime - CACHE_LIFETIME - 1));
	fi
}

###################
###FILE MANAGING###
###################

isFileExist() {
	[ -s "$1" ]
}

isFolderExist() {
	[ -d "$1" ]
}

removeFile() {
	if [ -f "$1" ];
	then
		rm "$1"
	fi
}

removeFolder() {
	rm -rf "$1"
}

removeFoldersContent() {
	rm -rf "$1"/*
}

grantPermissionsForFile() {
	if isFileExist "$1";
	then
		chmod a+x "$1"
	fi
}

fileContent() {
	if isFileExist "$1";
	then
		grantPermissionsForFile "$1"
		local content=$(<"$1")
		echo "$content"
	else
		echo ""
	fi
}

writeContentToFile() {
	grantPermissionsForFile "$2";
	echo "$1" > "$2"
}


#######################
###VERSION COMPARING###
#######################

#Shows difference between provided version and global release version including Header in ReadMe file.
#$1 - from version
showDifferenceFromVersion() {
	local difference=""
	local canShow=false
	local fromVersion="$1"

	while IFS='' read -r line || [[ -n "$line" ]]; do
		local version="$(echo "$line" | sed -n -E "${RELEASE_VERSION_PATTERN}")"
		if [ ! -z "$version" -a "$version" != " " ];
		then
			compareVersions "$fromVersion" "$version" refComparisonResult

			if [ $refComparisonResult == $COMPARE_RESULT_ASC ];
			then
				if [ "$difference" == "" ];
				then
					difference="$line"
				else
					difference="$difference\n$line"
				fi
				canShow=true;
			else
				break;
			fi
		else
			if [ "$difference" == "" ];
			then
				difference="$line";
			else
				difference="$difference\n$line";
			fi
		fi
	done < "$README_FILE"

	if $canShow;
	then
		echo -e "$difference"
	fi

	return $SUCCESS;
}

#Shows difference between provided versions in ReadMe file.
#$1 - from version
#$2 - to version
showDifferenceBetweenVersions() {
	local difference=""
	local canShow=false
	local fromVersion="$1"
	local toVersion="$2"

	compareVersions "$fromVersion" "$toVersion" refGuardComparisonResult

	if [ $refGuardComparisonResult -ne $COMPARE_RESULT_ASC ];
	then
		return $FAILURE;
	fi

	local canAppend=false
	while IFS='' read -r line || [[ -n "$line" ]]; do
		local version="$(echo "$line" | sed -n -E "${RELEASE_VERSION_PATTERN}")"
		if [ ! -z "$version" -a "$version" != " " ];
		then
			compareVersions "$toVersion" "$version" refComparisonResultToVersion
			#Raise canAppend flag to start appending changes from the range of text between two versions
			if [ $refComparisonResultToVersion == $COMPARE_RESULT_EQ ];
			then
				canAppend=true;
			fi

			if $canAppend;
			then
				compareVersions "$fromVersion" "$version" refComparisonResultFromVersion

				if [ $refComparisonResultFromVersion == $COMPARE_RESULT_ASC ];
				then
					if [ "$difference" == "" ];
					then
						difference="$line"
					else
						difference="$difference\n$line"
					fi
					canShow=true;
				else
					break;
				fi
			fi
		else
			if $canAppend;
			then
				difference="$difference\n$line";
			fi
		fi
	done < "$README_FILE"

	if $canShow;
	then
		echo -e "$difference"
	fi

	return $SUCCESS;
}

##compares two versions and writes to the result variable
##v1 = 1.0.0.0
##v2 = 1.0.0.1
##v3 = 1.0.0.0
##v4 = 0.1.0.1

##compareVersions v1 v2 result
##result = COMPARE_RESULT_ASC

##compareVersions v1 v3 result
##result = COMPARE_RESULT_EQ

##compareVersions v1 v4 result
##result = COMPARE_RESULT_DESC

compareVersions() {
	local __resultVar=$3
	if [[ $1 == $2 ]]
	then
		eval $__resultVar=$COMPARE_RESULT_EQ
	return
	fi
	local IFS=.
	local i ver1=($1) ver2=($2)
	# fill empty fields in ver1 with zeros
	for ((i=${#ver1[@]}; i<${#ver2[@]}; i++))
	do
		ver1[i]=0
	done
	for ((i=0; i<${#ver1[@]}; i++))
	do
		if [[ -z ${ver2[i]} ]]
		then
			# fill empty fields in ver2 with zeros
			ver2[i]=0
		fi
		if ((10#${ver1[i]} > 10#${ver2[i]}))
		then
			eval $__resultVar=$COMPARE_RESULT_DESC
			return
		fi
		if ((10#${ver1[i]} < 10#${ver2[i]}))
		then
			eval $__resultVar=$COMPARE_RESULT_ASC
			return
		fi
	done
	eval $__resultVar=$COMPARE_RESULT_EQ
	return
}


updateGlobalReadMe() {
	if shouldGetGlobalReadMeFromTheServer;
	then
		local readMeContent=$(curl -sS --fail "$README_URL" --netrc)
		if [  ! -z "$readMeContent" -a "$readMeContent" != " " ]
		then
			writeContentToFile "$readMeContent" "$README_FILE"
			writeContentToFile "$(date +%s)" "$LAST_UPDATE_TIMESTAMP_FILE"
			return $README_UPDATE_STATUS_UPDATED
		else
			return $README_UPDATE_STATUS_FAILED
		fi
	fi
	return $README_UPDATE_STATUS_CACHED
}

#Versions are mentioned in the ReadMe file in descending order
getAppSDKVersionNumbers() {
	local readMe="$(fileContent "$README_FILE")"
	local versions="$(echo "$readMe" | sed -n -E "${RELEASE_VERSION_PATTERN}")"
	echo "$versions"
}

getLatestVersionNumber() {
	IFS=$'\n' read -rd '' -a versionsArray <<<"$(getAppSDKVersionNumbers)"
	unset IFS
	echo "$versionsArray"
}

getPodfilePodDefintion() {
	local podfileContent="$(fileContent "$PODFILE_PATH")"
	local podDefinition="$(echo "$podfileContent" | sed -n -E "$NIELSEN_APP_SDK_DEFINITION_PATTERN")"
	echo "$podDefinition"
}

getPodfileVersionDefinitionFromPodDefinition() {
	local podVersionDefinition="$(echo "$1" | sed -n -E "$NIELSEN_APP_SDK_VERSION_DEFINITION_PATTERN")"
	echo "$podVersionDefinition"
}

getPodfileVersionSignFromDefinition() {
	echo "$(echo "$1" | sed -n -E "$NIELSEN_APP_SDK_SIGN_PATTERN")"
}

getPodfileVersionNumberFromDefinition() {
	[[ "$1" =~ [0-9]+(\.[0-9]+)* ]] && echo "${BASH_REMATCH[0]}"
}

getMajorVersion() {
	IFS=$'.' read -rd '' -a versionElements <<<"$1"
	unset IFS

	echo "$versionElements"
}

#Gets target OS from the list:
#watchsimulator watchos
#macosx
#appletvsimulator appletvos
#iphoneos iphonesimulator

#TARGET_WATCHOS=3
#TARGET_MACOS=2
#TARGET_TVOS=1
#TARGET_IPHONEOS=0

getTargetOS() {
	local platformName="${PLATFORM_NAME}"
	if [[ "$platformName" = *"iphoneos"* ]] || [[ "$platformName" = *"iphonesimulator"* ]];
	then
		return $TARGET_IPHONEOS;
	fi
	if [[ "$platformName" = *"appletvos"* ]] || [[ "$platformName" = *"appletvsimulator"* ]];
	then
		return $TARGET_TVOS;
	fi
	if [[ "$platformName" = *"macosx"* ]];
	then
		return $TARGET_MACOS;
	fi
	if [[ "$platformName" = *"watchos"* ]] || [[ "$platformName" = *"watchsimulator"* ]];
	then
		return $TARGET_WATCHOS;
	fi

	return $TARGET_IPHONEOS
}

getOSFolder() {
	getTargetOS
	local targetOS=$?
	case "$targetOS" in
		"$TARGET_IPHONEOS")
			echo "iOS"
		;;
		"$TARGET_TVOS")
			echo "tvOS"
		;;
		"$TARGET_MACOS")
			echo "macOS"
		;;
		"$TARGET_WATCHOS")
			echo "watchOS"
		;;
		*)
			echo "iOS"
		;;
	esac
}

buildPathToTheRelease() {
	local version="$1"
	local pathToFile="$BASE_URL/$(getOSFolder)/$DISTRIBUTOR/$APP_SDK_NAME-$version.zip"
	echo "$pathToFile"
}

fetchSDKForVersion() {
	local version="$1"
	local pathToFile="$(buildPathToTheRelease "$version")"
	local tempFilename="$APP_SDK_NAME-$version.zip"

	removeFile "$tempFilename"
	removeFile "$LAST_UPDATE_TIMESTAMP_FILE"
	if ! curl -sS --fail -o "$tempFilename" "$pathToFile" --netrc;
	then
		return $FAILURE;
	fi

	if ! isFileExist "$tempFilename";
	then
		return $FAILURE;
	fi

	removeFoldersContent "$APP_SDK_NAME"

	unzip -qq "$tempFilename" -d "$APP_SDK_NAME"

	removeFile "$tempFilename"

	if [ "$(ls -A $APP_SDK_NAME)" ];
	then
		writeContentToFile "$(date +%s)" "$LAST_UPDATE_TIMESTAMP_FILE"
		return $SUCCESS;
	else
		return $FAILURE;
	fi
}

isVersionExist() {
	local version="$1"
	IFS=$'\n' read -rd '' -a releaseVersions <<<"$2"
	unset IFS

	for releaseVersion in ${releaseVersions[@]}
	do
		if [[ "$version" == "$releaseVersion" ]];
		then
			true
			return
		fi
	done
	false
}

#Updates SDK with up to major version from the provided version
#Returns new version number string or empty if it was not updated
#$1 - Target At Least Version
#$2 - Pointer to the argument where release version will be written to
#$3 - Updating strategy: MAJOR, GLOBAL or SPECIFIC
#$4 - Current App SDK Version
#$5 - Should forcely update

updateSDKFromTheVersion() {
	local targetVersion="$1"
	local versionUpdateLogic="$3"
	local appSDKVersion="$4"
	local forceUpdate=$5

	#Check Parameters
	if [ -z "$targetVersion" -a "$targetVersion" == "" ] || [ -z "$versionUpdateLogic" -a "$versionUpdateLogic" == "" ] || [ -z "$appSDKVersion" -a "$appSDKVersion" == "" ]
	then
		echo "One of the required parameters is not provided."
		eval "$2=''"
		return $SDK_UPDATE_STATUS_FAILED;
	fi

	local appSDKVersionNumbers="$(getAppSDKVersionNumbers)"
	IFS=$'\n' read -rd '' -a releaseVersions <<<"$appSDKVersionNumbers"
	unset IFS

	if [ -z "$releaseVersions" -a "$releaseVersions" == "" ]
	then
		echo "Unable to retrieve release versions."
		eval "$2=''"
		return $SDK_UPDATE_STATUS_FAILED;
	fi

	local releaseVersionToUpdateTo=""

	if [ "$versionUpdateLogic" == "$UPDATE_TO_MAJOR" ]
	then
		local majorTargetVersion="$(getMajorVersion "$targetVersion")"
		#Get the first version, the major version of which is equal to
		#the major version of the 'targetVersion' and greater than or equal to 'targetVersion'
		for releaseVersion in ${releaseVersions[@]}
		do
			local majorReleaseVersion="$(getMajorVersion "$releaseVersion")"
			compareVersions "$targetVersion" "$releaseVersion" comparisonResult
			if [[ "$majorTargetVersion" == "$majorReleaseVersion"  && ( $comparisonResult == $COMPARE_RESULT_EQ || $comparisonResult == $COMPARE_RESULT_ASC ) ]]; 
			then
				releaseVersionToUpdateTo="$releaseVersion";
				break;
			fi
		done

		if [ "$releaseVersionToUpdateTo" == "" ]
		then
			echo "warning: No release versions for '~> $targetVersion' update is found. Consider to update your CocoaPods repository."
			eval "$2=''"
			return $SDK_UPDATE_STATUS_FAILED;
		fi
	elif [ "$versionUpdateLogic" == "$UPDATE_TO_GLOBAL" ]
	then
		#Get first most version to update to Global release version
		releaseVersionToUpdateTo="${releaseVersions[0]}"

		if [ "$releaseVersionToUpdateTo" == "" ]
		then
			echo "warning: No global release version for update is found. Consider to update your CocoaPods repository."
			eval "$2=''"
			return $SDK_UPDATE_STATUS_FAILED;
		fi
	elif [ "$versionUpdateLogic" == "$UPDATE_TO_SPECIFIC" ]
	then
		#Use provided target version to update the SDK to specific version
		releaseVersionToUpdateTo="$targetVersion"
		if ! isVersionExist "$releaseVersionToUpdateTo" "$appSDKVersionNumbers";
		then
			echo "warning: No release versions for '$targetVersion' update is found. Consider to update your CocoaPods repository."
			eval "$2=''"
			return $SDK_UPDATE_STATUS_FAILED;
		fi
	else
		echo "warning: Unknown version update logic provided."
		eval "$2=''"
		return $SDK_UPDATE_STATUS_FAILED;
	fi


	if [[ "$appSDKVersion" == "$releaseVersionToUpdateTo" ]] && ( ! $forceUpdate )
	then
		eval "$2='$releaseVersionToUpdateTo'"
		return $SDK_UPDATE_STATUS_NOT_NEEDED;
	fi

	echo "Updating $APP_SDK_NAME to the version: $releaseVersionToUpdateTo.";
	fetchSDKForVersion "$releaseVersionToUpdateTo"
	local fetchResult=$?

	if [ $fetchResult == $SUCCESS ];
	then
		echo ""
		echo "$APP_SDK_NAME '$releaseVersionToUpdateTo' has been downloaded."
		eval "$2='$releaseVersionToUpdateTo'"
		return $SDK_UPDATE_STATUS_UPDATED;
	else
		echo ""
		echo "Unable to download the $APP_SDK_NAME"
		eval "$2=''"
		return $SDK_UPDATE_STATUS_FAILED;
	fi
}


##########
###MAIN###
##########

##compares current version with global remote version
#$1 - global remote release version
#$2 - version to which SDK has been updated
#$3 - version from which SDK has been updated
#$4 - SDK update status
compareVersionsForSDKUpdateStatus() {
	local remoteVersion="$1"
	local currentVersion="$2"
	local baseVersion="$3"
	local sdkUpdateStatus=$4

	if [ $sdkUpdateStatus == $SDK_UPDATE_STATUS_FAILED ];
	then
		return $FAILURE;
	fi

	compareVersions "$baseVersion" "$currentVersion" comparisonResultBetweenBaseAndCurrent
	compareVersions "$currentVersion" "$remoteVersion" comparisonResultBetweenCurrentAndRelease

	if [ $sdkUpdateStatus == $SDK_UPDATE_STATUS_UPDATED ];
	then
		if [ $comparisonResultBetweenBaseAndCurrent == $COMPARE_RESULT_ASC ];
		then
			echo ""
			echo "warning: $APP_SDK_NAME has been updated from $baseVersion to $currentVersion version."
			echo ""
			echo "INTRODUCED CHANGES:"
			echo ""
			showDifferenceBetweenVersions "$baseVersion" "$currentVersion"
		fi
	fi

	if [ $comparisonResultBetweenCurrentAndRelease -ne $COMPARE_RESULT_EQ ];
	then
		if [ $comparisonResultBetweenCurrentAndRelease == $COMPARE_RESULT_ASC ];
		then
			echo ""
			echo "warning: Your version of the $APP_SDK_NAME ($currentVersion) is old! The new version is available ($remoteVersion)."
			echo ""
			showDifferenceFromVersion "$currentVersion"
		else
			echo "warning: Your version of the $APP_SDK_NAME ($baseVersion) is not published for the market. It is not guaranted that the SDK will work properly."
		fi
	fi

	return $SUCCESS;
}

checkAppSDKVersion() {
	local podDefinition="$(getPodfilePodDefintion)"
	if [ -z "$podDefinition" ]
	then
		return 0;
	fi

	updateGlobalReadMe
	local readmeUpdateStatus=$?
	if [ $readmeUpdateStatus == $README_UPDATE_STATUS_FAILED ];
	then
		echo "Unable to retrieve ReadMe file from the Server."
		echo "warning: Your version of the SDK ($APP_SDK_VERSION) is not guaranted to be fresh."
		return $FAILURE;
	fi

	local podVersionDefinition="$(getPodfileVersionDefinitionFromPodDefinition "$podDefinition")"
	local podSign="$(getPodfileVersionSignFromDefinition "$podVersionDefinition")"
	local podVersion="$(getPodfileVersionNumberFromDefinition "$podVersionDefinition")"

	if [[ "$podSign" != "$VERSION_TW" ]] && [[ "$podSign" != "$VERSION_ND" ]]
	then
		echo "warning: '$podSign' sign in Podfile is not supported!"
		return $FAILURE
	fi

	local baseVersion="$APP_SDK_VERSION"

	#Detect if the podfile has been changed
	if [ ! -z "$podVersion" -a "$podVersion" != " " ]
	then
		compareVersions "$podVersion" "$APP_SDK_VERSION" comparisonResult
		if [[ $comparisonResult != $COMPARE_RESULT_EQ ]]
		then
			# 6.0.0.4 <-> 5.1.1.29
			# 5.1.1.29 <-> 6.0.0.4
			# 5.1.1.29 <-> 7.0.0
			baseVersion="$podVersion"
		fi
	fi

	#if there is no $BUNDLE_NAME.framework, forcely download it
	local forceUpdate=false;
	if ! isFolderExist "$BUNDLE_PATH";
	then
		forceUpdate=true;
	fi

	local sdkUpdateStatus=$SDK_UPDATE_STATUS_FAILED
	#refVersionUpdatedTo - reference to the memory where the version to which SDK got updated will be written
	if [ "$podSign" == "$VERSION_TW" ]
	then
		updateSDKFromTheVersion "$baseVersion" refVersionUpdatedTo "$UPDATE_TO_MAJOR" "$APP_SDK_VERSION" $forceUpdate
		sdkUpdateStatus=$?
	elif [ "$podVersion" == "" ]
	then
		updateSDKFromTheVersion "$baseVersion" refVersionUpdatedTo "$UPDATE_TO_GLOBAL" "$APP_SDK_VERSION" $forceUpdate
		sdkUpdateStatus=$?
	elif [ "$podSign" == "$VERSION_ND" ] && [ ! -z "$podVersion" -a "$podVersion" != " " ]
	then
		updateSDKFromTheVersion "$baseVersion" refVersionUpdatedTo "$UPDATE_TO_SPECIFIC" "$APP_SDK_VERSION" $forceUpdate
		sdkUpdateStatus=$?
	fi


	local latestReleaseVersion="$(getLatestVersionNumber)"
	if [ ! -z "$latestReleaseVersion" -a "$latestReleaseVersion" != " " ]
	then
		compareVersionsForSDKUpdateStatus "$latestReleaseVersion" "$refVersionUpdatedTo" "$APP_SDK_VERSION" $sdkUpdateStatus
	else
		echo "warning: Cannot fetch the latest release version. It is not guaranted that the SDK work properly."
	fi

	return 0;
}

#################
###ENTRY POINT###
#################

checkAppSDKVersion
