# Author: Mete Rodoper
# For more detail refer the How to code and use Various Mobility Model Scripts to Emulate Mobility at ORBIT tutorial

# **this code is based on reference node model**


#!/usr/bin/perl

use Math::Round qw(:all);
use Math::Trig 'rad2deg';

#############################################################################################################
######################################## Enter the values here ##############################################
#############################################################################################################

@sourceXValue = (1, 1, 4); # Source X values of all 3 VMs. 
@sourceYValue = (1, 4, 12); # Source Y values of all 3 VMs. 

$numberOfDestinations = 3; # The number of destinations that you want VM to travel
$maxIntervalTime = 100; #Maximum waiting time at a node
$minIntervalTime = 10; #Maximum waiting time at a node
@accelerationRandomness = ([25, -5, -2],
			   [12, -4, -4],
			   [32, -12, 3]);  # Acceleration values between checkpoints, e.g.: Between VM1 source and 1st checkpoint point acceleration is 25, then -5, last, -2 and same for other VMs.
$randomnessInterval = 1; # Maximum distance that a node can jump at an iteration

#############################################################################################################
#############################################################################################################
#############################################################################################################

$numberOfDestinationsIterator = 1;
$numberOfSources = scalar(@sourceXValue);
$numberOfSources--;

while ($numberOfSources > -1)
{
	while (1 + $numberOfDestinations > $numberOfDestinationsIterator)
	{
		$randX = 1 + int(rand(19));
		$randY = 1 + int(rand(19));

		push @{$destinationXValue{$numberOfSources}}, $randX;
		push @{$destinationYValue{$numberOfSources}}, $randY;

		$numberOfDestinationsIterator++;
	}
	$numberOfSources--;
	$numberOfDestinationsIterator = 1;
}

$randomTemp;
$intervalTime = $maxIntervalTime;
$mobileNumber = scalar(@sourceXValue);
$cumulativeTime = 0;

$mobileNumberIterator = 0;

$previousNode = "";

while($mobileNumberIterator < $mobileNumber)
{
$mobileNumberIteratorToPrint = $mobileNumberIterator +1;
print "Mobile node $mobileNumberIteratorToPrint starts\n";

	$cumulativeTime = 0;
	$cumulativeTimeOld = 0;
	$intervalTime = $maxIntervalTime;

	$randomTemp = int(rand($accelerationRandomness[$mobileNumberIterator][0]));
	if ($intervalTime - $randomTemp >= $minIntervalTime && $intervalTime - $randomTemp <= $maxIntervalTime)
	{
		$intervalTime = $intervalTime - $randomTemp;
	}

	$cumulativeTime = $cumulativeTime + $intervalTime;
	$cumulativeTimeOld = $cumulativeTime-$intervalTime;

	$nodeNumber = $sourceXValue[$mobileNumberIterator] * 100 + $sourceYValue[$mobileNumberIterator];

	if(isUnique($intervalTime , $cumulativeTime, $nodeNumber, @timer))
	{
		$loopIterator = 0;
		while ($loopIterator < $intervalTime)
		{
			push @{$timer{$nodeNumber}}, $cumulativeTimeOld + $loopIterator;
			$loopIterator++;
		}

		$nodeNameAndTime = "$cumulativeTimeOld node$sourceXValue[$mobileNumberIterator]-$sourceYValue[$mobileNumberIterator]";
		print "$cumulativeTimeOld node$sourceXValue[$mobileNumberIterator]-$sourceYValue[$mobileNumberIterator]\n";
		push @{$store{$mobileNumberIterator}}, $nodeNameAndTime;
	}
	else
	{
		$k--;
	}

	for($destinationNo = 0 ; $destinationNo < $numberOfDestinations ; $destinationNo++)
	{

		$distance = sqrt((${$destinationYValue{$mobileNumberIterator}}[$destinationNo]-$sourceYValue[$mobileNumberIterator])*(${$destinationYValue{$mobileNumberIterator}}[$destinationNo]-$sourceYValue[$mobileNumberIterator]) + (${$destinationXValue{$mobileNumberIterator}}[$destinationNo]-$sourceXValue[$mobileNumberIterator])*(${$destinationXValue{$mobileNumberIterator}}[$destinationNo]-$sourceXValue[$mobileNumberIterator]));

		$absdistance = int($distance);

		$angle = atan2((${$destinationYValue{$mobileNumberIterator}}[$destinationNo]-$sourceYValue[$mobileNumberIterator]), (${$destinationXValue{$mobileNumberIterator}}[$destinationNo]-$sourceXValue[$mobileNumberIterator]));
		$angle2 = rad2deg($angle);
		
		$k=1;

		while ($k < $absdistance)
		{
			do{
				$pointX = $sourceXValue[$mobileNumberIterator] + $k * cos($angle) + rand($randomnessInterval)-($randomnessInterval)/2;
			}while($pointX > 20);
			do{
				$pointY = $sourceYValue[$mobileNumberIterator] + $k * sin($angle) + rand($randomnessInterval)-($randomnessInterval)/2;
			}while($pointY > 20);
	
			$fractionX = $pointX - int($pointX);
			$fractionY = $pointY - int($pointY);
		
			$firstQuarter = $fractionY * $fractionY + $fractionX * $fractionX;
			$secondQuarter = $fractionY * $fractionY + (1-$fractionX) * (1-$fractionX);
			$thirdQuarter = (1-$fractionY) * (1-$fractionY) + (1-$fractionX) * (1-$fractionX);
			$fourthQuarter = (1-$fractionY) * (1-$fractionY) + $fractionX * $fractionX;
		
			$floorX = int($pointX);
			$floorY = int($pointY);
			$ceilingX = $floorX+1;
			$ceilingY = $floorY+1;
			
			$minDistance = $firstQuarter;
			$min = "1";
			if ($secondQuarter < $minDistance)
			{
				$min = "2";
			        $minDistance = $secondQuarter;
			}
			if ($thirdQuarter < $minDistance)
			{
				$min = "3";
			        $minDistance = $thirdQuarter;
			}
			if ($fourthQuarter < $minDistance)
			{
				$min = "4";
			}
	
			if ($min == "1")
			{

				$nodeName = "node$floorX-$floorY";
				if ($previousNode ne $nodeName)
				{
					$randomTemp = int(rand($accelerationRandomness[$mobileNumberIterator][$destinationNo]));
					if ($intervalTime - $randomTemp >= $minIntervalTime && $intervalTime - $randomTemp <= $maxIntervalTime)
					{
						$intervalTime = $intervalTime - $randomTemp;
					}
					$cumulativeTime = $cumulativeTime + $intervalTime;
					$cumulativeTimeOld = $cumulativeTime-$intervalTime;
					$nodeNumber = $floorX * 100 + $floorY;

					if(isUnique($intervalTime, $cumulativeTime, $nodeNumber, @timer))
					{
						$loopIterator = 0;
						while ($loopIterator < $intervalTime)
						{
							push @{$timer{$nodeNumber}}, $cumulativeTimeOld + $loopIterator;
							$loopIterator++;
						}

						$nodeNameAndTime = "$cumulativeTimeOld node$floorX-$floorY";
						print "$nodeNameAndTime\n";
						push @{$store{$mobileNumberIterator}}, $nodeNameAndTime;
						$previousNode = $nodeName;
					}
					else
					{
						$k--;
					}
				}
			}
			elsif ($min == "2")
			{
				$nodeName = "node$ceilingX-$floorY";
				if ($previousNode ne $nodeName)
				{
					$randomTemp = int(rand($accelerationRandomness[$mobileNumberIterator][$destinationNo]));
					if ($intervalTime - $randomTemp >= $minIntervalTime && $intervalTime - $randomTemp <= $maxIntervalTime)
					{
						$intervalTime = $intervalTime - $randomTemp;
					}
					$cumulativeTime = $cumulativeTime + $intervalTime;
					$cumulativeTimeOld = $cumulativeTime-$intervalTime;
					$nodeNumber = $ceilingX * 100 + $floorY;

					if(isUnique($intervalTime , $cumulativeTime, $nodeNumber, @timer))
					{
						$loopIterator = 0;
						while ($loopIterator < $intervalTime)
						{
							push @{$timer{$nodeNumber}}, $cumulativeTimeOld + $loopIterator;
							$loopIterator++;
						}

						$nodeNameAndTime = "$cumulativeTimeOld node$ceilingX-$floorY";
						print "$nodeNameAndTime\n";
						push @{$store{$mobileNumberIterator}}, $nodeNameAndTime;
						$previousNode = $nodeName;
					}
					else
					{
						$k--;
					}
				}
			}
			elsif ($min == "3")
			{
				$nodeName = "node$ceilingX-$ceilingY";
				if ($previousNode ne $nodeName)
				{
					$randomTemp = int(rand($accelerationRandomness[$mobileNumberIterator][$destinationNo]));
					if ($intervalTime - $randomTemp >= $minIntervalTime && $intervalTime - $randomTemp <= $maxIntervalTime)
					{
						$intervalTime = $intervalTime - $randomTemp;
					}
					$cumulativeTime = $cumulativeTime + $intervalTime;
					$cumulativeTimeOld = $cumulativeTime-$intervalTime;
					$nodeNumber = $ceilingX * 100 + $ceilingY;
					if(isUnique($intervalTime , $cumulativeTime, $nodeNumber, @timer))
					{
						$loopIterator = 0;
						while ($loopIterator < $intervalTime)
						{
							push @{$timer{$nodeNumber}}, $cumulativeTimeOld + $loopIterator;
							$loopIterator++;
						}
	
						$nodeNameAndTime = "$cumulativeTimeOld node$ceilingX-$ceilingY";
						print "$nodeNameAndTime\n";
						push @{$store{$mobileNumberIterator}}, $nodeNameAndTime;
						$previousNode = $nodeName;
					}
					else
					{
						$k--;
					}
				}
			}
			elsif ($min == "4")
			{
				$nodeName = "node$floorX-$ceilingY";
				if ($previousNode ne $nodeName)
				{	
					$randomTemp = int(rand($accelerationRandomness[$mobileNumberIterator][$destinationNo]));
					if ($intervalTime - $randomTemp >= $minIntervalTime && $intervalTime - $randomTemp <= $maxIntervalTime)
					{
						$intervalTime = $intervalTime - $randomTemp;
					}
					$cumulativeTime = $cumulativeTime + $intervalTime;
					$cumulativeTimeOld = $cumulativeTime-$intervalTime;
					$nodeNumber = $floorX * 100 + $ceilingY;
					if(isUnique($intervalTime , $cumulativeTime, $nodeNumber, @timer))
					{
						$loopIterator = 0;
						while ($loopIterator < $intervalTime)
						{
							push @{$timer{$nodeNumber}}, $cumulativeTimeOld + $loopIterator;
							$loopIterator++;
						}

						$nodeNameAndTime = "$cumulativeTimeOld node$floorX-$ceilingY";
						print "$nodeNameAndTime\n";
						push @{$store{$mobileNumberIterator}}, $nodeNameAndTime;
						$previousNode = $nodeName;
					}
					else
					{
						$k--;
					}
				}
			}
		$k++;
		}

		$nodeName = "node${$destinationXValue{$mobileNumberIterator}}[$destinationNo]-$destinationYValu[$mobileNumberIterator][$destinationNo]";
		if ($previousNode ne $nodeName)
		{	
			$randomTemp = int(rand($accelerationRandomness[$mobileNumberIterator][$destinationNo]));
			if ($intervalTime - $randomTemp >= $minIntervalTime && $intervalTime - $randomTemp <= $maxIntervalTime)
			{
				$intervalTime = $intervalTime - $randomTemp;
			}
			$cumulativeTime = $cumulativeTime + $intervalTime;
			$cumulativeTimeOld = $cumulativeTime-$intervalTime;
			$nodeNumber = ${$destinationXValue{$mobileNumberIterator}}[$destinationNo] * 100 + ${$destinationYValue{$mobileNumberIterator}}[$destinationNo];
			if(isUnique($intervalTime , $cumulativeTime, $nodeNumber, @timer))
			{
				$loopIterator = 0;
				while ($loopIterator < $intervalTime)
				{
					push @{$timer{$nodeNumber}}, $cumulativeTimeOld + $loopIterator;
					$loopIterator++;
				}
	
				$nodeNameAndTime = "$cumulativeTimeOld node${$destinationXValue{$mobileNumberIterator}}[$destinationNo]-${$destinationYValue{$mobileNumberIterator}}[$destinationNo]";
				print "$cumulativeTimeOld node${$destinationXValue{$mobileNumberIterator}}[$destinationNo]-${$destinationYValue{$mobileNumberIterator}}[$destinationNo]\n";
				push @{$store{$mobileNumberIterator}}, $nodeNameAndTime;
				$previousNode = $nodeName;
			}
		}

	$destinationNoToPrint = $destinationNo +1;
	print "Destination No : $destinationNoToPrint is Reached for Mobile Node Number : $mobileNumberIteratorToPrint\n";	

	$sourceXValue[$mobileNumberIterator] = ${$destinationXValue{$mobileNumberIterator}}[$destinationNo];
	$sourceYValue[$mobileNumberIterator]= ${$destinationYValue{$mobileNumberIterator}}[$destinationNo];
	}
$destinationNo = 0;
$mobileNumberIterator++;
print "\n";
}

$j = 0;

$mobileNumberIterator--;
$printNode = $mobileNumberIterator + 1;

while($mobileNumberIterator > -1)
{
	while (${$store{$mobileNumberIterator}}[$j] ne ())
	{
		$tempWrite = ${$store{$mobileNumberIterator}}[$j];
		system("echo $tempWrite >> VM$printNode.txt");
		$j = $j + 1;
	}
	$mobileNumberIterator--;
	$printNode--;
	$j = 0;
}

sub isUnique
{
	$intervalTime = $_[0];
	$cumulativeTime = $_[1];
	$nodeNumber = $_[2];
	@timer = @_[3];
	
	$cumulativeTimeOld = $cumulativeTime - $intervalTime;
	$loopIterator = 0;

	while ($loopIterator < $intervalTime)
	{	
		while (${$timer{$nodeNumber}}[$j] ne ())
		{
			if (${$timer{$nodeNumber}}[$j] == $cumulativeTimeOld + $loopIterator)
			{
				print "ERROR ${$timer{$nodeNumber}}[$j]\n";
				return 0;
			}
			$j = $j + 1;
		}
		$loopIterator++;
		$j = 0;
	}
	return 1;
}
