#! /usr/bin/python3

#load the libraries
import sys
import random
import math
import numpy as np
import json

#the  fingerprinter for coordinating the forgers
global checkFingerprinter
checkFingerprinter = None

#the object representing normal users
class User(object):
	
	#the creation of the object
	#parameter:
	#       attributes:     list of attributes for the user
	#       fingerprinters: a list of fingerprinters to visit, the first one is for statistics, the second for coordinating the forgers
	def __init__(self,attributes,fingerprinters):
		#list of attributes for the user
		self.attributes            = attributes
		#the fingerprinter to visit
		self.fingerprinters        = fingerprinters

		#increment the total number of users
		global userCounter
		userCounter  = userCounter + 1

		#set the userid
		self.userId  = userCounter

		#mark the user as nonforger
		self.isForger = False

	#the callback function for the main simulation
	def tick(self):
		self.action()

	#do some tasks
	def action(self):
		self.browse()
		
	#visit the fingerprinter
	def browse(self):
		self.fingerprinters[0].visitedBy(self)

		#visit the fingerprint for coordinating forgeries with the given chance
		if random.random() > float(sys.argv[4]):
			self.fingerprinters[1].visitedBy(self)

	#a empty function for forgery calls
	def forge(self):
		pass

#the object representing a forger
class ForgingUser(User):
	
	#the creation of the object
	#parameter:
	#       attributes: the list of attributes to meassure to obtain a fingerprint
	#       fingerprinter:  a list of fingerprinters to visit, the first one is for statistics, the second for coordinating the forgers
	#       fixed:  a list of attribute indexes marking these attributes as unchangeable
	def __init__(self,attributes,fingerprinters,fixed):
		#call superclass constructor
		super().__init__(attributes,fingerprinters)

		#the attributes which are unchangeable
		self.fixed = fixed

		#mark the user as forger
		self.isForger = True

	#forge a random Fingerprint
	def forge(self):
		#get a random from the coordination fingerprinter
		global checkFingerprinter
		newAttributes = checkFingerprinter.getRandom(self.fixed,self.attributes)

		#change the attributes if a fingerprint to forge was found
		if newAttributes:
			self.attributes = newAttributes
		else:
			pass
			#print("no attribute found")

#the object representing a fingerprintingscript
class Fingerprinter(object):

	#the creation of the object
	#parameter:
	#       fingerprintedAttributes: the list of attributes to meassure to obtain a fingerprint
	def __init__(self,fingerprintedAttributes):
		#the list of attributes to meassure to obtain a fingerprint
		self.fingerprintedAttributes = fingerprintedAttributes

		#the fingerprints meassured
		self.messuredFingerprints = []

	#the function for beeing visited by an user
	#parameter:
	#       user: the user visiting
	def visitedBy(self,user):
		self.messuredFingerprints.append([user.userId,self.extractFingerprint(user),user.isForger])

	#reset the fingerprinterstate
	def reset(self):
		#clear the meassured fingerprints
		self.messuredFingerprints = []

	#measure the fingerprint for a user
	#parameter:
	#       user: the user to get the fingerprint from
	def extractFingerprint(self,user):
		result = []
		for index in self.fingerprintedAttributes:
			result.append(user.attributes[index])
		return result

#The Fingerprinter for coordinating the forgers
class InfoFingerprinter(Fingerprinter):
	#the creation of the object
	#parameter:
	#       fingerprintedAttributes: the list of attributes to meassure to obtain a fingerprint
	def __init__(self,fingerprintedAttributes):
		#call superclass constructor
		super().__init__(fingerprintedAttributes)

	#get a random fingerprint for a specific forger
	def getRandom(self,fixed,values):
		#return a random fingerprint from all users if there are no restrictions
		if len(fixed) == 0:
			if len(self.messuredFingerprints):
				return random.choice(self.messuredFingerprints)[1]

		#create a lsit of fingerprint wich are potentially foregable
		reducedFingerprints = []
		for fingerprint in self.messuredFingerprints:
			identifier = ""
			counter = 0
			breakAll = False
			while counter < 10:
				if counter in fixed:
					if fingerprint[1][counter] == values[counter]:
						counter += 1
						continue
					else:
						breakAll = True
						break
				counter += 1

			if breakAll:
				continue

			reducedFingerprints.append(fingerprint)

		#return a random fingerprint if candidates were found
		if len(reducedFingerprints):
			return random.choice(reducedFingerprints)[1]
		else:
			return None

#the  fingerprinter for coordinating the forgers
checkFingerprinter = None
#the total number of forgers
numForges = 0

#the actual simulation of the fingerprinting process			
class Simulation(object):

	#the creation of the object
	#parameter:
	#       numUsers:       the number of users to simulate
	def __init__(self,numUsers=1):
		#reset the total number of forgers
		global numForges
		numForges = 0

		#create a container to store the forgers in
		self.forgers = []
	
		#create empty containers for statistics
		self.forgersStatistics = {}
		self.allStatistics = {}

		#save the number of users
		self.numUsers = numUsers

		#the fingerprinter for creating the statistics
		self.__analyseFingerprinter = Fingerprinter([0,1,2,3,4,5,6,7,8,9])

		#the fingerprinter for coordinating the forgers
		self.__checkFingerprinter = InfoFingerprinter([0,1,2,3,4,5,6,7,8,9])
		global checkFingerprinter
		checkFingerprinter = self.__checkFingerprinter

		#create the users
		self.__users = []
		for i in range(0,self.numUsers):
			self.__users.append(self.__generateUser())

		#prepare the containers for statistics with dummy structures
		for user in self.__users:
			self.allStatistics[user.userId] = {}
			self.allStatistics[user.userId]["forgedTouched"] = set()
			
		for forger in self.forgers:
			self.forgersStatistics[forger.userId] = {}
			self.forgersStatistics[forger.userId]["touched"] = set()
			self.forgersStatistics[forger.userId]["forgedTouched"] = set()
			self.forgersStatistics[forger.userId]["fingerprints"] = set()
			self.forgersStatistics[forger.userId]["lastFingerprint"] = str(self.__analyseFingerprinter.extractFingerprint(forger))
			self.forgersStatistics[forger.userId]["lastRawFingerprint"] = self.__analyseFingerprinter.extractFingerprint(forger)
			self.forgersStatistics[forger.userId]["changes"] = 0
			self.forgersStatistics[forger.userId]["detectable_random"] = set()
		
		#calculate statistic about the anonomity between the forgers
		counterDict = {}
		for forger in self.forgers:
			fingerprint = self.forgersStatistics[forger.userId]["lastRawFingerprint"]
			realFingerprint = []

			counter = 0
			while counter < 10:
				if not counter in forger.fixed:
					realFingerprint.append(fingerprint[counter])
				else:
					realFingerprint.append(None)
				counter += 1

			realFingerprint = str(realFingerprint)
			if realFingerprint in counterDict:
				counterDict[realFingerprint] += 1
			else:
				counterDict[realFingerprint] = 1
	
		self.forgerEntropy = 0
		self.forgerAnonset = 0
		for anonSet in counterDict.values():
			probability = anonSet/len(self.__users)
			self.forgerEntropy += probability*-math.log(probability,2)
			self.forgerAnonset += anonSet
		self.forgerAnonset /= len(counterDict)

		#the container for the result
		self.__result = []

	#run the simulation
	#parameter:
	#       ticks:  the number of ticks to simulate
	#       numRun: how many times this siulation was run
	def run(self,ticks,numRun):
		#do all ticks
		for i in range(0,ticks):
			print("tick "+str(i+1))
	
			#do the tick on all users
			for user in self.__users:
				user.tick()

			#calculate the statistics for this tick
			self.middleStatics(numRun,i+1)

			#forge random fingerprints
			if i < int(sys.argv[3])-1:
				counter = 0
				for user in self.__users:
					user.forge()
					counter += 1

			#reset the fingerprints
			self.__analyseFingerprinter.reset()
			self.__checkFingerprinter.reset()

	#calculate the statistics for a tick
	def middleStatics(self,run,tick):
		import math

		#make a list of the fingerprints of the forgers and forged fingerprints containing the useris of the forger
		forgedFingerprints = {}
		forgerFingerprints = {}
		for forger in self.forgers:
			fingerprint = str(self.__analyseFingerprinter.extractFingerprint(forger))

			if not fingerprint in forgedFingerprints:
				forgedFingerprints[fingerprint] = set()
			
			if not fingerprint in forgerFingerprints:
				forgerFingerprints[fingerprint] = set()
				forgerFingerprints[fingerprint].add(forger.userId)
			else:
				forgerFingerprints[fingerprint].add(forger.userId)

		#the dict for counting the sizes of the anonymity sets
		counter = {}
		for fingerprint in self.__analyseFingerprinter.messuredFingerprints:
			if str(fingerprint[1]) in forgedFingerprints:
				forgedFingerprints[str(fingerprint[1])].add(fingerprint[0])

			if not str(fingerprint[1]) in counter:
				counter[str(fingerprint[1])] = 1
			else:
				counter[str(fingerprint[1])] += 1

		#caculate with how many forgers normal users interacted with
		percentTouched = 0
		sizeAllForgedAnon = 0
		for fingerprint in self.__analyseFingerprinter.messuredFingerprints:
			if str(fingerprint[1]) in forgerFingerprints:
				self.allStatistics[fingerprint[0]]["forgedTouched"] |= forgerFingerprints[str(fingerprint[1])]

			numForgers = len(self.allStatistics[fingerprint[0]]["forgedTouched"])
			if fingerprint[2]:
				numForgers -= 1
			sizeAllForgedAnon += numForgers

			if numForgers:
				percentTouched += 1
				
		sizeAllForgedAnon /= len(self.__analyseFingerprinter.messuredFingerprints)
		percentTouched /= len(self.__analyseFingerprinter.messuredFingerprints)
				
		#calculate statistics about the users
		sizeForgedAnon = 0
		fullsizeAnon = 0
		fullsizeForgedAnon = 0
		detectableFixed = 0
		numFingerprints = 0
		numChanges	= 0
		for forger in self.forgers:
			rawfingerprint = self.__analyseFingerprinter.extractFingerprint(forger)
			fingerprint = str(rawfingerprint)
			anonSet = forgedFingerprints[fingerprint]

			if not fingerprint == self.forgersStatistics[forger.userId]["lastFingerprint"]:
				self.forgersStatistics[forger.userId]["changes"] +=1

				counter2 = 0
				while counter2 <10:
					if not rawfingerprint[counter2] == self.forgersStatistics[forger.userId]["lastRawFingerprint"][counter2]:
						self.forgersStatistics[forger.userId]["detectable_random"].add(counter2)
					counter2 += 1

			if len(self.forgersStatistics[forger.userId]["detectable_random"]) + len(forger.fixed) == 10:
				detectableFixed += 1
					
			self.forgersStatistics[forger.userId]["lastFingerprint"] = fingerprint
			self.forgersStatistics[forger.userId]["lastRawFingerprint"] = rawfingerprint

			self.forgersStatistics[forger.userId]["fingerprints"].add(fingerprint)

			self.forgersStatistics[forger.userId]["touched"] |= anonSet

			self.forgersStatistics[forger.userId]["forgedTouched"] |= forgerFingerprints[fingerprint]

			sizeForgedAnon += len(anonSet)
			fullsizeForgedAnon += len(self.forgersStatistics[forger.userId]["forgedTouched"])
			numFingerprints += len(self.forgersStatistics[forger.userId]["fingerprints"])
			numChanges += self.forgersStatistics[forger.userId]["changes"]
			fullsizeAnon += len(self.forgersStatistics[forger.userId]["touched"])
			
		sizeForgedAnon /= len(self.forgers)
		fullsizeForgedAnon /= len(self.forgers)
		detectableFixed /= len(self.forgers)
		numChanges /= len(self.forgers)
		numFingerprints /= len(self.forgers)
		fullsizeAnon /= len(self.forgers)

		#caluclate how many users were touched indirectly by the users
		touched1hop = 0
		forgedTouched1hop = 0
		for forger in self.forgers:
			self.forgersStatistics[forger.userId]["touched1hop"] = set()
			self.forgersStatistics[forger.userId]["forgedTouched1hop"] = set()
			for partner in self.forgersStatistics[forger.userId]["forgedTouched"]:

				anonSet = set()
				anonSet = self.forgersStatistics[partner]["touched"]
				self.forgersStatistics[forger.userId]["touched1hop"] |= anonSet

				forgedAnonSet = self.forgersStatistics[partner]["forgedTouched"]
				self.forgersStatistics[forger.userId]["forgedTouched1hop"] |= forgedAnonSet


			touched1hop += len(self.forgersStatistics[forger.userId]["touched1hop"])
			forgedTouched1hop += len(self.forgersStatistics[forger.userId]["forgedTouched1hop"])
	
		touched1hop /= len(self.forgers)
		forgedTouched1hop /= len(self.forgers)

		touched2hop = 0
		forgedTouched2hop = 0
		for forger in self.forgers:
			self.forgersStatistics[forger.userId]["touched2hop"] = set()
			self.forgersStatistics[forger.userId]["forgedTouched2hop"] = set()
			for partner in self.forgersStatistics[forger.userId]["forgedTouched1hop"]:

				anonSet = set()
				anonSet = self.forgersStatistics[partner]["touched1hop"]
				self.forgersStatistics[forger.userId]["touched2hop"] |= anonSet

				forgedAnonSet = self.forgersStatistics[partner]["forgedTouched1hop"]
				self.forgersStatistics[forger.userId]["forgedTouched2hop"] |= forgedAnonSet

			touched2hop += len(self.forgersStatistics[forger.userId]["touched2hop"])
			forgedTouched2hop += len(self.forgersStatistics[forger.userId]["forgedTouched2hop"])
	
		touched2hop /= len(self.forgers)
		forgedTouched2hop /= len(self.forgers)

		touched3hop = 0
		forgedTouched3hop = 0
		for forger in self.forgers:
			self.forgersStatistics[forger.userId]["touched3hop"] = set()
			self.forgersStatistics[forger.userId]["forgedTouched3hop"] = set()
			for partner in self.forgersStatistics[forger.userId]["forgedTouched2hop"]:

				anonSet = set()
				anonSet = self.forgersStatistics[partner]["touched2hop"]
				self.forgersStatistics[forger.userId]["touched3hop"] |= anonSet

				forgedAnonSet = self.forgersStatistics[partner]["forgedTouched2hop"]
				self.forgersStatistics[forger.userId]["forgedTouched3hop"] |= forgedAnonSet


			touched3hop += len(self.forgersStatistics[forger.userId]["touched3hop"])
			forgedTouched3hop += len(self.forgersStatistics[forger.userId]["forgedTouched3hop"])
	
		touched3hop /= len(self.forgers)
		forgedTouched3hop /= len(self.forgers)
			
		#sort the anonymity sets by size
		sortedCounter = list(counter.values())
		sortedCounter.sort()

		#calculate the entropy of the measured fingerprints
		entropy = 0
		for anonSet in sortedCounter:
			probability = anonSet/self.numUsers
			entropy += probability*-math.log(probability,2)

		#calculate the number of unique users
		unique = 0
		for anonSet in sortedCounter:
			if anonSet == 1:
				unique += 1

		#write the raw data
		data_dump = json.dumps({"analyseFingerprinter":self.__analyseFingerprinter.messuredFingerprints,"checkFingerprinter":self.__checkFingerprinter.messuredFingerprints})
		try:
			os.stat(sys.argv[7]+"/data/run"+str(run))
		except:
			os.mkdir(sys.argv[7]+"/data/run"+str(run))
		file = open(sys.argv[7]+"/data/run"+str(run)+"/tick"+str(tick),"w")
		file.write(data_dump)
		file.close()
		
		#get the size of the biggest anonymity-set
		maxAnon = sortedCounter[-1]

		global numForges

		#the result for this tick
		roundResult = {}

		#add the data to the result
		roundResult["touched1hop"] = touched1hop
		roundResult["forgedTouched1hop"] = forgedTouched1hop
		roundResult["touched2hop"] = touched2hop
		roundResult["forgedTouched2hop"] = forgedTouched2hop
		roundResult["touched3hop"] = touched3hop
		roundResult["forgedTouched3hop"] = forgedTouched3hop

		roundResult["fullsizeAnon"] = fullsizeAnon
		roundResult["fullsizeForgedAnon"] = fullsizeForgedAnon
		roundResult["detectableFixed"] = detectableFixed
		roundResult["numChanges"] = numChanges
		roundResult["numFingerprints"] = numFingerprints
		roundResult["sizeAllForgedAnon"] = sizeAllForgedAnon
		roundResult["percentTouched"] = percentTouched
		roundResult["sizeForgedAnon"] = sizeForgedAnon

		roundResult["unique"]  = unique
		roundResult["maxAnon"] = maxAnon
		roundResult["forgerEntropy"]  = self.forgerEntropy
		roundResult["forgerAnonset"]  = self.forgerAnonset

		roundResult["Nutzer1"]         = 0
		roundResult["Nutzer2"]         = 0
		roundResult["Nutzer2-9"]       = 0
		roundResult["Nutzer10+"]       = 0
		for anonSet in sortedCounter:
			if anonSet == 1:
				roundResult["Nutzer1"] += 1
			if anonSet == 2:
				roundResult["Nutzer2"] += 2
			if anonSet >= 2 and anonSet <= 9:
				roundResult["Nutzer2-9"] += anonSet
			if anonSet >= 10:
				roundResult["Nutzer10+"] += anonSet
		roundResult["Nutzer1"]       /= self.numUsers
		roundResult["Nutzer2"]       /= self.numUsers
		roundResult["Nutzer2-9"]     /= self.numUsers
		roundResult["Nutzer10+"]     /= self.numUsers
		
		
		roundResult["Entropie"] = entropy
		roundResult["forges"] = numForges

		roundResult["num users"]     = self.numUsers
		roundResult["anon1"]         = sortedCounter[-1]
		try:
			roundResult["anon2"]         = sortedCounter[-2]
		except:
			roundResult["anon2"]         = float('nan')
		try:
			roundResult["anon3"]         = sortedCounter[-3]
		except:
			roundResult["anon3"]         = float('nan')
		try:
			roundResult["anon4"]         = sortedCounter[-4]
		except:
			roundResult["anon4"]         = float('nan')
		try:
			roundResult["anon5"]         = sortedCounter[-5]
		except:
			roundResult["anon5"]         = float('nan')
		try:
			roundResult["anon6"]         = sortedCounter[-6]
		except:
			roundResult["anon6"]         = float('nan')
		try:
			roundResult["anon7"]         = sortedCounter[-7]
		except:
			roundResult["anon7"]         = float('nan')
		try:
			roundResult["anon8"]         = sortedCounter[-8]
		except:
			roundResult["anon8"]         = float('nan')
		try:
			roundResult["anon9"]         = sortedCounter[-9]
		except:
			roundResult["anon9"]         = float('nan')
		try:
			roundResult["anon10"]        = sortedCounter[-10]
		except:
			roundResult["anon10"]        = float('nan')

		#print the temporary result
		print(roundResult)

		#add the result for the tick to the general result
		self.__result.append(roundResult)

	#end the simulation
	#return:
	#       the data collected in the simulation
	def finish(self):
		print("finished")
		return self.__result

	#generate a new user
	#return:
	#       the new user
	def __generateUser(self):
		#the propabilities for generating users
		highProbability = 0.69
		lowProbability = 0.36

		#generate the fingerprint for the new user
		attributes = {}
		counter = 0
		#choose a distribution for unique users or big anonymity sets
		if random.random() < 0.1:
			while counter < 10:
				attributes[counter] = np.random.geometric(highProbability)+10
				counter += 1
		else:
			while counter < 10:
				attributes[counter] = np.random.geometric(lowProbability)+10
				counter += 1

		#set the fingerprinters to visit
		fingerprinters = [self.__analyseFingerprinter,self.__checkFingerprinter]

		#generate either a forger or a normal user
		if random.random() < float(sys.argv[5]):
			#return a normal user
			return User(attributes,fingerprinters)
		else:
			#make some attributes unchangeble
			static = []
			counter = 0
			while counter < 10:
				if random.random() < float(sys.argv[6]):
					static.append(counter)

				counter += 1

			#increment the total number of forges
			global numForges
			numForges += 1

			#create the forgers
			user = ForgingUser(attributes,fingerprinters,static)

			#add the forger to the list of forgers
			self.forgers.append(user)

			#return the new forger
			return user

#seed the random generators with a fixed seed
random.seed(sys.argv[8])
np.random.seed(int(sys.argv[8]))

#container for the results
allData = []
finalResult = []

#set the number of runs to do
numRuns = int(sys.argv[1])

#set up dummies for each part of the results
counter = 0
while counter < int(sys.argv[3]):
	tmpResult = {}
	tmpResult["touched1hop"]   = 0
	tmpResult["forgedTouched1hop"]   = 0
	tmpResult["touched2hop"]   = 0
	tmpResult["forgedTouched2hop"]   = 0
	tmpResult["touched3hop"]   = 0
	tmpResult["forgedTouched3hop"]   = 0
	tmpResult["fullsizeAnon"]   = 0
	tmpResult["sizeAllForgedAnon"]   = 0
	tmpResult["percentTouched"]   = 0
	tmpResult["fullsizeForgedAnon"]   = 0
	tmpResult["detectableFixed"]   = 0
	tmpResult["numChanges"]   = 0
	tmpResult["numFingerprints"]   = 0
	tmpResult["sizeForgedAnon"]   = 0
	tmpResult["forgerEntropy"]   = 0
	tmpResult["Nutzer1"]          = 0
	tmpResult["Nutzer2"]          = 0
	tmpResult["Nutzer2-9"]        = 0
	tmpResult["Nutzer10+"]        = 0
	tmpResult["num users"]        = 0
	tmpResult["anon1"]            = 0
	tmpResult["anon2"]            = 0
	tmpResult["anon3"]            = 0
	tmpResult["anon4"]            = 0
	tmpResult["anon5"]            = 0
	tmpResult["anon6"]            = 0
	tmpResult["anon7"]            = 0
	tmpResult["anon8"]            = 0
	tmpResult["anon9"]            = 0
	tmpResult["anon10"]           = 0
	tmpResult["Entropie"]         = 0
	tmpResult["forges"]         = 0
	tmpResult["tick"]           = 0

	finalResult.append(tmpResult)
	
	counter += 1

#create the folder to write the data into
import os
try:
	os.stat(sys.argv[7])
except:
	os.mkdir(sys.argv[7])

try:
	os.stat(sys.argv[7]+"/data/")
except:
	os.mkdir(sys.argv[7]+"/data/")

#run the simulation and average the results
counter = 0
while (counter < numRuns):
	#the number of users created yet (used for the userids)
	userCounter = 0

	counter += 1

	#run the simulation and get its result
	simulation = Simulation(numUsers=int(sys.argv[2]))
	simulation.run(int(sys.argv[3]),counter)
	result = simulation.finish()

	#add the round results to the complete result
	allData.append(result)

	#print some eyecandy
	print("")
	print("run: "+str(counter))
	print(result)
	print("")
	
	#add the round results to the complete result
	counter2 = 0
	while counter2 < int(sys.argv[3]):
		result[counter2]["tick"] = counter2+1

		finalResult[counter2]["touched1hop"]	+= result[counter2]["touched1hop"]
		finalResult[counter2]["forgedTouched1hop"]	+= result[counter2]["forgedTouched1hop"]
		finalResult[counter2]["touched2hop"]	+= result[counter2]["touched2hop"]
		finalResult[counter2]["forgedTouched2hop"]	+= result[counter2]["forgedTouched2hop"]
		finalResult[counter2]["touched3hop"]	+= result[counter2]["touched3hop"]
		finalResult[counter2]["forgedTouched3hop"]	+= result[counter2]["forgedTouched3hop"]
		finalResult[counter2]["fullsizeAnon"]	+= result[counter2]["fullsizeAnon"]
		finalResult[counter2]["fullsizeForgedAnon"]	+= result[counter2]["fullsizeForgedAnon"]
		finalResult[counter2]["detectableFixed"]	+= result[counter2]["detectableFixed"]
		finalResult[counter2]["numChanges"]	+= result[counter2]["numChanges"]
		finalResult[counter2]["numFingerprints"]	+= result[counter2]["numFingerprints"]
		finalResult[counter2]["sizeAllForgedAnon"]	+= result[counter2]["sizeAllForgedAnon"]
		finalResult[counter2]["percentTouched"]	+= result[counter2]["percentTouched"]
		finalResult[counter2]["sizeForgedAnon"]	+= result[counter2]["sizeForgedAnon"]
		finalResult[counter2]["forgerEntropy"]	+= result[counter2]["forgerEntropy"]
		finalResult[counter2]["Nutzer1"]	+= result[counter2]["Nutzer1"]
		finalResult[counter2]["Nutzer2"]	+= result[counter2]["Nutzer2"]
		finalResult[counter2]["Nutzer2-9"]	+= result[counter2]["Nutzer2-9"]
		finalResult[counter2]["Nutzer10+"]	+= result[counter2]["Nutzer10+"]
		finalResult[counter2]["num users"]	+= result[counter2]["num users"]
		finalResult[counter2]["anon1"]		+= result[counter2]["anon1"]
		finalResult[counter2]["anon2"]		+= result[counter2]["anon2"]
		finalResult[counter2]["anon3"]		+= result[counter2]["anon3"]
		finalResult[counter2]["anon4"]		+= result[counter2]["anon4"]
		finalResult[counter2]["anon5"]		+= result[counter2]["anon5"]
		finalResult[counter2]["anon6"]		+= result[counter2]["anon6"]
		finalResult[counter2]["anon7"]		+= result[counter2]["anon7"]
		finalResult[counter2]["anon8"]		+= result[counter2]["anon8"]
		finalResult[counter2]["anon9"]		+= result[counter2]["anon9"]
		finalResult[counter2]["anon10"]		+= result[counter2]["anon10"]
		finalResult[counter2]["Entropie"]	+= result[counter2]["Entropie"]
		finalResult[counter2]["forges"]		+= result[counter2]["forges"]
		finalResult[counter2]["tick"]		+= result[counter2]["tick"]

		counter2 += 1

#finish calculating the average
counter = 0
while counter < int(sys.argv[3]):
	finalResult[counter]["touched1hop"]	/= numRuns
	finalResult[counter]["forgedTouched1hop"]	/= numRuns
	finalResult[counter]["touched2hop"]	/= numRuns
	finalResult[counter]["forgedTouched2hop"]	/= numRuns
	finalResult[counter]["touched3hop"]	/= numRuns
	finalResult[counter]["forgedTouched3hop"]	/= numRuns
	finalResult[counter]["fullsizeAnon"]	/= numRuns
	finalResult[counter]["fullsizeForgedAnon"]	/= numRuns
	finalResult[counter]["detectableFixed"]	/= numRuns
	finalResult[counter]["numChanges"]	/= numRuns
	finalResult[counter]["numFingerprints"]	/= numRuns
	finalResult[counter]["sizeAllForgedAnon"]	/= numRuns
	finalResult[counter]["percentTouched"]	/= numRuns
	finalResult[counter]["sizeForgedAnon"]	/= numRuns
	finalResult[counter]["forgerEntropy"]	/= numRuns
	finalResult[counter]["Nutzer1"]		/= numRuns
	finalResult[counter]["Nutzer2"]		/= numRuns
	finalResult[counter]["Nutzer2-9"]	/= numRuns
	finalResult[counter]["Nutzer10+"]	/= numRuns
	finalResult[counter]["num users"]	/= numRuns
	finalResult[counter]["anon1"]		/= numRuns
	finalResult[counter]["anon2"]		/= numRuns
	finalResult[counter]["anon3"]		/= numRuns
	finalResult[counter]["anon4"]		/= numRuns
	finalResult[counter]["anon5"]		/= numRuns
	finalResult[counter]["anon6"]		/= numRuns
	finalResult[counter]["anon7"]		/= numRuns
	finalResult[counter]["anon8"]		/= numRuns
	finalResult[counter]["anon9"]		/= numRuns
	finalResult[counter]["anon10"]		/= numRuns
	finalResult[counter]["Entropie"]	/= numRuns
	finalResult[counter]["forges"]		/= numRuns
	finalResult[counter]["tick"]		/= numRuns

	counter += 1

#calculate the variance
varianz = []

counter = 0
while counter < int(sys.argv[3]):
	tmpResult = {}
	tmpResult["touched1hop"]   = 0
	tmpResult["forgedTouched1hop"]   = 0
	tmpResult["touched2hop"]   = 0
	tmpResult["forgedTouched2hop"]   = 0
	tmpResult["touched3hop"]   = 0
	tmpResult["forgedTouched3hop"]   = 0
	tmpResult["fullsizeAnon"]   = 0
	tmpResult["fullsizeForgedAnon"]   = 0
	tmpResult["detectableFixed"]   = 0
	tmpResult["numChanges"]   = 0
	tmpResult["numFingerprints"]   = 0
	tmpResult["sizeAllForgedAnon"]   = 0
	tmpResult["percentTouched"]   = 0
	tmpResult["sizeForgedAnon"]   = 0
	tmpResult["forgerEntropy"]   = 0
	tmpResult["Nutzer1"]          = 0
	tmpResult["Nutzer2"]          = 0
	tmpResult["Nutzer2-9"]        = 0
	tmpResult["Nutzer10+"]        = 0
	tmpResult["num users"]        = 0
	tmpResult["anon1"]            = 0
	tmpResult["anon2"]            = 0
	tmpResult["anon3"]            = 0
	tmpResult["anon4"]            = 0
	tmpResult["anon5"]            = 0
	tmpResult["anon6"]            = 0
	tmpResult["anon7"]            = 0
	tmpResult["anon8"]            = 0
	tmpResult["anon9"]            = 0
	tmpResult["anon10"]           = 0
	tmpResult["Entropie"]         = 0
	tmpResult["forges"]           = 0
	tmpResult["tick"]             = 0

	varianz.append(tmpResult)
	
	counter += 1

counter = 0
while (counter < numRuns):
	counter2 = 0
	while counter2 < int(sys.argv[3]):
		varianz[counter2]["touched1hop"]	+= math.pow(allData[counter][counter2]["touched1hop"]-finalResult[counter2]["touched1hop"],2)
		varianz[counter2]["forgedTouched1hop"]	+= math.pow(allData[counter][counter2]["forgedTouched1hop"]-finalResult[counter2]["forgedTouched1hop"],2)
		varianz[counter2]["touched2hop"]	+= math.pow(allData[counter][counter2]["touched2hop"]-finalResult[counter2]["touched2hop"],2)
		varianz[counter2]["forgedTouched2hop"]	+= math.pow(allData[counter][counter2]["forgedTouched2hop"]-finalResult[counter2]["forgedTouched2hop"],2)
		varianz[counter2]["touched3hop"]	+= math.pow(allData[counter][counter2]["touched3hop"]-finalResult[counter2]["touched3hop"],2)
		varianz[counter2]["forgedTouched3hop"]	+= math.pow(allData[counter][counter2]["forgedTouched3hop"]-finalResult[counter2]["forgedTouched3hop"],2)
		varianz[counter2]["fullsizeAnon"]	+= math.pow(allData[counter][counter2]["fullsizeAnon"]-finalResult[counter2]["fullsizeAnon"],2)
		varianz[counter2]["fullsizeForgedAnon"]	+= math.pow(allData[counter][counter2]["fullsizeForgedAnon"]-finalResult[counter2]["fullsizeForgedAnon"],2)
		varianz[counter2]["detectableFixed"]	+= math.pow(allData[counter][counter2]["detectableFixed"]-finalResult[counter2]["detectableFixed"],2)
		varianz[counter2]["numChanges"]	+= math.pow(allData[counter][counter2]["numChanges"]-finalResult[counter2]["numChanges"],2)
		varianz[counter2]["numFingerprints"]	+= math.pow(allData[counter][counter2]["numFingerprints"]-finalResult[counter2]["numFingerprints"],2)
		varianz[counter2]["sizeAllForgedAnon"]	+= math.pow(allData[counter][counter2]["sizeAllForgedAnon"]-finalResult[counter2]["sizeAllForgedAnon"],2)
		varianz[counter2]["percentTouched"]	+= math.pow(allData[counter][counter2]["percentTouched"]-finalResult[counter2]["percentTouched"],2)
		varianz[counter2]["sizeForgedAnon"]	+= math.pow(allData[counter][counter2]["sizeForgedAnon"]-finalResult[counter2]["sizeForgedAnon"],2)
		varianz[counter2]["forgerEntropy"]	+= math.pow(allData[counter][counter2]["forgerEntropy"]-finalResult[counter2]["forgerEntropy"],2)
		varianz[counter2]["Nutzer1"]	+= math.pow(allData[counter][counter2]["Nutzer1"]-finalResult[counter2]["Nutzer1"],2)
		varianz[counter2]["Nutzer2"]	+= math.pow(allData[counter][counter2]["Nutzer2"]-finalResult[counter2]["Nutzer2"],2)
		varianz[counter2]["Nutzer2-9"]	+= math.pow(allData[counter][counter2]["Nutzer2-9"]-finalResult[counter2]["Nutzer2-9"],2)
		varianz[counter2]["Nutzer10+"]	+= math.pow(allData[counter][counter2]["Nutzer10+"]-finalResult[counter2]["Nutzer10+"],2)
		varianz[counter2]["num users"]	+= math.pow(allData[counter][counter2]["num users"]-finalResult[counter2]["num users"],2)
		varianz[counter2]["anon1"]	+= math.pow(allData[counter][counter2]["anon1"]-finalResult[counter2]["anon1"],2)
		varianz[counter2]["anon2"]	+= math.pow(allData[counter][counter2]["anon2"]-finalResult[counter2]["anon2"],2)
		varianz[counter2]["anon3"]	+= math.pow(allData[counter][counter2]["anon3"]-finalResult[counter2]["anon3"],2)
		varianz[counter2]["anon4"]	+= math.pow(allData[counter][counter2]["anon4"]-finalResult[counter2]["anon4"],2)
		varianz[counter2]["anon5"]	+= math.pow(allData[counter][counter2]["anon5"]-finalResult[counter2]["anon5"],2)
		varianz[counter2]["anon6"]	+= math.pow(allData[counter][counter2]["anon6"]-finalResult[counter2]["anon6"],2)
		varianz[counter2]["anon7"]	+= math.pow(allData[counter][counter2]["anon7"]-finalResult[counter2]["anon7"],2)
		varianz[counter2]["anon8"]	+= math.pow(allData[counter][counter2]["anon8"]-finalResult[counter2]["anon8"],2)
		varianz[counter2]["anon9"]	+= math.pow(allData[counter][counter2]["anon9"]-finalResult[counter2]["anon9"],2)
		varianz[counter2]["anon10"]	+= math.pow(allData[counter][counter2]["anon10"]-finalResult[counter2]["anon10"],2)
		varianz[counter2]["Entropie"]	+= math.pow(allData[counter][counter2]["Entropie"]-finalResult[counter2]["Entropie"],2)
		varianz[counter2]["forges"]	+= math.pow(allData[counter][counter2]["forges"]-finalResult[counter2]["forges"],2)
		varianz[counter2]["tick"]	+= math.pow(allData[counter][counter2]["tick"]-finalResult[counter2]["tick"],2)
	
		counter2 += 1

	counter += 1

counter = 0
while counter < int(sys.argv[3]):
	varianz[counter]["touched1hop"]	/= numRuns
	varianz[counter]["forgedTouched1hop"]	/= numRuns
	varianz[counter]["touched2hop"]	/= numRuns
	varianz[counter]["forgedTouched2hop"]	/= numRuns
	varianz[counter]["touched3hop"]	/= numRuns
	varianz[counter]["forgedTouched3hop"]	/= numRuns
	varianz[counter]["fullsizeAnon"]	/= numRuns
	varianz[counter]["fullsizeForgedAnon"]	/= numRuns
	varianz[counter]["detectableFixed"]	/= numRuns
	varianz[counter]["numChanges"]	/= numRuns
	varianz[counter]["numFingerprints"]	/= numRuns
	varianz[counter]["sizeAllForgedAnon"]	/= numRuns
	varianz[counter]["percentTouched"]	/= numRuns
	varianz[counter]["sizeForgedAnon"]	/= numRuns
	varianz[counter]["forgerEntropy"]	/= numRuns
	varianz[counter]["Nutzer1"]	/= numRuns
	varianz[counter]["Nutzer2"]	/= numRuns
	varianz[counter]["Nutzer2-9"]	/= numRuns
	varianz[counter]["Nutzer10+"]	/= numRuns
	varianz[counter]["num users"]	/= numRuns
	varianz[counter]["anon1"]	/= numRuns
	varianz[counter]["anon2"]	/= numRuns
	varianz[counter]["anon3"]	/= numRuns
	varianz[counter]["anon4"]	/= numRuns
	varianz[counter]["anon5"]	/= numRuns
	varianz[counter]["anon6"]	/= numRuns
	varianz[counter]["anon7"]	/= numRuns
	varianz[counter]["anon8"]	/= numRuns
	varianz[counter]["anon9"]	/= numRuns
	varianz[counter]["anon10"]	/= numRuns
	varianz[counter]["Entropie"]	/= numRuns
	varianz[counter]["forges"]	/= numRuns
	varianz[counter]["tick"]	/= numRuns

	counter += 1

#calculate the coefficient of variation
varianzKoeff = []

counter = 0
while counter < int(sys.argv[3]):
	tmpResult = {}
	try:
		tmpResult["touched1hop"]        = math.sqrt(varianz[counter]["touched1hop"])/finalResult[counter]["touched1hop"]
	except:
		tmpResult["touched1hop"]          = float('nan')
	try:
		tmpResult["forgedTouched1hop"]        = math.sqrt(varianz[counter]["forgedTouched1hop"])/finalResult[counter]["forgedTouched1hop"]
	except:
		tmpResult["forgedTouched1hop"]          = float('nan')
	try:
		tmpResult["touched2hop"]        = math.sqrt(varianz[counter]["touched2hop"])/finalResult[counter]["touched2hop"]
	except:
		tmpResult["touched2hop"]          = float('nan')
	try:
		tmpResult["forgedTouched2hop"]        = math.sqrt(varianz[counter]["forgedTouched2hop"])/finalResult[counter]["forgedTouched2hop"]
	except:
		tmpResult["forgedTouched2hop"]          = float('nan')
	try:
		tmpResult["touched3hop"]        = math.sqrt(varianz[counter]["touched3hop"])/finalResult[counter]["touched3hop"]
	except:
		tmpResult["touched3hop"]          = float('nan')
	try:
		tmpResult["forgedTouched3hop"]        = math.sqrt(varianz[counter]["forgedTouched3hop"])/finalResult[counter]["forgedTouched3hop"]
	except:
		tmpResult["forgedTouched3hop"]          = float('nan')
	try:
		tmpResult["fullsizeAnon"]        = math.sqrt(varianz[counter]["fullsizeAnon"])/finalResult[counter]["fullsizeAnon"]
	except:
		tmpResult["fullsizeAnon"]          = float('nan')
	try:
		tmpResult["detectableFixed"]        = math.sqrt(varianz[counter]["detectableFixed"])/finalResult[counter]["detectableFixed"]
	except:
		tmpResult["detectableFixed"]          = float('nan')
	try:
		tmpResult["fullsizeForgedAnon"]        = math.sqrt(varianz[counter]["fullsizeForgedAnon"])/finalResult[counter]["fullsizeForgedAnon"]
	except:
		tmpResult["fullsizeForgedAnon"]          = float('nan')
	try:
		tmpResult["numChanges"]        = math.sqrt(varianz[counter]["numChanges"])/finalResult[counter]["numChanges"]
	except:
		tmpResult["numChanges"]          = float('nan')
	try:
		tmpResult["numFingerprints"]        = math.sqrt(varianz[counter]["numFingerprints"])/finalResult[counter]["numFingerprints"]
	except:
		tmpResult["numFingerprints"]          = float('nan')
	try:
		tmpResult["sizeAllForgedAnon"]        = math.sqrt(varianz[counter]["sizeAllForgedAnon"])/finalResult[counter]["sizeAllForgedAnon"]
	except:
		tmpResult["sizeAllForgedAnon"]          = float('nan')
	try:
		tmpResult["percentTouched"]        = math.sqrt(varianz[counter]["percentTouched"])/finalResult[counter]["percentTouched"]
	except:
		tmpResult["percentTouched"]          = float('nan')
	try:
		tmpResult["sizeForgedAnon"]        = math.sqrt(varianz[counter]["sizeForgedAnon"])/finalResult[counter]["sizeForgedAnon"]
	except:
		tmpResult["sizeForgedAnon"]          = float('nan')
	try:
		tmpResult["forgerEntropy"]        = math.sqrt(varianz[counter]["forgerEntropy"])/finalResult[counter]["forgerEntropy"]
	except:
		tmpResult["forgerEntropy"]          = float('nan')
	try:
		tmpResult["Nutzer1"]          = math.sqrt(varianz[counter]["Nutzer1"])/finalResult[counter]["Nutzer1"]
	except:
		tmpResult["Nutzer1"]          = float('nan')
	try:
		tmpResult["Nutzer2"]          = math.sqrt(varianz[counter]["Nutzer2"])/finalResult[counter]["Nutzer2"]
	except:
		tmpResult["Nutzer2"]          = float('nan')
	try:
		tmpResult["Nutzer2-9"]        = math.sqrt(varianz[counter]["Nutzer2-9"])/finalResult[counter]["Nutzer2-9"]
	except:
		tmpResult["Nutzer2-9"]          = float('nan')
	try:
		tmpResult["Nutzer10+"]        = math.sqrt(varianz[counter]["Nutzer10+"])/finalResult[counter]["Nutzer10+"]
	except:
		tmpResult["Nutzer10+"]          = float('nan')
	tmpResult["num users"]        = math.sqrt(varianz[counter]["num users"])/finalResult[counter]["num users"]
	tmpResult["anon1"]            = math.sqrt(varianz[counter]["anon1"])/finalResult[counter]["anon1"]
	tmpResult["anon2"]            = math.sqrt(varianz[counter]["anon2"])/finalResult[counter]["anon2"]
	tmpResult["anon3"]            = math.sqrt(varianz[counter]["anon3"])/finalResult[counter]["anon3"]
	tmpResult["anon4"]            = math.sqrt(varianz[counter]["anon4"])/finalResult[counter]["anon4"]
	tmpResult["anon5"]            = math.sqrt(varianz[counter]["anon5"])/finalResult[counter]["anon5"]
	tmpResult["anon6"]            = math.sqrt(varianz[counter]["anon6"])/finalResult[counter]["anon6"]
	tmpResult["anon7"]            = math.sqrt(varianz[counter]["anon7"])/finalResult[counter]["anon7"]
	tmpResult["anon8"]            = math.sqrt(varianz[counter]["anon8"])/finalResult[counter]["anon8"]
	tmpResult["anon9"]            = math.sqrt(varianz[counter]["anon9"])/finalResult[counter]["anon9"]
	tmpResult["anon10"]           = math.sqrt(varianz[counter]["anon10"])/finalResult[counter]["anon10"]
	try:
		tmpResult["Entropie"]         = math.sqrt(varianz[counter]["Entropie"])/finalResult[counter]["Entropie"]
	except:
		tmpResult["Entropie"]          = float('nan')
	tmpResult["forges"]           = math.sqrt(varianz[counter]["forges"])/finalResult[counter]["forges"]
	tmpResult["tick"]             = math.sqrt(varianz[counter]["tick"])/finalResult[counter]["tick"]

	varianzKoeff.append(tmpResult)
	
	counter += 1

#save the detailed result
data_dump = json.dumps(allData)
file = open(sys.argv[7]+"/condensedData","w")
file.write(data_dump)
file.close()

#add the variance and coeffient of variation
counter = 0
while counter < int(sys.argv[3]):
	finalResult[counter]["varianz"]          = varianz[counter]
	finalResult[counter]["varKoeff"]         = varianzKoeff[counter]

	counter += 1

#print the result
print(finalResult)

#save the averaged result
result_dump = json.dumps(finalResult)
file = open(sys.argv[7]+"/results","w")
file.write(result_dump)
file.close()
