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

            int currentValidPathId;

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

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

            while (true) {

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

                    // get the metadata for the current basic block
                    GraphTransformerMetadataBasicBlock metadata = null;
                    for (int i = 0; i < currentBasicBlock.transformationMetadata.Count(); i++) {
                        // get graph transformer metadata for basic blocks
                        if ((currentBasicBlock.transformationMetadata.ElementAt(i) as GraphTransformerMetadataBasicBlock) == null) {
                            continue;
                        }
                        metadata = (currentBasicBlock.transformationMetadata.ElementAt(i) as GraphTransformerMetadataBasicBlock);
                        break;
                    }
                    if (metadata == null) {
                        throw new ArgumentException("Not able to find metadata for current basic block.");
                    }

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

                    // check if the current exit branch is of type "no branch target"
                    if (currentBasicBlock.exitBranch as NoBranchTarget != null) {

                        NoBranchTarget introBranch = (NoBranchTarget)currentBasicBlock.exitBranch;

                        // search for all semantically equal basic blocks in the modified method CFG (as possible targets)
                        int searchSementicId = introBranch.takenTarget.semanticId;
                        List<BasicBlock> possibleTargetBasicBlocks = new List<BasicBlock>();
                        if (searchSementicId != -1) {
                            foreach (BasicBlock searchBasicBlock in methodCfg.basicBlocks) {
                                if (searchBasicBlock.semanticId == searchSementicId) {
                                    possibleTargetBasicBlocks.Add(searchBasicBlock);
                                }
                            }
                            if (possibleTargetBasicBlocks.Count() == 0) {
                                throw new ArgumentException("Not able to find any semantically equal basic block in CFG.");
                            }
                        }
                        else {
                            possibleTargetBasicBlocks.Add(introBranch.takenTarget);
                        }

                        // create a list of target basic blocks of this branch
                        List<Target> listOfTargets = new List<Target>();
                        Target target = new Target();
                        target.basicBlock = introBranch.takenTarget;
                        listOfTargets.Add(target);

                        // generate code for the "state switch"
                        BasicBlock stateBasicBlock = null;
                        SwitchBranchTarget stateExitBranch = null;
                        this.createCodeStateSwitch(ref stateBasicBlock, ref stateExitBranch, intStateLocal, metadata.correspondingGraphNodes);
                        cfgManipulator.insertBasicBlockBetweenBranch(introBranch, stateBasicBlock, stateExitBranch, 0);

                        // create for each valid path a branch in the switch statement of the "state switch"
                        for (currentValidPathId = 0; currentValidPathId < this.graph.graphValidPathCount; currentValidPathId++) {

                            // ignore first valid path (with id 0)
                            // => add artificial branch to original branch target (for the current valid path id)
                            if (currentValidPathId != 0) {

                                // fill switch taken branch list with null when index is out of range
                                while (stateExitBranch.takenTarget.Count() <= currentValidPathId) {
                                    stateExitBranch.takenTarget.Add(null);
                                }

                                // randomly chose what the target of the current branch should be (weight to use an existing basic block to have less memory consumption)
                                switch (this.prng.Next(this.duplicateBasicBlockWeight)) {
                                    case 0:
                                    case 1:
                                    case 2:
                                    case 3:
                                    case 4:
                                    case 5: {

                                            // duplicate the target basic block
                                            BasicBlock duplicatedBasicBlock = this.duplicateBasicBlock(originalMethodCfg, methodCfg, listOfTargets.ElementAt(0).basicBlock);
                                            methodCfg.basicBlocks.Add(duplicatedBasicBlock);
                                            basicBlocksToProcess.Add(duplicatedBasicBlock);

                                            // add new basic block as target of the switch case
                                            stateExitBranch.takenTarget[currentValidPathId] = duplicatedBasicBlock;
                                            duplicatedBasicBlock.entryBranches.Add(stateExitBranch);

                                            // add new basic block to the list of target basic blocks
                                            target = new Target();
                                            target.basicBlock = duplicatedBasicBlock;
                                            listOfTargets.Add(target);

                                            // add duplicated basic block to the list of possible target basic blocks
                                            possibleTargetBasicBlocks.Add(duplicatedBasicBlock);

                                            // create metadata for the newly created basic block
                                            if (!createAndAddMetadata(duplicatedBasicBlock)) {
                                                throw new ArgumentException("Creating metadata for the duplicated basic block failed.");
                                            }

                                            break;

                                        }
                                    default: {

                                            // use a random possible basic block as target
                                            int randPosition = this.prng.Next(possibleTargetBasicBlocks.Count());
                                            BasicBlock newTarget = possibleTargetBasicBlocks.ElementAt(randPosition);

                                            target = new Target();
                                            target.basicBlock = newTarget;
                                            listOfTargets.Add(target);

                                            // set switch taken branch for current valid path id to the chosen branch target
                                            stateExitBranch.takenTarget[currentValidPathId] = target.basicBlock;
                                            target.basicBlock.entryBranches.Add(stateExitBranch);

                                            break;

                                        }

                                }

                            }

                            // set current valid path id of the target
                            target.currentValidPathId = currentValidPathId;

                            // get the link from the current basic block to the obfuscation graph
                            BasicBlockGraphNodeLink currentGraphLink = null;
                            foreach (BasicBlockGraphNodeLink tempLink in metadata.correspondingGraphNodes) {
                                if (tempLink.validPathId == currentValidPathId) {
                                    currentGraphLink = tempLink;
                                    break;
                                }
                            }
                            if (currentGraphLink == null) {
                                throw new ArgumentNullException("Could not find link from current basic block to the graph for the given path id.");
                            }

                            // get the metadata for the target basic block
                            GraphTransformerMetadataBasicBlock targetMetadata = null;
                            for (int i = 0; i < target.basicBlock.transformationMetadata.Count(); i++) {
                                // get graph transformer metadata for basic blocks
                                if ((target.basicBlock.transformationMetadata.ElementAt(i) as GraphTransformerMetadataBasicBlock) == null) {
                                    continue;
                                }
                                targetMetadata = (target.basicBlock.transformationMetadata.ElementAt(i) as GraphTransformerMetadataBasicBlock);
                                break;
                            }
                            if (targetMetadata == null) {
                                throw new ArgumentException("Not able to find metadata for target basic block.");
                            }

                            // get the link from the target basic block to the obfuscation graph
                            BasicBlockGraphNodeLink targetGraphLink = null;
                            foreach (BasicBlockGraphNodeLink tempLink in targetMetadata.correspondingGraphNodes) {
                                if (tempLink.validPathId == currentValidPathId) {
                                    targetGraphLink = tempLink;
                                    break;
                                }
                            }
                            if (targetGraphLink == null) {
                                throw new ArgumentNullException("Could not find link from target basic block to the graph for the given path id.");
                            }

                            // choose randomly to either just correct the pointer position or to inject a "state change"
                            switch (this.prng.Next(this.stateChangeWeight)) {

                                // case: "state change"
                                case 0:
                                case 1:
                                case 2:
                                case 3:
                                case 4:
                                case 5: {

                                        // generate code for the "state change"
                                        BasicBlock stateChangeBasicBlock = null;
                                        SwitchBranchTarget stateChangeExitBranch = null;
                                        this.createCodeStateChange(ref stateChangeBasicBlock, ref stateChangeExitBranch, randomStateGenerator, currentGraphLink, intStateLocal); 
                                        cfgManipulator.insertBasicBlockBetweenBranch(stateExitBranch, currentValidPathId, stateChangeBasicBlock, stateChangeExitBranch, 0);

                                        // create for each valid path a branch in the switch statement of the "state change"
                                        for (int changedCurrentValidPathId = 0; changedCurrentValidPathId < this.graph.graphValidPathCount; changedCurrentValidPathId++) {

                                            // ignore first valid path (with id 0)
                                            // => add artificial branch to original branch target (for the changed current valid path id)
                                            if (changedCurrentValidPathId != 0) {

                                                // fill switch taken branch list with null when index is out of range
                                                while (stateChangeExitBranch.takenTarget.Count() <= changedCurrentValidPathId) {
                                                    stateChangeExitBranch.takenTarget.Add(null);
                                                }

                                                // randomly chose what the target of the current branch should be (weight to use an existing basic block to have less memory consumption)
                                                switch (this.prng.Next(this.duplicateBasicBlockWeight)) {
                                                    case 0:
                                                    case 1:
                                                    case 2:
                                                    case 3:
                                                    case 4:
                                                    case 5: {

                                                            // duplicate the target basic block
                                                            BasicBlock duplicatedBasicBlock = this.duplicateBasicBlock(originalMethodCfg, methodCfg, listOfTargets.ElementAt(0).basicBlock);
                                                            methodCfg.basicBlocks.Add(duplicatedBasicBlock);
                                                            basicBlocksToProcess.Add(duplicatedBasicBlock);

                                                            // add new basic block as target of the switch case
                                                            stateChangeExitBranch.takenTarget[changedCurrentValidPathId] = duplicatedBasicBlock;
                                                            duplicatedBasicBlock.entryBranches.Add(stateChangeExitBranch);

                                                            // add new basic block to the list of target basic blocks
                                                            target = new Target();
                                                            target.basicBlock = duplicatedBasicBlock;
                                                            listOfTargets.Add(target);

                                                            // add duplicated basic block to the list of possible target basic blocks
                                                            possibleTargetBasicBlocks.Add(duplicatedBasicBlock);

                                                            // create metadata for the newly created basic block
                                                            if (!createAndAddMetadata(duplicatedBasicBlock)) {
                                                                throw new ArgumentException("Creating metadata for the duplicated basic block failed.");
                                                            }

                                                            break;

                                                        }
                                                    default: {

                                                            // use a random possible basic block as target
                                                            int randPosition = this.prng.Next(possibleTargetBasicBlocks.Count());
                                                            BasicBlock newTarget = possibleTargetBasicBlocks.ElementAt(randPosition);

                                                            target = new Target();
                                                            target.basicBlock = newTarget;
                                                            listOfTargets.Add(target);

                                                            // set switch taken branch for current valid path id to the chosen branch target
                                                            stateChangeExitBranch.takenTarget[changedCurrentValidPathId] = target.basicBlock;
                                                            target.basicBlock.entryBranches.Add(stateChangeExitBranch);

                                                            break;

                                                        }
                                                }

                                            }

                                            // set current valid path id of the target
                                            target.currentValidPathId = changedCurrentValidPathId;

                                            // get the metadata for the change target basic block
                                            GraphTransformerMetadataBasicBlock changeTargetMetadata = null;
                                            for (int i = 0; i < target.basicBlock.transformationMetadata.Count(); i++) {
                                                // get graph transformer metadata for basic blocks
                                                if ((target.basicBlock.transformationMetadata.ElementAt(i) as GraphTransformerMetadataBasicBlock) == null) {
                                                    continue;
                                                }
                                                changeTargetMetadata = (target.basicBlock.transformationMetadata.ElementAt(i) as GraphTransformerMetadataBasicBlock);
                                                break;
                                            }
                                            if (changeTargetMetadata == null) {
                                                throw new ArgumentException("Not able to find metadata for target basic block.");
                                            }

                                            // get the link from the change target basic block to the obfuscation graph
                                            BasicBlockGraphNodeLink changeTargetGraphLink = null;
                                            foreach (BasicBlockGraphNodeLink tempLink in changeTargetMetadata.correspondingGraphNodes) {
                                                if (tempLink.validPathId == changedCurrentValidPathId) {
                                                    changeTargetGraphLink = tempLink;
                                                    break;
                                                }
                                            }
                                            if (changeTargetGraphLink == null) {
                                                throw new ArgumentNullException("Could not find link from target basic block to the graph for the given path id.");
                                            }

                                            // correct the pointer position to the obfuscation graph
                                            this.injectLinkMoveCode(cfgManipulator, currentGraphLink, changeTargetGraphLink, stateChangeExitBranch, changedCurrentValidPathId, currentNodeLocal);

                                            // if debugging is activated => dump method cfg and add code to dump current graph
                                            if (this.debugging) {
                                                List<IOperation> debugOperations = new List<IOperation>();
                                                debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldarg_0));
                                                debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldstr, this.debuggingNumber.ToString().PadLeft(3, '0') + "_" + target.basicBlock.id.ToString() + "_obfu_" + this.logger.makeFuncSigString(methodCfg.method)));
                                                debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldarg_0));
                                                debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Callvirt, this.interfaceStartPointerGet));
                                                debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldloc, currentNodeLocal));
                                                debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Callvirt, this.debuggingDumpGraphMethod));
                                                target.basicBlock.operations.InsertRange(0, debugOperations);

                                                //this.logger.dumpMethodCfg(methodCfg, this.debuggingNumber.ToString().PadLeft(3, '0') + "_obfu_" + this.logger.makeFuncSigString(methodCfg.method));
                                                this.debuggingNumber++;
                                            }

                                        }

                                        break;
                                    }

                                // case: correct pointer position
                                default: {

                                        this.injectLinkMoveCode(cfgManipulator, currentGraphLink, targetGraphLink, stateExitBranch, currentGraphLink.validPathId, currentNodeLocal);

                                        // if debugging is activated => dump method cfg and add code to dump current graph
                                        if (this.debugging) {
                                            List<IOperation> debugOperations = new List<IOperation>();
                                            debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldarg_0));
                                            debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldstr, this.debuggingNumber.ToString().PadLeft(3, '0') + "_" + target.basicBlock.id.ToString() + "_obfu_" + this.logger.makeFuncSigString(methodCfg.method)));
                                            debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldarg_0));
                                            debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Callvirt, this.interfaceStartPointerGet));
                                            debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldloc, currentNodeLocal));
                                            debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Callvirt, this.debuggingDumpGraphMethod));
                                            target.basicBlock.operations.InsertRange(0, debugOperations);

                                            //this.logger.dumpMethodCfg(methodCfg, this.debuggingNumber.ToString().PadLeft(3, '0') + "_obfu_" + this.logger.makeFuncSigString(methodCfg.method));
                                            this.debuggingNumber++;
                                        }

                                        break;
                                    }
                            }
                        }

                    }

                    // check if the current exit branch is of type "unconditional branch target"
                    else if (currentBasicBlock.exitBranch as UnconditionalBranchTarget != null) {

                        UnconditionalBranchTarget introBranch = (UnconditionalBranchTarget)currentBasicBlock.exitBranch;

                        // search for all semantically equal basic blocks in the modified method CFG (as possible targets)
                        int searchSementicId = introBranch.takenTarget.semanticId;
                        List<BasicBlock> possibleTargetBasicBlocks = new List<BasicBlock>();
                        if (searchSementicId != -1) {
                            foreach (BasicBlock searchBasicBlock in methodCfg.basicBlocks) {
                                if (searchBasicBlock.semanticId == searchSementicId) {
                                    possibleTargetBasicBlocks.Add(searchBasicBlock);
                                }
                            }
                            if (possibleTargetBasicBlocks.Count() == 0) {
                                throw new ArgumentException("Not able to find any semantically equal basic block in CFG.");
                            }
                        }
                        else {
                            possibleTargetBasicBlocks.Add(introBranch.takenTarget);
                        }

                        // create a list of target basic blocks of this branch
                        List<Target> listOfTargets = new List<Target>();
                        Target target = new Target();
                        target.basicBlock = introBranch.takenTarget;
                        listOfTargets.Add(target);

                        // generate code for the "state switch"
                        BasicBlock stateBasicBlock = null;
                        SwitchBranchTarget stateExitBranch = null;
                        this.createCodeStateSwitch(ref stateBasicBlock, ref stateExitBranch, intStateLocal, metadata.correspondingGraphNodes);
                        cfgManipulator.insertBasicBlockBetweenBranch(introBranch, stateBasicBlock, stateExitBranch, 0);

                        // create for each valid path a branch in the switch statement of the "state switch"
                        for (currentValidPathId = 0; currentValidPathId < this.graph.graphValidPathCount; currentValidPathId++) {

                            // ignore first valid path (with id 0)
                            // => add artificial branch to original branch target (for the current valid path id)
                            if (currentValidPathId != 0) {

                                // fill switch taken branch list with null when index is out of range
                                while (stateExitBranch.takenTarget.Count() <= currentValidPathId) {
                                    stateExitBranch.takenTarget.Add(null);
                                }

                                // randomly chose what the target of the current branch should be (weight to use an existing basic block to have less memory consumption)
                                switch (this.prng.Next(this.duplicateBasicBlockWeight)) {
                                    case 0:
                                    case 1:
                                    case 2:
                                    case 3:
                                    case 4:
                                    case 5: {

                                            // duplicate the target basic block
                                            BasicBlock duplicatedBasicBlock = this.duplicateBasicBlock(originalMethodCfg, methodCfg, listOfTargets.ElementAt(0).basicBlock);
                                            methodCfg.basicBlocks.Add(duplicatedBasicBlock);
                                            basicBlocksToProcess.Add(duplicatedBasicBlock);

                                            // add new basic block as target of the switch case
                                            stateExitBranch.takenTarget[currentValidPathId] = duplicatedBasicBlock;
                                            duplicatedBasicBlock.entryBranches.Add(stateExitBranch);

                                            // add new basic block to the list of target basic blocks
                                            target = new Target();
                                            target.basicBlock = duplicatedBasicBlock;
                                            listOfTargets.Add(target);

                                            // add duplicated basic block to the list of possible target basic blocks
                                            possibleTargetBasicBlocks.Add(duplicatedBasicBlock);

                                            // create metadata for the newly created basic block
                                            if (!createAndAddMetadata(duplicatedBasicBlock)) {
                                                throw new ArgumentException("Creating metadata for the duplicated basic block failed.");
                                            }

                                            break;

                                        }
                                    default: {

                                            // use a random possible basic block as target
                                            int randPosition = this.prng.Next(possibleTargetBasicBlocks.Count());
                                            BasicBlock newTarget = possibleTargetBasicBlocks.ElementAt(randPosition);

                                            target = new Target();
                                            target.basicBlock = newTarget;
                                            listOfTargets.Add(target);

                                            //set switch taken branch for current valid path id to the chosen branch target
                                            stateExitBranch.takenTarget[currentValidPathId] = target.basicBlock;
                                            target.basicBlock.entryBranches.Add(stateExitBranch);

                                            break;

                                        }

                                }

                            }

                            // set current valid path id of the target
                            target.currentValidPathId = currentValidPathId;

                            // get the link from the current basic block to the obfuscation graph
                            BasicBlockGraphNodeLink currentGraphLink = null;
                            foreach (BasicBlockGraphNodeLink tempLink in metadata.correspondingGraphNodes) {
                                if (tempLink.validPathId == currentValidPathId) {
                                    currentGraphLink = tempLink;
                                    break;
                                }
                            }
                            if (currentGraphLink == null) {
                                throw new ArgumentNullException("Could not find link from current basic block to the graph for the given path id.");
                            }

                            // get the metadata for the target basic block
                            GraphTransformerMetadataBasicBlock targetMetadata = null;
                            for (int i = 0; i < target.basicBlock.transformationMetadata.Count(); i++) {
                                // get graph transformer metadata for basic blocks
                                if ((target.basicBlock.transformationMetadata.ElementAt(i) as GraphTransformerMetadataBasicBlock) == null) {
                                    continue;
                                }
                                targetMetadata = (target.basicBlock.transformationMetadata.ElementAt(i) as GraphTransformerMetadataBasicBlock);
                                break;
                            }
                            if (targetMetadata == null) {
                                throw new ArgumentException("Not able to find metadata for target basic block.");
                            }

                            // get the link from the target basic block to the obfuscation graph
                            BasicBlockGraphNodeLink targetGraphLink = null;
                            foreach (BasicBlockGraphNodeLink tempLink in targetMetadata.correspondingGraphNodes) {
                                if (tempLink.validPathId == currentValidPathId) {
                                    targetGraphLink = tempLink;
                                    break;
                                }
                            }
                            if (targetGraphLink == null) {
                                throw new ArgumentNullException("Could not find link from target basic block to the graph for the given path id.");
                            }

                            // choose randomly to either just correct the pointer position or to inject a "state change"
                            switch (this.prng.Next(this.stateChangeWeight)) {

                                // case: "state change"
                                case 0:
                                case 1:
                                case 2:
                                case 3:
                                case 4:
                                case 5: {

                                        // generate code for the "state change"
                                        BasicBlock stateChangeBasicBlock = null;
                                        SwitchBranchTarget stateChangeExitBranch = null;
                                        this.createCodeStateChange(ref stateChangeBasicBlock, ref stateChangeExitBranch, randomStateGenerator, currentGraphLink, intStateLocal);
                                        cfgManipulator.insertBasicBlockBetweenBranch(stateExitBranch, currentValidPathId, stateChangeBasicBlock, stateChangeExitBranch, 0);

                                        // create for each valid path a branch in the switch statement of the "state change"
                                        for (int changedCurrentValidPathId = 0; changedCurrentValidPathId < this.graph.graphValidPathCount; changedCurrentValidPathId++) {

                                            // ignore first valid path (with id 0)
                                            // => add artificial branch to original branch target (for the changed current valid path id)
                                            if (changedCurrentValidPathId != 0) {

                                                // fill switch taken branch list with null when index is out of range
                                                while (stateChangeExitBranch.takenTarget.Count() <= changedCurrentValidPathId) {
                                                    stateChangeExitBranch.takenTarget.Add(null);
                                                }

                                                // randomly chose what the target of the current branch should be (weight to use an existing basic block to have less memory consumption)
                                                switch (this.prng.Next(this.duplicateBasicBlockWeight)) {
                                                    case 0:
                                                    case 1:
                                                    case 2:
                                                    case 3:
                                                    case 4:
                                                    case 5: {

                                                            // duplicate the target basic block
                                                            BasicBlock duplicatedBasicBlock = this.duplicateBasicBlock(originalMethodCfg, methodCfg, listOfTargets.ElementAt(0).basicBlock);
                                                            methodCfg.basicBlocks.Add(duplicatedBasicBlock);
                                                            basicBlocksToProcess.Add(duplicatedBasicBlock);

                                                            // add new basic block as target of the switch case
                                                            stateChangeExitBranch.takenTarget[changedCurrentValidPathId] = duplicatedBasicBlock;
                                                            duplicatedBasicBlock.entryBranches.Add(stateChangeExitBranch);

                                                            // add new basic block to the list of target basic blocks
                                                            target = new Target();
                                                            target.basicBlock = duplicatedBasicBlock;
                                                            listOfTargets.Add(target);

                                                            // add duplicated basic block to the list of possible target basic blocks
                                                            possibleTargetBasicBlocks.Add(duplicatedBasicBlock);

                                                            // create metadata for the newly created basic block
                                                            if (!createAndAddMetadata(duplicatedBasicBlock)) {
                                                                throw new ArgumentException("Creating metadata for the duplicated basic block failed.");
                                                            }

                                                            break;

                                                        }
                                                    default: {

                                                            // use a random possible basic block as target
                                                            int randPosition = this.prng.Next(possibleTargetBasicBlocks.Count());
                                                            BasicBlock newTarget = possibleTargetBasicBlocks.ElementAt(randPosition);

                                                            target = new Target();
                                                            target.basicBlock = newTarget;
                                                            listOfTargets.Add(target);

                                                            // set switch taken branch for current valid path id to the chosen branch target
                                                            stateChangeExitBranch.takenTarget[changedCurrentValidPathId] = target.basicBlock;
                                                            target.basicBlock.entryBranches.Add(stateChangeExitBranch);

                                                            break;

                                                        }
                                                }

                                            }

                                            // set current valid path id of the target
                                            target.currentValidPathId = changedCurrentValidPathId;

                                            // get the metadata for the change target basic block
                                            GraphTransformerMetadataBasicBlock changeTargetMetadata = null;
                                            for (int i = 0; i < target.basicBlock.transformationMetadata.Count(); i++) {
                                                // get graph transformer metadata for basic blocks
                                                if ((target.basicBlock.transformationMetadata.ElementAt(i) as GraphTransformerMetadataBasicBlock) == null) {
                                                    continue;
                                                }
                                                changeTargetMetadata = (target.basicBlock.transformationMetadata.ElementAt(i) as GraphTransformerMetadataBasicBlock);
                                                break;
                                            }
                                            if (changeTargetMetadata == null) {
                                                throw new ArgumentException("Not able to find metadata for target basic block.");
                                            }

                                            // get the link from the change target basic block to the obfuscation graph
                                            BasicBlockGraphNodeLink changeTargetGraphLink = null;
                                            foreach (BasicBlockGraphNodeLink tempLink in changeTargetMetadata.correspondingGraphNodes) {
                                                if (tempLink.validPathId == changedCurrentValidPathId) {
                                                    changeTargetGraphLink = tempLink;
                                                    break;
                                                }
                                            }
                                            if (changeTargetGraphLink == null) {
                                                throw new ArgumentNullException("Could not find link from target basic block to the graph for the given path id.");
                                            }

                                            // correct the pointer position to the obfuscation graph
                                            this.injectLinkMoveCode(cfgManipulator, currentGraphLink, changeTargetGraphLink, stateChangeExitBranch, changedCurrentValidPathId, currentNodeLocal);

                                            // if debugging is activated => dump method cfg and add code to dump current graph
                                            if (this.debugging) {
                                                List<IOperation> debugOperations = new List<IOperation>();
                                                debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldarg_0));
                                                debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldstr, this.debuggingNumber.ToString().PadLeft(3, '0') + "_" + target.basicBlock.id.ToString() + "_obfu_" + this.logger.makeFuncSigString(methodCfg.method)));
                                                debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldarg_0));
                                                debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Callvirt, this.interfaceStartPointerGet));
                                                debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldloc, currentNodeLocal));
                                                debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Callvirt, this.debuggingDumpGraphMethod));
                                                target.basicBlock.operations.InsertRange(0, debugOperations);

                                                //this.logger.dumpMethodCfg(methodCfg, this.debuggingNumber.ToString().PadLeft(3, '0') + "_obfu_" + this.logger.makeFuncSigString(methodCfg.method));
                                                this.debuggingNumber++;
                                            }

                                        }

                                        break;
                                    }

                                // case: correct pointer position
                                default: {

                                        this.injectLinkMoveCode(cfgManipulator, currentGraphLink, targetGraphLink, stateExitBranch, currentGraphLink.validPathId, currentNodeLocal);

                                        // if debugging is activated => dump method cfg and add code to dump current graph
                                        if (this.debugging) {
                                            List<IOperation> debugOperations = new List<IOperation>();
                                            debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldarg_0));
                                            debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldstr, this.debuggingNumber.ToString().PadLeft(3, '0') + "_" + target.basicBlock.id.ToString() + "_obfu_" + this.logger.makeFuncSigString(methodCfg.method)));
                                            debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldarg_0));
                                            debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Callvirt, this.interfaceStartPointerGet));
                                            debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldloc, currentNodeLocal));
                                            debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Callvirt, this.debuggingDumpGraphMethod));
                                            target.basicBlock.operations.InsertRange(0, debugOperations);

                                            //this.logger.dumpMethodCfg(methodCfg, this.debuggingNumber.ToString().PadLeft(3, '0') + "_obfu_" + this.logger.makeFuncSigString(methodCfg.method));
                                            this.debuggingNumber++;
                                        }

                                        break;
                                    }
                            }
                        }

                    }

                    // check if the current exit branch is of type "conditional branch target"
                    else if (currentBasicBlock.exitBranch as ConditionalBranchTarget != null) {

                        ConditionalBranchTarget introBranch = (ConditionalBranchTarget)currentBasicBlock.exitBranch;

                        // search for all semantically equal basic blocks in the modified method CFG (as possible targets)
                        int searchSementicId = introBranch.takenTarget.semanticId;
                        List<BasicBlock> possibleTargetBasicBlocks = new List<BasicBlock>();
                        if (searchSementicId != -1) {
                            foreach (BasicBlock searchBasicBlock in methodCfg.basicBlocks) {
                                if (searchBasicBlock.semanticId == searchSementicId) {
                                    possibleTargetBasicBlocks.Add(searchBasicBlock);
                                }
                            }
                            if (possibleTargetBasicBlocks.Count() == 0) {
                                throw new ArgumentException("Not able to find any semantically equal basic block in CFG.");
                            }
                        }
                        else {
                            possibleTargetBasicBlocks.Add(introBranch.takenTarget);
                        }

                        // create a list of target basic blocks of this branch
                        List<Target> listOfTargets = new List<Target>();
                        Target target = new Target();
                        target.basicBlock = introBranch.takenTarget;
                        listOfTargets.Add(target);

                        // generate code for the "state switch"
                        BasicBlock stateBasicBlock = null;
                        SwitchBranchTarget stateExitBranch = null;
                        this.createCodeStateSwitch(ref stateBasicBlock, ref stateExitBranch, intStateLocal, metadata.correspondingGraphNodes);
                        cfgManipulator.insertBasicBlockBetweenBranch(introBranch, true, stateBasicBlock, stateExitBranch, 0);

                        // create for each valid path a branch in the switch statement of the "state switch"
                        for (currentValidPathId = 0; currentValidPathId < this.graph.graphValidPathCount; currentValidPathId++) {

                            // ignore first valid path (with id 0)
                            // => add artificial branch to original branch target (for the current valid path id)
                            if (currentValidPathId != 0) {

                                // fill switch taken branch list with null when index is out of range
                                while (stateExitBranch.takenTarget.Count() <= currentValidPathId) {
                                    stateExitBranch.takenTarget.Add(null);
                                }

                                // randomly chose what the target of the current branch should be (weight to use an existing basic block to have less memory consumption)
                                switch (this.prng.Next(this.duplicateBasicBlockWeight)) {
                                    case 0:
                                    case 1:
                                    case 2:
                                    case 3:
                                    case 4:
                                    case 5: {

                                            // duplicate the target basic block
                                            BasicBlock duplicatedBasicBlock = this.duplicateBasicBlock(originalMethodCfg, methodCfg, listOfTargets.ElementAt(0).basicBlock);
                                            methodCfg.basicBlocks.Add(duplicatedBasicBlock);
                                            basicBlocksToProcess.Add(duplicatedBasicBlock);

                                            // add new basic block as target of the switch case
                                            stateExitBranch.takenTarget[currentValidPathId] = duplicatedBasicBlock;
                                            duplicatedBasicBlock.entryBranches.Add(stateExitBranch);

                                            // add new basic block to the list of target basic blocks
                                            target = new Target();
                                            target.basicBlock = duplicatedBasicBlock;
                                            listOfTargets.Add(target);

                                            // add duplicated basic block to the list of possible target basic blocks
                                            possibleTargetBasicBlocks.Add(duplicatedBasicBlock);

                                            // create metadata for the newly created basic block
                                            if (!createAndAddMetadata(duplicatedBasicBlock)) {
                                                throw new ArgumentException("Creating metadata for the duplicated basic block failed.");
                                            }

                                            break;

                                        }
                                    default: {

                                            // use a random possible basic block as target
                                            int randPosition = this.prng.Next(possibleTargetBasicBlocks.Count());
                                            BasicBlock newTarget = possibleTargetBasicBlocks.ElementAt(randPosition);

                                            target = new Target();
                                            target.basicBlock = newTarget;
                                            listOfTargets.Add(target);

                                            //set switch taken branch for current valid path id to the chosen branch target
                                            stateExitBranch.takenTarget[currentValidPathId] = target.basicBlock;
                                            target.basicBlock.entryBranches.Add(stateExitBranch);

                                            break;

                                        }

                                }

                            }

                            // set current valid path id of the target
                            target.currentValidPathId = currentValidPathId;

                            // get the link from the current basic block to the obfuscation graph
                            BasicBlockGraphNodeLink currentGraphLink = null;
                            foreach (BasicBlockGraphNodeLink tempLink in metadata.correspondingGraphNodes) {
                                if (tempLink.validPathId == currentValidPathId) {
                                    currentGraphLink = tempLink;
                                    break;
                                }
                            }
                            if (currentGraphLink == null) {
                                throw new ArgumentNullException("Could not find link from current basic block to the graph for the given path id.");
                            }

                            // get the metadata for the target basic block
                            GraphTransformerMetadataBasicBlock targetMetadata = null;
                            for (int i = 0; i < target.basicBlock.transformationMetadata.Count(); i++) {
                                // get graph transformer metadata for basic blocks
                                if ((target.basicBlock.transformationMetadata.ElementAt(i) as GraphTransformerMetadataBasicBlock) == null) {
                                    continue;
                                }
                                targetMetadata = (target.basicBlock.transformationMetadata.ElementAt(i) as GraphTransformerMetadataBasicBlock);
                                break;
                            }
                            if (targetMetadata == null) {
                                throw new ArgumentException("Not able to find metadata for target basic block.");
                            }

                            // get the link from the target basic block to the obfuscation graph
                            BasicBlockGraphNodeLink targetGraphLink = null;
                            foreach (BasicBlockGraphNodeLink tempLink in targetMetadata.correspondingGraphNodes) {
                                if (tempLink.validPathId == currentValidPathId) {
                                    targetGraphLink = tempLink;
                                    break;
                                }
                            }
                            if (targetGraphLink == null) {
                                throw new ArgumentNullException("Could not find link from target basic block to the graph for the given path id.");
                            }

                            // choose randomly to either just correct the pointer position or to inject a "state change"
                            switch (this.prng.Next(this.stateChangeWeight)) {

                                // case: "state change"
                                case 0:
                                case 1:
                                case 2:
                                case 3:
                                case 4:
                                case 5: {

                                        // generate code for the "state change"
                                        BasicBlock stateChangeBasicBlock = null;
                                        SwitchBranchTarget stateChangeExitBranch = null;
                                        this.createCodeStateChange(ref stateChangeBasicBlock, ref stateChangeExitBranch, randomStateGenerator, currentGraphLink, intStateLocal);
                                        cfgManipulator.insertBasicBlockBetweenBranch(stateExitBranch, currentValidPathId, stateChangeBasicBlock, stateChangeExitBranch, 0);

                                        // create for each valid path a branch in the switch statement of the "state change"
                                        for (int changedCurrentValidPathId = 0; changedCurrentValidPathId < this.graph.graphValidPathCount; changedCurrentValidPathId++) {

                                            // ignore first valid path (with id 0)
                                            // => add artificial branch to original branch target (for the changed current valid path id)
                                            if (changedCurrentValidPathId != 0) {

                                                // fill switch taken branch list with null when index is out of range
                                                while (stateChangeExitBranch.takenTarget.Count() <= changedCurrentValidPathId) {
                                                    stateChangeExitBranch.takenTarget.Add(null);
                                                }

                                                // randomly chose what the target of the current branch should be (weight to use an existing basic block to have less memory consumption)
                                                switch (this.prng.Next(this.duplicateBasicBlockWeight)) {
                                                    case 0:
                                                    case 1:
                                                    case 2:
                                                    case 3:
                                                    case 4:
                                                    case 5: {

                                                            // duplicate the target basic block
                                                            BasicBlock duplicatedBasicBlock = this.duplicateBasicBlock(originalMethodCfg, methodCfg, listOfTargets.ElementAt(0).basicBlock);
                                                            methodCfg.basicBlocks.Add(duplicatedBasicBlock);
                                                            basicBlocksToProcess.Add(duplicatedBasicBlock);

                                                            // add new basic block as target of the switch case
                                                            stateChangeExitBranch.takenTarget[changedCurrentValidPathId] = duplicatedBasicBlock;
                                                            duplicatedBasicBlock.entryBranches.Add(stateChangeExitBranch);

                                                            // add new basic block to the list of target basic blocks
                                                            target = new Target();
                                                            target.basicBlock = duplicatedBasicBlock;
                                                            listOfTargets.Add(target);

                                                            // add duplicated basic block to the list of possible target basic blocks
                                                            possibleTargetBasicBlocks.Add(duplicatedBasicBlock);

                                                            // create metadata for the newly created basic block
                                                            if (!createAndAddMetadata(duplicatedBasicBlock)) {
                                                                throw new ArgumentException("Creating metadata for the duplicated basic block failed.");
                                                            }

                                                            break;

                                                        }
                                                    default: {

                                                            // use a random possible basic block as target
                                                            int randPosition = this.prng.Next(possibleTargetBasicBlocks.Count());
                                                            BasicBlock newTarget = possibleTargetBasicBlocks.ElementAt(randPosition);

                                                            target = new Target();
                                                            target.basicBlock = newTarget;
                                                            listOfTargets.Add(target);

                                                            // set switch taken branch for current valid path id to the chosen branch target
                                                            stateChangeExitBranch.takenTarget[changedCurrentValidPathId] = target.basicBlock;
                                                            target.basicBlock.entryBranches.Add(stateChangeExitBranch);

                                                            break;

                                                        }
                                                }

                                            }

                                            // set current valid path id of the target
                                            target.currentValidPathId = changedCurrentValidPathId;

                                            // get the metadata for the change target basic block
                                            GraphTransformerMetadataBasicBlock changeTargetMetadata = null;
                                            for (int i = 0; i < target.basicBlock.transformationMetadata.Count(); i++) {
                                                // get graph transformer metadata for basic blocks
                                                if ((target.basicBlock.transformationMetadata.ElementAt(i) as GraphTransformerMetadataBasicBlock) == null) {
                                                    continue;
                                                }
                                                changeTargetMetadata = (target.basicBlock.transformationMetadata.ElementAt(i) as GraphTransformerMetadataBasicBlock);
                                                break;
                                            }
                                            if (changeTargetMetadata == null) {
                                                throw new ArgumentException("Not able to find metadata for target basic block.");
                                            }

                                            // get the link from the change target basic block to the obfuscation graph
                                            BasicBlockGraphNodeLink changeTargetGraphLink = null;
                                            foreach (BasicBlockGraphNodeLink tempLink in changeTargetMetadata.correspondingGraphNodes) {
                                                if (tempLink.validPathId == changedCurrentValidPathId) {
                                                    changeTargetGraphLink = tempLink;
                                                    break;
                                                }
                                            }
                                            if (changeTargetGraphLink == null) {
                                                throw new ArgumentNullException("Could not find link from target basic block to the graph for the given path id.");
                                            }

                                            // correct the pointer position to the obfuscation graph
                                            this.injectLinkMoveCode(cfgManipulator, currentGraphLink, changeTargetGraphLink, stateChangeExitBranch, changedCurrentValidPathId, currentNodeLocal);

                                            // if debugging is activated => dump method cfg and add code to dump current graph
                                            if (this.debugging) {
                                                List<IOperation> debugOperations = new List<IOperation>();
                                                debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldarg_0));
                                                debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldstr, this.debuggingNumber.ToString().PadLeft(3, '0') + "_" + target.basicBlock.id.ToString() + "_obfu_" + this.logger.makeFuncSigString(methodCfg.method)));
                                                debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldarg_0));
                                                debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Callvirt, this.interfaceStartPointerGet));
                                                debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldloc, currentNodeLocal));
                                                debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Callvirt, this.debuggingDumpGraphMethod));
                                                target.basicBlock.operations.InsertRange(0, debugOperations);

                                                //this.logger.dumpMethodCfg(methodCfg, this.debuggingNumber.ToString().PadLeft(3, '0') + "_obfu_" + this.logger.makeFuncSigString(methodCfg.method));
                                                this.debuggingNumber++;
                                            }

                                        }

                                        break;
                                    }

                                // case: correct pointer position
                                default: {

                                        this.injectLinkMoveCode(cfgManipulator, currentGraphLink, targetGraphLink, stateExitBranch, currentGraphLink.validPathId, currentNodeLocal);

                                        // if debugging is activated => dump method cfg and add code to dump current graph
                                        if (this.debugging) {
                                            List<IOperation> debugOperations = new List<IOperation>();
                                            debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldarg_0));
                                            debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldstr, this.debuggingNumber.ToString().PadLeft(3, '0') + "_" + target.basicBlock.id.ToString() + "_obfu_" + this.logger.makeFuncSigString(methodCfg.method)));
                                            debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldarg_0));
                                            debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Callvirt, this.interfaceStartPointerGet));
                                            debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldloc, currentNodeLocal));
                                            debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Callvirt, this.debuggingDumpGraphMethod));
                                            target.basicBlock.operations.InsertRange(0, debugOperations);

                                            //this.logger.dumpMethodCfg(methodCfg, this.debuggingNumber.ToString().PadLeft(3, '0') + "_obfu_" + this.logger.makeFuncSigString(methodCfg.method));
                                            this.debuggingNumber++;
                                        }

                                        break;
                                    }
                            }
                        }

                        // search for all semantically equal basic blocks in the modified method CFG (as possible targets)
                        searchSementicId = introBranch.notTakenTarget.semanticId;
                        possibleTargetBasicBlocks = new List<BasicBlock>();
                        if (searchSementicId != -1) {
                            foreach (BasicBlock searchBasicBlock in methodCfg.basicBlocks) {
                                if (searchBasicBlock.semanticId == searchSementicId) {
                                    possibleTargetBasicBlocks.Add(searchBasicBlock);
                                }
                            }
                            if (possibleTargetBasicBlocks.Count() == 0) {
                                throw new ArgumentException("Not able to find any semantically equal basic block in CFG.");
                            }
                        }
                        else {
                            possibleTargetBasicBlocks.Add(introBranch.notTakenTarget);
                        }

                        // create a list of target basic blocks of this branch
                        listOfTargets = new List<Target>();
                        target = new Target();
                        target.basicBlock = introBranch.notTakenTarget;
                        listOfTargets.Add(target);

                        // generate code for the "state switch"
                        stateBasicBlock = null;
                        stateExitBranch = null;
                        this.createCodeStateSwitch(ref stateBasicBlock, ref stateExitBranch, intStateLocal, metadata.correspondingGraphNodes);
                        cfgManipulator.insertBasicBlockBetweenBranch(introBranch, false, stateBasicBlock, stateExitBranch, 0);

                        // create for each valid path a branch in the switch statement of the "state switch"
                        for (currentValidPathId = 0; currentValidPathId < this.graph.graphValidPathCount; currentValidPathId++) {

                            // ignore first valid path (with id 0)
                            // => add artificial branch to original branch target (for the current valid path id)
                            if (currentValidPathId != 0) {

                                // fill switch taken branch list with null when index is out of range
                                while (stateExitBranch.takenTarget.Count() <= currentValidPathId) {
                                    stateExitBranch.takenTarget.Add(null);
                                }

                                // randomly chose what the target of the current branch should be (weight to use an existing basic block to have less memory consumption)
                                switch (this.prng.Next(this.duplicateBasicBlockWeight)) {
                                    case 0:
                                    case 1:
                                    case 2:
                                    case 3:
                                    case 4:
                                    case 5: {

                                            // duplicate the target basic block
                                            BasicBlock duplicatedBasicBlock = this.duplicateBasicBlock(originalMethodCfg, methodCfg, listOfTargets.ElementAt(0).basicBlock);
                                            methodCfg.basicBlocks.Add(duplicatedBasicBlock);
                                            basicBlocksToProcess.Add(duplicatedBasicBlock);

                                            // add new basic block as target of the switch case
                                            stateExitBranch.takenTarget[currentValidPathId] = duplicatedBasicBlock;
                                            duplicatedBasicBlock.entryBranches.Add(stateExitBranch);

                                            // add new basic block to the list of target basic blocks
                                            target = new Target();
                                            target.basicBlock = duplicatedBasicBlock;
                                            listOfTargets.Add(target);

                                            // add duplicated basic block to the list of possible target basic blocks
                                            possibleTargetBasicBlocks.Add(duplicatedBasicBlock);

                                            // create metadata for the newly created basic block
                                            if (!createAndAddMetadata(duplicatedBasicBlock)) {
                                                throw new ArgumentException("Creating metadata for the duplicated basic block failed.");
                                            }

                                            break;

                                        }
                                    default: {

                                            // use a random possible basic block as target
                                            int randPosition = this.prng.Next(possibleTargetBasicBlocks.Count());
                                            BasicBlock newTarget = possibleTargetBasicBlocks.ElementAt(randPosition);

                                            target = new Target();
                                            target.basicBlock = newTarget;
                                            listOfTargets.Add(target);

                                            //set switch taken branch for current valid path id to the chosen branch target
                                            stateExitBranch.takenTarget[currentValidPathId] = target.basicBlock;
                                            target.basicBlock.entryBranches.Add(stateExitBranch);

                                            break;

                                        }

                                }

                            }

                            // set current valid path id of the target
                            target.currentValidPathId = currentValidPathId;

                            // get the link from the current basic block to the obfuscation graph
                            BasicBlockGraphNodeLink currentGraphLink = null;
                            foreach (BasicBlockGraphNodeLink tempLink in metadata.correspondingGraphNodes) {
                                if (tempLink.validPathId == currentValidPathId) {
                                    currentGraphLink = tempLink;
                                    break;
                                }
                            }
                            if (currentGraphLink == null) {
                                throw new ArgumentNullException("Could not find link from current basic block to the graph for the given path id.");
                            }

                            // get the metadata for the target basic block
                            GraphTransformerMetadataBasicBlock targetMetadata = null;
                            for (int i = 0; i < target.basicBlock.transformationMetadata.Count(); i++) {
                                // get graph transformer metadata for basic blocks
                                if ((target.basicBlock.transformationMetadata.ElementAt(i) as GraphTransformerMetadataBasicBlock) == null) {
                                    continue;
                                }
                                targetMetadata = (target.basicBlock.transformationMetadata.ElementAt(i) as GraphTransformerMetadataBasicBlock);
                                break;
                            }
                            if (targetMetadata == null) {
                                throw new ArgumentException("Not able to find metadata for target basic block.");
                            }

                            // get the link from the target basic block to the obfuscation graph
                            BasicBlockGraphNodeLink targetGraphLink = null;
                            foreach (BasicBlockGraphNodeLink tempLink in targetMetadata.correspondingGraphNodes) {
                                if (tempLink.validPathId == currentValidPathId) {
                                    targetGraphLink = tempLink;
                                    break;
                                }
                            }
                            if (targetGraphLink == null) {
                                throw new ArgumentNullException("Could not find link from target basic block to the graph for the given path id.");
                            }

                            // choose randomly to either just correct the pointer position or to inject a "state change"
                            switch (this.prng.Next(this.stateChangeWeight)) {

                                // case: "state change"
                                case 0:
                                case 1:
                                case 2:
                                case 3:
                                case 4:
                                case 5: {

                                        // generate code for the "state change"
                                        BasicBlock stateChangeBasicBlock = null;
                                        SwitchBranchTarget stateChangeExitBranch = null;
                                        this.createCodeStateChange(ref stateChangeBasicBlock, ref stateChangeExitBranch, randomStateGenerator, currentGraphLink, intStateLocal);
                                        cfgManipulator.insertBasicBlockBetweenBranch(stateExitBranch, currentValidPathId, stateChangeBasicBlock, stateChangeExitBranch, 0);

                                        // create for each valid path a branch in the switch statement of the "state change"
                                        for (int changedCurrentValidPathId = 0; changedCurrentValidPathId < this.graph.graphValidPathCount; changedCurrentValidPathId++) {

                                            // ignore first valid path (with id 0)
                                            // => add artificial branch to original branch target (for the changed current valid path id)
                                            if (changedCurrentValidPathId != 0) {

                                                // fill switch taken branch list with null when index is out of range
                                                while (stateChangeExitBranch.takenTarget.Count() <= changedCurrentValidPathId) {
                                                    stateChangeExitBranch.takenTarget.Add(null);
                                                }

                                                // randomly chose what the target of the current branch should be (weight to use an existing basic block to have less memory consumption)
                                                switch (this.prng.Next(this.duplicateBasicBlockWeight)) {
                                                    case 0:
                                                    case 1:
                                                    case 2:
                                                    case 3:
                                                    case 4:
                                                    case 5: {

                                                            // duplicate the target basic block
                                                            BasicBlock duplicatedBasicBlock = this.duplicateBasicBlock(originalMethodCfg, methodCfg, listOfTargets.ElementAt(0).basicBlock);
                                                            methodCfg.basicBlocks.Add(duplicatedBasicBlock);
                                                            basicBlocksToProcess.Add(duplicatedBasicBlock);

                                                            // add new basic block as target of the switch case
                                                            stateChangeExitBranch.takenTarget[changedCurrentValidPathId] = duplicatedBasicBlock;
                                                            duplicatedBasicBlock.entryBranches.Add(stateChangeExitBranch);

                                                            // add new basic block to the list of target basic blocks
                                                            target = new Target();
                                                            target.basicBlock = duplicatedBasicBlock;
                                                            listOfTargets.Add(target);

                                                            // add duplicated basic block to the list of possible target basic blocks
                                                            possibleTargetBasicBlocks.Add(duplicatedBasicBlock);

                                                            // create metadata for the newly created basic block
                                                            if (!createAndAddMetadata(duplicatedBasicBlock)) {
                                                                throw new ArgumentException("Creating metadata for the duplicated basic block failed.");
                                                            }

                                                            break;

                                                        }
                                                    default: {

                                                            // use a random possible basic block as target
                                                            int randPosition = this.prng.Next(possibleTargetBasicBlocks.Count());
                                                            BasicBlock newTarget = possibleTargetBasicBlocks.ElementAt(randPosition);

                                                            target = new Target();
                                                            target.basicBlock = newTarget;
                                                            listOfTargets.Add(target);

                                                            // set switch taken branch for current valid path id to the chosen branch target
                                                            stateChangeExitBranch.takenTarget[changedCurrentValidPathId] = target.basicBlock;
                                                            target.basicBlock.entryBranches.Add(stateChangeExitBranch);

                                                            break;

                                                        }
                                                }

                                            }

                                            // set current valid path id of the target
                                            target.currentValidPathId = changedCurrentValidPathId;

                                            // get the metadata for the change target basic block
                                            GraphTransformerMetadataBasicBlock changeTargetMetadata = null;
                                            for (int i = 0; i < target.basicBlock.transformationMetadata.Count(); i++) {
                                                // get graph transformer metadata for basic blocks
                                                if ((target.basicBlock.transformationMetadata.ElementAt(i) as GraphTransformerMetadataBasicBlock) == null) {
                                                    continue;
                                                }
                                                changeTargetMetadata = (target.basicBlock.transformationMetadata.ElementAt(i) as GraphTransformerMetadataBasicBlock);
                                                break;
                                            }
                                            if (changeTargetMetadata == null) {
                                                throw new ArgumentException("Not able to find metadata for target basic block.");
                                            }

                                            // get the link from the change target basic block to the obfuscation graph
                                            BasicBlockGraphNodeLink changeTargetGraphLink = null;
                                            foreach (BasicBlockGraphNodeLink tempLink in changeTargetMetadata.correspondingGraphNodes) {
                                                if (tempLink.validPathId == changedCurrentValidPathId) {
                                                    changeTargetGraphLink = tempLink;
                                                    break;
                                                }
                                            }
                                            if (changeTargetGraphLink == null) {
                                                throw new ArgumentNullException("Could not find link from target basic block to the graph for the given path id.");
                                            }

                                            // correct the pointer position to the obfuscation graph
                                            this.injectLinkMoveCode(cfgManipulator, currentGraphLink, changeTargetGraphLink, stateChangeExitBranch, changedCurrentValidPathId, currentNodeLocal);

                                            // if debugging is activated => dump method cfg and add code to dump current graph
                                            if (this.debugging) {
                                                List<IOperation> debugOperations = new List<IOperation>();
                                                debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldarg_0));
                                                debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldstr, this.debuggingNumber.ToString().PadLeft(3, '0') + "_" + target.basicBlock.id.ToString() + "_obfu_" + this.logger.makeFuncSigString(methodCfg.method)));
                                                debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldarg_0));
                                                debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Callvirt, this.interfaceStartPointerGet));
                                                debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldloc, currentNodeLocal));
                                                debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Callvirt, this.debuggingDumpGraphMethod));
                                                target.basicBlock.operations.InsertRange(0, debugOperations);

                                                //this.logger.dumpMethodCfg(methodCfg, this.debuggingNumber.ToString().PadLeft(3, '0') + "_obfu_" + this.logger.makeFuncSigString(methodCfg.method));
                                                this.debuggingNumber++;
                                            }

                                        }

                                        break;
                                    }

                                // case: correct pointer position
                                default: {

                                        this.injectLinkMoveCode(cfgManipulator, currentGraphLink, targetGraphLink, stateExitBranch, currentGraphLink.validPathId, currentNodeLocal);

                                        // if debugging is activated => dump method cfg and add code to dump current graph
                                        if (this.debugging) {
                                            List<IOperation> debugOperations = new List<IOperation>();
                                            debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldarg_0));
                                            debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldstr, this.debuggingNumber.ToString().PadLeft(3, '0') + "_" + target.basicBlock.id.ToString() + "_obfu_" + this.logger.makeFuncSigString(methodCfg.method)));
                                            debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldarg_0));
                                            debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Callvirt, this.interfaceStartPointerGet));
                                            debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Ldloc, currentNodeLocal));
                                            debugOperations.Add(this.helperClass.createNewOperation(OperationCode.Callvirt, this.debuggingDumpGraphMethod));
                                            target.basicBlock.operations.InsertRange(0, debugOperations);

                                            //this.logger.dumpMethodCfg(methodCfg, this.debuggingNumber.ToString().PadLeft(3, '0') + "_obfu_" + this.logger.makeFuncSigString(methodCfg.method));
                                            this.debuggingNumber++;
                                        }

                                        break;
                                    }
                            }
                        }
                    }

                    // check if the current exit branch is of type "try block target"
                    else if (currentBasicBlock.exitBranch as TryBlockTarget != null) {
                        throw new ArgumentException("Not yet implemented.");
                    }

                    // check if the current exit branch is of type "switch branch target"
                    else if (currentBasicBlock.exitBranch as SwitchBranchTarget != null) {
                        throw new ArgumentException("Not yet implemented.");
                    }

                    // check if the current exit branch is of type "exception branch target"
                    else if (currentBasicBlock.exitBranch as ExceptionBranchTarget != null) {
                        throw new ArgumentException("Not yet implemented.");
                    }

                    // check if the current exit branch is of type "exit branch target"
                    else if (currentBasicBlock.exitBranch as ExitBranchTarget != null) {
                        continue;
                    }

                    // check if the current exit branch is of type "throw branch target"
                    else if (currentBasicBlock.exitBranch as ThrowBranchTarget != null) {
                        continue;
                    }

                    // this case should never be reached
                    else {
                        throw new ArgumentException("Do not know how to handle branch.");
                    }

                }

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

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

                // adjust probability to duplicate basic blocks (each processing round the probability drops to duplicate a basic block)
                this.duplicateBasicBlockWeight += this.duplicateBasicBlockCorrectionValue;

                // adjust probability to insert a state change (each processing round the probability drops to insert a state change)
                this.stateChangeWeight += this.stateChangeCorrectionValue;

            }

        }
        // this function injects an opaque predicate to the target branch
        private void injectOpaquePredicateCode(CfgManipulator cfgManipulator, Target target, ref ConditionalBranchTarget opaqueExitBranch, IBranchTarget targetBranch, BasicBlockGraphNodeLink link, int currentValidPathId, int opaquePredicate, LocalDefinition currentNodeLocal) {

            // create "true" or "false" opaque predicate and add it to the code
            switch (opaquePredicate) {

                // "true" opaque predicate
                case 0: {
                        BasicBlock opaqueStartBasicBlock = null;

                        this.createCodeTruePredicate(ref opaqueStartBasicBlock, ref opaqueExitBranch, link, currentNodeLocal);

                        // inject target branch with opaque predicate
                        if ((targetBranch as SwitchBranchTarget) != null) {
                            SwitchBranchTarget tempTargetBranch = (targetBranch as SwitchBranchTarget);
                            cfgManipulator.insertBasicBlockBetweenBranch(tempTargetBranch, currentValidPathId, opaqueStartBasicBlock, opaqueExitBranch, true);
                        }
                        else {
                            throw new ArgumentException("Not implemented yet.");
                        }

                        // set template semantic id of dead code basic block
                        BasicBlock deadCodeBasicBlock = opaqueExitBranch.notTakenTarget;
                        GraphTransformerDeadCodeBasicBlock deadCodeMetadata = (deadCodeBasicBlock.transformationMetadata.ElementAt(0) as GraphTransformerDeadCodeBasicBlock);
                        deadCodeMetadata.semanticId = target.basicBlock.semanticId;

                        break;
                    }

                // "false" opaque predicate
                case 1: {
                        BasicBlock opaqueStartBasicBlock = null;

                        this.createCodeFalsePredicate(ref opaqueStartBasicBlock, ref opaqueExitBranch, link, currentNodeLocal);

                        // inject target branch with opaque predicate
                        if ((targetBranch as SwitchBranchTarget) != null) {
                            SwitchBranchTarget tempTargetBranch = (targetBranch as SwitchBranchTarget);
                            cfgManipulator.insertBasicBlockBetweenBranch(tempTargetBranch, currentValidPathId, opaqueStartBasicBlock, opaqueExitBranch, false);
                        }
                        else {
                            throw new ArgumentException("Not implemented yet.");
                        }

                        // set template semantic id of dead code basic block
                        BasicBlock deadCodeBasicBlock = opaqueExitBranch.takenTarget;
                        GraphTransformerDeadCodeBasicBlock deadCodeMetadata = (deadCodeBasicBlock.transformationMetadata.ElementAt(0) as GraphTransformerDeadCodeBasicBlock);
                        deadCodeMetadata.semanticId = target.basicBlock.semanticId;

                        break;
                    }

                // "Random" opaque predicate.
                case 2: {
                        BasicBlock opaqueStartBasicBlock = null;

                        if((targetBranch as SwitchBranchTarget) != null) {
                            SwitchBranchTarget tempTargetBranch = (targetBranch as SwitchBranchTarget);
                            var destinationBlock = tempTargetBranch.takenTarget[currentValidPathId];

                            this.createCodeRandomPredicate(ref opaqueStartBasicBlock, ref opaqueExitBranch, link, currentNodeLocal);

                            bool chooseBranch = prng.Next(1) == 0;
                            cfgManipulator.insertBasicBlockBetweenBranch(tempTargetBranch, currentValidPathId, opaqueStartBasicBlock, opaqueExitBranch, chooseBranch);
                        }
                        else {
                            throw new ArgumentException("Not implemented yet.");
                        }
                        break;
                    }

                default:
                    throw new ArgumentException("This case should never be reached.");
            }

        }