///////////////////////////////////////////////////////////////////////////////////
        ///////////////////////////////////////////////////////////////////////////////////

        /// <summary>
        /// Completes check operations in search program from given currentOperation on
        /// (taking borderlines set by enclosing search program and check negative into account)
        /// Completion:
        /// - determine continuation point
        /// - insert remove isomorphy opertions needed for continuing there
        /// - insert continuing operation itself
        /// </summary>
        private static void CompleteCheckOperations(
            SearchProgramOperation currentOperation,
            SearchProgramOperation enclosingSearchProgram, // might be a negative/independent in case these are nested
            AlternativeCaseMatching enclosingAlternativeCase,
            CheckPartialMatchByNegativeOrIndependent enclosingCheckNegativeOrIndependent,
            SearchProgram topLevelSearchProgram)
        {
            // mainly dispatching and iteration method, traverses search program
            // real completion done in MoveOutwardsAppendingRemoveIsomorphyAndJump
            // outermost operation for that function is computed here, regarding negative patterns
            // program nesting structure: search program - [alternative] - [negative|independent]*

            // complete check operations by inserting failure code
            // find them in depth first search of search program
            while (currentOperation != null)
            {
                //////////////////////////////////////////////////////////
                if (currentOperation is CheckCandidate)
                //////////////////////////////////////////////////////////
                {
                    CheckCandidate checkCandidate =
                        (CheckCandidate)currentOperation;
                    checkCandidate.CheckFailedOperations =
                        new SearchProgramList(checkCandidate);
                    string[] neededElementsForCheckOperation = new string[1];
                    neededElementsForCheckOperation[0] = checkCandidate.PatternElementName;
                    MoveOutwardsAppendingRemoveIsomorphyAndJump(
                        checkCandidate,
                        neededElementsForCheckOperation,
                        enclosingCheckNegativeOrIndependent ?? (enclosingAlternativeCase ?? enclosingSearchProgram),
                        topLevelSearchProgram);
                }
                //////////////////////////////////////////////////////////
                else if (currentOperation is CheckPartialMatch)
                //////////////////////////////////////////////////////////
                {
                    if (currentOperation is CheckPartialMatchByCondition)
                    {
                        CheckPartialMatchByCondition checkCondition =
                            (CheckPartialMatchByCondition)currentOperation;
                        checkCondition.CheckFailedOperations =
                            new SearchProgramList(checkCondition);
                        MoveOutwardsAppendingRemoveIsomorphyAndJump(
                            checkCondition,
                            checkCondition.NeededElements,
                            enclosingCheckNegativeOrIndependent ?? (enclosingAlternativeCase ?? enclosingSearchProgram),
                            topLevelSearchProgram);
                    }
                    else if (currentOperation is CheckPartialMatchForDuplicate)
                    {
                        CheckPartialMatchForDuplicate checkDuplicateMatch =
                            (CheckPartialMatchForDuplicate)currentOperation;
                        checkDuplicateMatch.CheckFailedOperations =
                            new SearchProgramList(checkDuplicateMatch);
                        MoveOutwardsAppendingRemoveIsomorphyAndJump(
                            checkDuplicateMatch,
                            checkDuplicateMatch.NeededElements,
                            enclosingCheckNegativeOrIndependent ?? (enclosingAlternativeCase ?? enclosingSearchProgram),
                            topLevelSearchProgram);
                    }
                    else if (currentOperation is CheckPartialMatchByNegativeOrIndependent)
                    {
                        CheckPartialMatchByNegativeOrIndependent checkNegativeOrIndependent =
                            (CheckPartialMatchByNegativeOrIndependent)currentOperation;

                        // ByNegative/ByIndependent is handled in CheckContinueMatchingFailed
                        // of the negative/independent case - enter negative/independent case
                        CompleteCheckOperations(
                            checkNegativeOrIndependent.NestedOperationsList,
                            enclosingCheckNegativeOrIndependent ?? enclosingSearchProgram,
                            enclosingCheckNegativeOrIndependent != null ? null : enclosingAlternativeCase,
                            checkNegativeOrIndependent,
                            topLevelSearchProgram);
                    }
                    else if (currentOperation is CheckPartialMatchForSubpatternsFound)
                    {
                        CheckPartialMatchForSubpatternsFound checkSubpatternsFound =
                            (CheckPartialMatchForSubpatternsFound)currentOperation;

                        if (enclosingCheckNegativeOrIndependent == null)
                        {
                            // determine insertion point within check failed operations
                            // to append the nested check maximum matches
                            SearchProgramOperation insertionPoint =
                                checkSubpatternsFound.CheckFailedOperations;
                            while (insertionPoint.Next != null)
                            {
                                insertionPoint = insertionPoint.Next;
                            }

                            // append nested check maximum matches
                            CheckMaximumMatchesType checkMaxMatchesType = CheckMaximumMatchesType.Action;
                            if (enclosingSearchProgram is SearchProgramOfSubpattern ||
                                enclosingSearchProgram is SearchProgramOfAlternative)
                            {
                                checkMaxMatchesType = CheckMaximumMatchesType.Subpattern;
                            }
                            else if (enclosingSearchProgram is SearchProgramOfIterated)
                            {
                                checkMaxMatchesType = CheckMaximumMatchesType.Iterated;
                            }
                            CheckContinueMatchingMaximumMatchesReached checkMaximumMatches =
                                new CheckContinueMatchingMaximumMatchesReached(checkMaxMatchesType, false,
                                                                               enclosingSearchProgram is SearchProgramOfActionParallelizationBody);
                            insertionPoint.Append(checkMaximumMatches);

                            MoveOutwardsAppendingRemoveIsomorphyAndJump(
                                checkSubpatternsFound,
                                null,
                                enclosingCheckNegativeOrIndependent ?? (enclosingAlternativeCase ?? enclosingSearchProgram),
                                topLevelSearchProgram);
                        }

                        // check subpatterns found has a further check maximum matches
                        // or check continue matching of negative failed nested within check failed code
                        // give it its special bit of attention here
                        CompleteCheckOperations(
                            checkSubpatternsFound.CheckFailedOperations,
                            enclosingSearchProgram,
                            enclosingAlternativeCase,
                            enclosingCheckNegativeOrIndependent,
                            topLevelSearchProgram);
                    }
                    else
                    {
                        Debug.Assert(false, "unknown check partial match operation");
                    }
                }
                //////////////////////////////////////////////////////////
                else if (currentOperation is CheckContinueMatching)
                //////////////////////////////////////////////////////////
                {
                    if (currentOperation is CheckContinueMatchingMaximumMatchesReached)
                    {
                        CheckContinueMatchingMaximumMatchesReached checkMaximumMatches =
                            (CheckContinueMatchingMaximumMatchesReached)currentOperation;
                        checkMaximumMatches.CheckFailedOperations =
                            new SearchProgramList(checkMaximumMatches);

                        if (checkMaximumMatches.ListHeadAdjustment)
                        {
                            MoveOutwardsAppendingListHeadAdjustment(checkMaximumMatches, checkMaximumMatches.InParallelizedBody);
                        }

                        string[] neededElementsForCheckOperation = new string[0];
                        MoveOutwardsAppendingRemoveIsomorphyAndJump(
                            checkMaximumMatches,
                            neededElementsForCheckOperation,
                            enclosingSearchProgram,
                            topLevelSearchProgram);
                    }
                    else if (currentOperation is CheckContinueMatchingOfNegativeFailed)
                    {
                        CheckContinueMatchingOfNegativeFailed checkFailed =
                            (CheckContinueMatchingOfNegativeFailed)currentOperation;
                        checkFailed.CheckFailedOperations =
                            new SearchProgramList(checkFailed);
                        if (checkFailed.IsIterationBreaking)
                        {
                            string[] neededElementsForCheckOperation = new string[0];
                            MoveOutwardsAppendingRemoveIsomorphyAndJump(
                                checkFailed,
                                neededElementsForCheckOperation,
                                enclosingSearchProgram,
                                topLevelSearchProgram);
                        }
                        else
                        {
                            MoveOutwardsAppendingRemoveIsomorphyAndJump(
                                checkFailed,
                                enclosingCheckNegativeOrIndependent.NeededElements,
                                enclosingAlternativeCase ?? enclosingSearchProgram,
                                topLevelSearchProgram);
                        }
                    }
                    else if (currentOperation is CheckContinueMatchingOfIndependentSucceeded)
                    {
                        CheckContinueMatchingOfIndependentSucceeded checkSucceeded =
                            (CheckContinueMatchingOfIndependentSucceeded)currentOperation;
                        checkSucceeded.CheckFailedOperations = // yep, rotten wording
                                                               new SearchProgramList(checkSucceeded);
                        MoveRightAfterCorrespondingIndependentFailedAppendingRemoveIsomorphyAndJump(
                            checkSucceeded,
                            (CheckPartialMatchByIndependent)enclosingCheckNegativeOrIndependent,
                            topLevelSearchProgram);
                    }
                    else if (currentOperation is CheckContinueMatchingOfIndependentFailed)
                    {
                        CheckContinueMatchingOfIndependentFailed checkFailed =
                            (CheckContinueMatchingOfIndependentFailed)currentOperation;
                        checkFailed.CheckFailedOperations =
                            new SearchProgramList(checkFailed);
                        if (checkFailed.IsIterationBreaking)
                        {
                            string[] neededElementsForCheckOperation = new string[0];
                            MoveOutwardsAppendingRemoveIsomorphyAndJump(
                                checkFailed,
                                neededElementsForCheckOperation,
                                enclosingSearchProgram,
                                topLevelSearchProgram);
                        }
                        else
                        {
                            MoveOutwardsAppendingRemoveIsomorphyAndJump(
                                checkFailed,
                                checkFailed.CheckIndependent.NeededElements,
                                enclosingAlternativeCase ?? enclosingSearchProgram,
                                topLevelSearchProgram);
                        }
                    }
                    else if (currentOperation is CheckContinueMatchingTasksLeft)
                    {
                        CheckContinueMatchingTasksLeft tasksLeft =
                            (CheckContinueMatchingTasksLeft)currentOperation;

                        // determine insertion point within check failed operations
                        // to append the nested check maximum matches
                        SearchProgramOperation insertionPoint =
                            tasksLeft.CheckFailedOperations;
                        while (insertionPoint.Next != null)
                        {
                            insertionPoint = insertionPoint.Next;
                        }

                        // append nested check maximum matches
                        CheckContinueMatchingMaximumMatchesReached checkMaximumMatches =
                            new CheckContinueMatchingMaximumMatchesReached(
                                enclosingSearchProgram is SearchProgramOfIterated ? CheckMaximumMatchesType.Iterated : CheckMaximumMatchesType.Subpattern,
                                false, topLevelSearchProgram is SearchProgramOfActionParallelizationBody);
                        insertionPoint.Append(checkMaximumMatches);

                        MoveOutwardsAppendingRemoveIsomorphyAndJump(
                            tasksLeft,
                            null,
                            enclosingCheckNegativeOrIndependent ?? (enclosingAlternativeCase ?? enclosingSearchProgram),
                            topLevelSearchProgram);

                        // check tasks left has a further check maximum matches nested within check failed code
                        // give it its special bit of attention here
                        CompleteCheckOperations(
                            tasksLeft.CheckFailedOperations,
                            enclosingSearchProgram,
                            enclosingAlternativeCase,
                            enclosingCheckNegativeOrIndependent,
                            topLevelSearchProgram);
                    }
                    else if (currentOperation is CheckContinueMatchingIteratedPatternNonNullMatchFound)
                    {
                        // was built completely, nothing to complete
                    }
                    else
                    {
                        Debug.Assert(false, "unknown check abort matching operation");
                    }
                }
                //////////////////////////////////////////////////////////
                else if (currentOperation is AlternativeCaseMatching)
                //////////////////////////////////////////////////////////
                {
                    // depth first
                    CompleteCheckOperations(
                        currentOperation.GetNestedSearchOperationsList(),
                        enclosingSearchProgram,
                        (AlternativeCaseMatching)currentOperation,
                        null,
                        topLevelSearchProgram);
                }
                //////////////////////////////////////////////////////////
                else if (currentOperation.IsSearchNestingOperation())
                //////////////////////////////////////////////////////////
                {
                    // depth first
                    CompleteCheckOperations(
                        currentOperation.GetNestedSearchOperationsList(),
                        enclosingSearchProgram,
                        enclosingAlternativeCase,
                        enclosingCheckNegativeOrIndependent,
                        topLevelSearchProgram);
                }

                // breadth
                currentOperation = currentOperation.Next;
            }
        }
        /// <summary>
        /// Search program operations implementing the
        /// check for duplicate match search plan operation (needed in case an independent was inlined)
        /// are created and inserted into search program
        /// </summary>
        private SearchProgramOperation buildInlinedIndependentCheckForDuplicateMatch(
            SearchProgramOperation insertionPoint,
            int currentOperationIndex)
        {
            PatternGraph patternGraph = patternGraphWithNestingPatterns.Peek();

            List<String> namesOfPatternElements;
            List<String> matchObjectPaths;
            List<String> unprefixedNamesOfPatternElements;
            List<bool> patternElementIsNode;
            GetMatchElementsForDuplicateCheck(patternGraph,
                out namesOfPatternElements,
                out matchObjectPaths,
                out unprefixedNamesOfPatternElements,
                out patternElementIsNode);

            // if an independent was inlined, we may have to throw away duplicate matches
            // (duplicates in the sense that the non-inlined part was already matched with exactly the same elements)
            CheckPartialMatchForDuplicate checkDuplicateMatch =
                new CheckPartialMatchForDuplicate(rulePatternClassName,
                    patternGraph.pathPrefix + patternGraph.Name,
                    namesOfPatternElements.ToArray(),
                    matchObjectPaths.ToArray(),
                    unprefixedNamesOfPatternElements.ToArray(),
                    patternElementIsNode.ToArray());
            insertionPoint = insertionPoint.Append(checkDuplicateMatch);

            //---------------------------------------------------------------------------
            // build next operation
            insertionPoint = BuildScheduledSearchPlanOperationIntoSearchProgram(
                currentOperationIndex + 1,
                insertionPoint);
            //---------------------------------------------------------------------------

            return insertionPoint;
        }