private void addMetadataIter(CfgManipulator cfgManipulator, GraphRandomStateGenerator randomStateGenerator, MethodCfg originalMethodCfg, MethodCfg methodCfg, BasicBlock startBasicBlock, LocalDefinition intStateLocal, LocalDefinition currentNodeLocal) {

            int currentValidPathId;

            // create transformation metadata for the start basic block
            GraphTransformerMetadataBasicBlock metadata = new GraphTransformerMetadataBasicBlock();

            for (currentValidPathId = 0; currentValidPathId < this.graph.graphValidPathCount; currentValidPathId++) {
                BasicBlockGraphNodeLink link = new BasicBlockGraphNodeLink(this.graph.startingNode, currentValidPathId);
                metadata.correspondingGraphNodes.Add(link);
            }

            startBasicBlock.transformationMetadata.Add(metadata);

            // create a list of basic blocks that still have to be processed by the algorithm
            List<BasicBlock> basicBlocksToProcess = new List<BasicBlock>(methodCfg.basicBlocks);
            basicBlocksToProcess.Remove(startBasicBlock);

            System.Console.WriteLine("Basic Blocks to process (Metadata): " + basicBlocksToProcess.Count());

            // add metadata to all basic blocks
            while (true) {

                List<BasicBlock> copiedList = new List<BasicBlock>(basicBlocksToProcess);
                foreach (BasicBlock currentBasicBlock in copiedList) {

                    // check if the current basic block was already visited => it is already used for the graph obfuscation => skip it
                    bool hasGraphMetadata = false;
                    for (int i = 0; i < currentBasicBlock.transformationMetadata.Count(); i++) {
                        // get graph transformer metadata for basic blocks
                        if ((currentBasicBlock.transformationMetadata.ElementAt(i) as IGraphTransformerMetadata) == null) {
                            continue;
                        }
                        hasGraphMetadata = true;
                        break;
                    }
                    if (hasGraphMetadata) {
                        basicBlocksToProcess.Remove(currentBasicBlock);
                        continue;
                    }

                    if (!this.createAndAddMetadata(currentBasicBlock)) { 
                        continue;
                    }

                    // remove current basic block from the list of basic blocks to process
                    basicBlocksToProcess.Remove(currentBasicBlock);

                }

                System.Console.WriteLine("Basic Blocks to process (Metadata): " + basicBlocksToProcess.Count());

                // check if basic blocks exist to process => if not break loop
                if (basicBlocksToProcess.Count() == 0) {
                    break;
                }

            }

        }
        // this functions creates metadata for the given basic block and adds it
        private bool createAndAddMetadata(BasicBlock currentBasicBlock) {

            // get metadata of entry basic block (if exists)
            IGraphTransformerMetadata previousMetadata = null;
            BasicBlock previousBasicBlock = null;
            IBranchTarget previousExitBranch = null;
            for (int i = 0; i < currentBasicBlock.entryBranches.Count(); i++) {

                previousBasicBlock = currentBasicBlock.entryBranches.ElementAt(i).sourceBasicBlock;

                for (int j = 0; j < previousBasicBlock.transformationMetadata.Count(); j++) {
                    // get graph transformer metadata for basic blocks
                    if ((previousBasicBlock.transformationMetadata.ElementAt(j) as IGraphTransformerMetadata) == null) {
                        continue;
                    }
                    previousMetadata = (previousBasicBlock.transformationMetadata.ElementAt(j) as IGraphTransformerMetadata);
                    previousExitBranch = currentBasicBlock.entryBranches.ElementAt(i);
                    break;
                }
                if (previousMetadata != null) {
                    break;
                }
            }
            // skip basic block if there is no metadata in one of the entry basic blocks
            if (previousMetadata == null) { // TODO: here is room for optimization => do not skip it
                return false;
            }
            List<BasicBlockGraphNodeLink> previousLinks = previousMetadata.correspondingGraphNodes;

            // choose the next nodes of the obfuscation graph for the current basic block
            NodeObject[] currentNodes = new NodeObject[this.graph.graphValidPathCount];

            // check if previous basic block has links to the obfuscation graph for all existing valid paths
            // (if previous basic block for example was a "state change" basic block it can only have one link to the obfuscation graph)
            // => just copy obfuscation graph nodes of previous basic block if it contains all valid paths
            if (previousLinks.Count() == this.graph.graphValidPathCount) {
                for (int currentValidPathId = 0; currentValidPathId < this.graph.graphValidPathCount; currentValidPathId++) {
                    bool found = false;
                    for (int i = 0; i < previousLinks.Count(); i++) {
                        if (previousLinks.ElementAt(i).validPathId == currentValidPathId) {
                            currentNodes[currentValidPathId] = previousLinks.ElementAt(i).graphNode;
                            found = true;
                            break;
                        }
                    }
                    if (!found) {
                        throw new ArgumentException("Was not able to find link to obfuscation graph in previous basic block for at least one valid path.");
                    }
                }
            }

            // previous basic block does not contain all valid paths
            // => copy all existing valid paths links and choose random links for the missing ones
            else {

                for (int currentValidPathId = 0; currentValidPathId < this.graph.graphValidPathCount; currentValidPathId++) {
                    bool found = false;
                    for (int i = 0; i < previousLinks.Count(); i++) {
                        if (previousLinks.ElementAt(i).validPathId == currentValidPathId) {
                            currentNodes[currentValidPathId] = previousLinks.ElementAt(i).graphNode;
                            found = true;
                            break;
                        }
                    }

                    // if a link for the current valid path does not exist
                    // => choose randomly a node in the obfuscation graph on the current valid path
                    if (!found) {
                        int moveCount = this.prng.Next(this.graphDepth);
                        NodeObject nextNode = this.graph.startingNode;
                        for (int move = 0; move < moveCount; move++) {
                            for (int i = 0; i < nextNode.nodeObjects.Count(); i++) {

                                // if the child node does not belong to a valid path
                                // => skip it
                                if (nextNode.nodeObjects[i].elementOfValidPath.Count() == 0) {
                                    continue;
                                }

                                // the child node belongs to a valid path
                                // => check if it is the correct valid path
                                else {
                                    // if the child node belongs to the correct valid path
                                    // => set next node to it
                                    if (nextNode.nodeObjects[i].elementOfValidPath.Contains(currentValidPathId)) {
                                        nextNode = nextNode.nodeObjects[i];
                                        break;
                                    }
                                }
                            }
                            if (nextNode == null) {
                                throw new ArgumentException("Not able to find correct child node.");
                            }
                        }

                        currentNodes[currentValidPathId] = nextNode;

                    }
                }
            }

            NodeObject[] nextNodes = new NodeObject[this.graph.graphValidPathCount];
            for (int currentValidPathId = 0; currentValidPathId < currentNodes.Count(); currentValidPathId++) {

                // choose randomly if the pointer of the current valid path should be moved forward
                // => move the pointer of the current valid path forward
                if (this.prng.Next(2) == 0) {

                    // get the next node of the valid path
                    NodeObject nextNode = null;
                    int nextNodeIdx = 0;
                    this.getNextNode(ref nextNode, ref nextNodeIdx, currentNodes, currentValidPathId);
                    nextNodes[currentValidPathId] = nextNode;

                }

                // => do not move the pointer of the current valid path forward
                else {

                    // set next node in the graph to the current one (it was not changed)
                    nextNodes[currentValidPathId] = currentNodes[currentValidPathId];

                }
            }

            // create transformation metadata for the current basic block
            GraphTransformerMetadataBasicBlock metadata = new GraphTransformerMetadataBasicBlock();

            for (int currentValidPathId = 0; currentValidPathId < this.graph.graphValidPathCount; currentValidPathId++) {
                BasicBlockGraphNodeLink link = new BasicBlockGraphNodeLink(nextNodes[currentValidPathId], currentValidPathId);
                metadata.correspondingGraphNodes.Add(link);
            }

            currentBasicBlock.transformationMetadata.Add(metadata);

            return true;

        }