/* static */ void DictionaryUtils::processChildDicNodes(
        const DictionaryStructureWithBufferPolicy *const dictionaryStructurePolicy,
        const int inputCodePoint, const DicNode *const parentDicNode,
        std::vector<DicNode> *const outDicNodes) {
    DicNodeVector childDicNodes;
    DicNodeUtils::getAllChildDicNodes(parentDicNode, dictionaryStructurePolicy, &childDicNodes);
    for (int childIndex = 0; childIndex < childDicNodes.getSizeAndLock(); ++childIndex) {
        DicNode *const childDicNode = childDicNodes[childIndex];
        const int codePoint = CharUtils::toBaseLowerCase(childDicNode->getNodeCodePoint());
        if (inputCodePoint == codePoint) {
            outDicNodes->emplace_back(*childDicNode);
        }
        if (childDicNode->canBeIntentionalOmission()) {
            processChildDicNodes(dictionaryStructurePolicy, inputCodePoint, childDicNode,
                    outDicNodes);
        }
        if (DigraphUtils::hasDigraphForCodePoint(
                dictionaryStructurePolicy->getHeaderStructurePolicy(),
                childDicNode->getNodeCodePoint())) {
            childDicNode->advanceDigraphIndex();
            if (childDicNode->getNodeCodePoint() == codePoint) {
                childDicNode->advanceDigraphIndex();
                outDicNodes->emplace_back(*childDicNode);
            }
        }
    }
}
/* static */ int DictionaryUtils::getMaxProbabilityOfExactMatches(
        const DictionaryStructureWithBufferPolicy *const dictionaryStructurePolicy,
        const CodePointArrayView codePoints) {
    std::vector<DicNode> current;
    std::vector<DicNode> next;

    // No ngram context.
    NgramContext emptyNgramContext;
    WordIdArray<MAX_PREV_WORD_COUNT_FOR_N_GRAM> prevWordIdArray;
    const WordIdArrayView prevWordIds = emptyNgramContext.getPrevWordIds(
            dictionaryStructurePolicy, &prevWordIdArray, false /* tryLowerCaseSearch */);
    current.emplace_back();
    DicNodeUtils::initAsRoot(dictionaryStructurePolicy, prevWordIds, &current.front());
    for (const int codePoint : codePoints) {
        // The base-lower input is used to ignore case errors and accent errors.
        const int baseLowerCodePoint = CharUtils::toBaseLowerCase(codePoint);
        for (const DicNode &dicNode : current) {
            if (dicNode.isInDigraph() && dicNode.getNodeCodePoint() == baseLowerCodePoint) {
                next.emplace_back(dicNode);
                next.back().advanceDigraphIndex();
                continue;
            }
            processChildDicNodes(dictionaryStructurePolicy, baseLowerCodePoint, &dicNode, &next);
        }
        current.clear();
        current.swap(next);
    }

    int maxProbability = NOT_A_PROBABILITY;
    for (const DicNode &dicNode : current) {
        if (!dicNode.isTerminalDicNode()) {
            continue;
        }
        const WordAttributes wordAttributes =
                dictionaryStructurePolicy->getWordAttributesInContext(dicNode.getPrevWordIds(),
                        dicNode.getWordId(), nullptr /* multiBigramMap */);
        // dicNode can contain case errors, accent errors, intentional omissions or digraphs.
        maxProbability = std::max(maxProbability, wordAttributes.getProbability());
    }
    return maxProbability;
}
/* static */ int DictionaryUtils::getMaxProbabilityOfExactMatches(
        const DictionaryStructureWithBufferPolicy *const dictionaryStructurePolicy,
        const int *const codePoints, const int codePointCount) {
    std::vector<DicNode> current;
    std::vector<DicNode> next;

    // No prev words information.
    PrevWordsInfo emptyPrevWordsInfo;
    int prevWordsPtNodePos[MAX_PREV_WORD_COUNT_FOR_N_GRAM];
    emptyPrevWordsInfo.getPrevWordsTerminalPtNodePos(dictionaryStructurePolicy,
            prevWordsPtNodePos, false /* tryLowerCaseSearch */);
    current.emplace_back();
    DicNodeUtils::initAsRoot(dictionaryStructurePolicy, prevWordsPtNodePos, &current.front());
    for (int i = 0; i < codePointCount; ++i) {
        // The base-lower input is used to ignore case errors and accent errors.
        const int codePoint = CharUtils::toBaseLowerCase(codePoints[i]);
        for (const DicNode &dicNode : current) {
            if (dicNode.isInDigraph() && dicNode.getNodeCodePoint() == codePoint) {
                next.emplace_back(dicNode);
                next.back().advanceDigraphIndex();
                continue;
            }
            processChildDicNodes(dictionaryStructurePolicy, codePoint, &dicNode, &next);
        }
        current.clear();
        current.swap(next);
    }

    int maxProbability = NOT_A_PROBABILITY;
    for (const DicNode &dicNode : current) {
        if (!dicNode.isTerminalDicNode()) {
            continue;
        }
        // dicNode can contain case errors, accent errors, intentional omissions or digraphs.
        maxProbability = std::max(maxProbability, dicNode.getProbability());
    }
    return maxProbability;
}