// Copyright 2019 Google LLC.
#include "modules/skparagraph/src/ParagraphImpl.h"
#include "modules/skparagraph/src/TextWrapper.h"

namespace skia {
namespace textlayout {

// Since we allow cluster clipping when they don't fit
// we have to work with stretches - parts of clusters
void TextWrapper::lookAhead(SkScalar maxWidth, Cluster* endOfClusters) {
    fWords.startFrom(fEndLine.startCluster(), fEndLine.startPos());
    fClusters.startFrom(fEndLine.startCluster(), fEndLine.startPos());
    fClip.startFrom(fEndLine.startCluster(), fEndLine.startPos());
    for (auto cluster = fEndLine.endCluster(); cluster < endOfClusters; ++cluster) {
        if (fWords.width() + fClusters.width() + cluster->width() > maxWidth) {
            if (cluster->isWhitespaces()) {
                // It's the end of the word
                fMinIntrinsicWidth = SkTMax(fMinIntrinsicWidth, getClustersTrimmedWidth());
                fWords.extend(fClusters);
                break;
            }
            if (cluster->width() > maxWidth) {
                // Break the cluster into parts by glyph position
                auto delta = maxWidth - (fWords.width() + fClusters.width());
                fClip.extend(cluster, cluster->roundPos(delta));
                fTooLongCluster = true;
                fTooLongWord = true;
                break;
            }

            // Walk further to see if there is a too long word, cluster or glyph
            SkScalar nextWordLength = fClusters.width();
            for (auto further = cluster; further != endOfClusters; ++further) {
                if (further->isSoftBreak() || further->isHardBreak()) {
                    break;
                }
                nextWordLength += further->width();
            }
            if (nextWordLength > maxWidth) {
                // If the word is too long we can break it right now and hope it's enough
                fTooLongWord = true;
            }

            // TODO: this is the place when we use hyphenation
            fMinIntrinsicWidth = SkTMax(fMinIntrinsicWidth, nextWordLength);
            break;
        }

        fClusters.extend(cluster);

        // Keep adding clusters/words
        if (fClusters.endOfWord()) {
            fMinIntrinsicWidth = SkTMax(fMinIntrinsicWidth, getClustersTrimmedWidth());
            fWords.extend(fClusters);
        }

        if ((fHardLineBreak = cluster->isHardBreak())) {
            // Stop at the hard line break
            break;
        }
    }
}

void TextWrapper::moveForward() {
    do {
        if (fWords.width() > 0) {
            fEndLine.extend(fWords);
        } else if (fClusters.width() > 0) {
            fEndLine.extend(fClusters);
            fTooLongWord = false;
        } else if (fClip.width() > 0) {
            fEndLine.extend(fClip);
            fTooLongWord = false;
            fTooLongCluster = false;
        } else {
            break;
        }
    } while (fTooLongWord || fTooLongCluster);
}

// Special case for start/end cluster since they can be clipped
void TextWrapper::trimEndSpaces() {
    // Remember the breaking position
    fEndLine.saveBreak();
    // Move the end of the line to the left
    for (auto cluster = fEndLine.endCluster();
         cluster >= fEndLine.startCluster() && cluster->isWhitespaces();
         --cluster) {
        fEndLine.trim(cluster);
    }
    fEndLine.trim();
}

SkScalar TextWrapper::getClustersTrimmedWidth() {
    // Move the end of the line to the left
    SkScalar width = fClusters.width();
    auto cluster = fClusters.endCluster();
    for (; cluster > fClusters.startCluster() && cluster->isWhitespaces(); --cluster) {
        width -= cluster->width();
    }
    if (cluster >= fClusters.startCluster()) {
        width -= (cluster->width() - cluster->trimmedWidth(cluster->endPos()));
    }
    return width;
}

// Trim the beginning spaces in case of soft line break
void TextWrapper::trimStartSpaces(Cluster* endOfClusters) {
    // Restore the breaking position
    fEndLine.restoreBreak();
    fEndLine.nextPos();
    if (fHardLineBreak) {
        // End of line is always end of cluster, but need to skip \n
        fEndLine.startFrom(fEndLine.endCluster(), 0);
        return;
    }
    if (fEndLine.endPos() != 0) {
        // Clipping
        fEndLine.startFrom(fEndLine.endCluster(), fEndLine.endPos());
        return;
    }

    auto cluster = fEndLine.endCluster();
    while (cluster < endOfClusters && cluster->isWhitespaces()) {
        ++cluster;
    }
    fEndLine.startFrom(cluster, 0);
}

void TextWrapper::breakTextIntoLines(ParagraphImpl* parent,
                                     SkScalar maxWidth,
                                     const AddLineToParagraph& addLine) {
    auto span = parent->clusters();
    auto maxLines = parent->paragraphStyle().getMaxLines();
    auto ellipsisStr = parent->paragraphStyle().getEllipsis();

    fHeight = 0;
    fMinIntrinsicWidth = 0;
    fMaxIntrinsicWidth = 0;
    fEndLine = TextStretch(span.begin(), span.begin());
    auto end = &span.back();
    while (fEndLine.endCluster() != end) {
        reset();

        lookAhead(maxWidth, end);
        moveForward();

        // Do not trim end spaces on the naturally last line of the left aligned text
        trimEndSpaces();

        auto lastLine = maxLines == std::numeric_limits<size_t>::max() ||
            fLineNumber >= maxLines;
        auto needEllipsis =
            lastLine &&
                !fHardLineBreak &&
                fEndLine.endCluster() < end - 1 &&
                maxWidth != std::numeric_limits<SkScalar>::max() &&
                !ellipsisStr.isEmpty();
        // TODO: perform ellipsis work here
        if (parent->strutEnabled()) {
            // Make sure font metrics are not less than the strut
            parent->strutMetrics().updateLineMetrics(fEndLine.metrics(),
                                                     parent->strutForceHeight());
        }
        fMaxIntrinsicWidth = SkMaxScalar(fMaxIntrinsicWidth, fEndLine.width());
        // TODO: keep start/end/break info for text and runs but in a better way that below
        SkSpan<const char> text(fEndLine.startCluster()->text().begin(),
                                fEndLine.endCluster()->text().end() - fEndLine.startCluster()->text().begin());
        SkSpan<const char> textWithSpaces(fEndLine.startCluster()->text().begin(),
                                fEndLine.breakCluster()->text().end() - fEndLine.startCluster()->text().begin());
        addLine(text, textWithSpaces,
                fEndLine.startCluster(),
                fEndLine.endCluster(),
                fEndLine.startPos(),
                fEndLine.endPos(),
                SkVector::Make(0, fHeight),
                SkVector::Make(fEndLine.width(), fEndLine.metrics().height()),
                fEndLine.metrics(),
                needEllipsis);

        // Start a new line
        fHeight += fEndLine.metrics().height();

        trimStartSpaces(end);

        if (needEllipsis || fLineNumber >= maxLines) {
            break;
        }
        ++fLineNumber;
    }

    if (fHardLineBreak) {
        // Last character is a line break
        if (parent->strutEnabled()) {
            // Make sure font metrics are not less than the strut
            parent->strutMetrics().updateLineMetrics(fEndLine.metrics(),
                                                     parent->strutForceHeight());
        }
        SkSpan<const char> empty(fEndLine.breakCluster()->text().begin(), 0);
        addLine(empty, empty,
                fEndLine.breakCluster(),
                fEndLine.breakCluster(),
                0,
                0,
                SkVector::Make(0, fHeight),
                SkVector::Make(0, fEndLine.metrics().height()),
                fEndLine.metrics(),
                false);
    }
}

}  // namespace textlayout
}  // namespace skia
