// Copyright 2019 Google LLC.
#ifndef TextWrapper_DEFINED
#define TextWrapper_DEFINED

#include <string>
#include "include/core/SkSpan.h"
#include "modules/skparagraph/src/TextLine.h"

namespace skia {
namespace textlayout {

class ParagraphImpl;

class TextWrapper {
    class ClusterPos {
    public:
        ClusterPos() : fCluster(nullptr), fPos(0) {}
        ClusterPos(Cluster* cluster, size_t pos) : fCluster(cluster), fPos(pos) {}
        inline Cluster* cluster() const { return fCluster; }
        inline size_t position() const { return fPos; }
        inline void setPosition(size_t pos) { fPos = pos; }
        void clean() {
            fCluster = nullptr;
            fPos = 0;
        }
        void move(bool up) {
            fCluster += up ? 1 : -1;
            fPos = up ? 0 : fCluster->endPos();
        }

    private:
        Cluster* fCluster;
        size_t fPos;
    };
    class TextStretch {
    public:
        TextStretch() : fStart(), fEnd(), fWidth(0), fWidthWithGhostSpaces(0) {}
        TextStretch(Cluster* s, Cluster* e, bool forceStrut)
                : fStart(s, 0), fEnd(e, e->endPos()), fMetrics(forceStrut), fWidth(0), fWidthWithGhostSpaces(0) {
            for (auto c = s; c <= e; ++c) {
                if (auto r = c->runOrNull()) {
                    fMetrics.add(r);
                }
                if (c < e) {
                    fWidth += c->width();
                }
            }
            fWidthWithGhostSpaces = fWidth;
        }

        inline SkScalar width() const { return fWidth; }
        SkScalar widthWithGhostSpaces() const { return fWidthWithGhostSpaces; }
        inline Cluster* startCluster() const { return fStart.cluster(); }
        inline Cluster* endCluster() const { return fEnd.cluster(); }
        inline Cluster* breakCluster() const { return fBreak.cluster(); }
        inline InternalLineMetrics& metrics() { return fMetrics; }
        inline size_t startPos() const { return fStart.position(); }
        inline size_t endPos() const { return fEnd.position(); }
        bool endOfCluster() { return fEnd.position() == fEnd.cluster()->endPos(); }
        bool endOfWord() {
            return endOfCluster() &&
                   (fEnd.cluster()->isHardBreak() || fEnd.cluster()->isSoftBreak());
        }

        void extend(TextStretch& stretch) {
            fMetrics.add(stretch.fMetrics);
            fEnd = stretch.fEnd;
            fWidth += stretch.fWidth;
            stretch.clean();
        }

        bool empty() { return fStart.cluster() == fEnd.cluster() &&
                              fStart.position() == fEnd.position(); }

        void setMetrics(const InternalLineMetrics& metrics) { fMetrics = metrics; }

        void extend(Cluster* cluster) {
            if (fStart.cluster() == nullptr) {
                fStart = ClusterPos(cluster, cluster->startPos());
            }
            fEnd = ClusterPos(cluster, cluster->endPos());
            // TODO: Make sure all the checks are correct and there are no unnecessary checks
            auto& r = cluster->run();
            if (!cluster->isHardBreak() && !r.isPlaceholder()) {
                // We ignore metrics for \n as the Flutter does
                fMetrics.add(&r);
            }
            fWidth += cluster->width();
        }

        void extend(Cluster* cluster, size_t pos) {
            fEnd = ClusterPos(cluster, pos);
            if (auto r = cluster->runOrNull()) {
                fMetrics.add(r);
            }
        }

        void startFrom(Cluster* cluster, size_t pos) {
            fStart = ClusterPos(cluster, pos);
            fEnd = ClusterPos(cluster, pos);
            if (auto r = cluster->runOrNull()) {
                // In case of placeholder we should ignore the default text style -
                // we will pick up the correct one from the placeholder
                if (!r->isPlaceholder()) {
                    fMetrics.add(r);
                }
            }
            fWidth = 0;
        }

        void saveBreak() {
            fWidthWithGhostSpaces = fWidth;
            fBreak = fEnd;
        }

        void restoreBreak() {
            fWidth = fWidthWithGhostSpaces;
            fEnd = fBreak;
        }

        void shiftBreak() {
            fBreak.move(true);
        }

        void trim() {

            if (fEnd.cluster() != nullptr &&
                fEnd.cluster()->owner() != nullptr &&
                fEnd.cluster()->runOrNull() != nullptr &&
                fEnd.cluster()->run().placeholderStyle() == nullptr &&
                fWidth > 0) {
                fWidth -= (fEnd.cluster()->width() - fEnd.cluster()->trimmedWidth(fEnd.position()));
            }
        }

        void trim(Cluster* cluster) {
            SkASSERT(fEnd.cluster() == cluster);
            if (fEnd.cluster() > fStart.cluster()) {
                fEnd.move(false);
                fWidth -= cluster->width();
            } else {
                fEnd.setPosition(fStart.position());
                fWidth = 0;
            }
        }

        void clean() {
            fStart.clean();
            fEnd.clean();
            fWidth = 0;
            fMetrics.clean();
        }

    private:
        ClusterPos fStart;
        ClusterPos fEnd;
        ClusterPos fBreak;
        InternalLineMetrics fMetrics;
        SkScalar fWidth;
        SkScalar fWidthWithGhostSpaces;
    };

public:
    TextWrapper() {
         fLineNumber = 1;
         fHardLineBreak = false;
         fExceededMaxLines = false;
    }

    using AddLineToParagraph = std::function<void(TextRange textExcludingSpaces,
                                                  TextRange text,
                                                  TextRange textIncludingNewlines,
                                                  ClusterRange clusters,
                                                  ClusterRange clustersWithGhosts,
                                                  SkScalar AddLineToParagraph,
                                                  size_t startClip,
                                                  size_t endClip,
                                                  SkVector offset,
                                                  SkVector advance,
                                                  InternalLineMetrics metrics,
                                                  bool addEllipsis)>;
    void breakTextIntoLines(ParagraphImpl* parent,
                            SkScalar maxWidth,
                            const AddLineToParagraph& addLine);

    SkScalar height() const { return fHeight; }
    SkScalar minIntrinsicWidth() const { return fMinIntrinsicWidth; }
    SkScalar maxIntrinsicWidth() const { return fMaxIntrinsicWidth; }
    bool exceededMaxLines() const { return fExceededMaxLines; }

private:
    TextStretch fWords;
    TextStretch fClusters;
    TextStretch fClip;
    TextStretch fEndLine;
    size_t fLineNumber;
    bool fTooLongWord;
    bool fTooLongCluster;

    bool fHardLineBreak;
    bool fExceededMaxLines;

    SkScalar fHeight;
    SkScalar fMinIntrinsicWidth;
    SkScalar fMaxIntrinsicWidth;

    void reset() {
        fWords.clean();
        fClusters.clean();
        fClip.clean();
        fTooLongCluster = false;
        fTooLongWord = false;
        fHardLineBreak = false;
    }

    void lookAhead(SkScalar maxWidth, Cluster* endOfClusters);
    void moveForward(bool hasEllipsis);
    void trimEndSpaces(TextAlign align);
    std::tuple<Cluster*, size_t, SkScalar> trimStartSpaces(Cluster* endOfClusters);
    SkScalar getClustersTrimmedWidth();
};
}  // namespace textlayout
}  // namespace skia

#endif  // TextWrapper_DEFINED
