/*
 * Copyright 2020 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "modules/skottie/src/Adapter.h"
#include "modules/skottie/src/SkottieJson.h"
#include "modules/skottie/src/SkottiePriv.h"
#include "modules/skottie/src/SkottieValue.h"
#include "modules/skottie/src/layers/shapelayer/ShapeLayer.h"
#include "modules/sksg/include/SkSGRenderNode.h"

#include <vector>

namespace skottie {
namespace internal {

namespace  {

class RepeaterRenderNode final : public sksg::CustomRenderNode {
public:
    enum class CompositeMode { kBelow, kAbove };

    RepeaterRenderNode(std::vector<sk_sp<RenderNode>>&& children, CompositeMode mode)
        : INHERITED(std::move(children))
        , fMode(mode) {}

    SG_ATTRIBUTE(Count       , size_t, fCount       )
    SG_ATTRIBUTE(Offset      , float , fOffset      )
    SG_ATTRIBUTE(AnchorPoint , SkV2  , fAnchorPoint )
    SG_ATTRIBUTE(Position    , SkV2  , fPosition    )
    SG_ATTRIBUTE(Scale       , SkV2  , fScale       )
    SG_ATTRIBUTE(Rotation    , float , fRotation    )
    SG_ATTRIBUTE(StartOpacity, float , fStartOpacity)
    SG_ATTRIBUTE(EndOpacity  , float , fEndOpacity  )

private:
    const RenderNode* onNodeAt(const SkPoint&) const override { return nullptr; } // no hit-testing

    SkMatrix instanceTransform(size_t i) const {
        const auto t = fOffset + i;

        // Position, scale & rotation are "scaled" by index/offset.
        return SkMatrix::Translate(t * fPosition.x + fAnchorPoint.x,
                                   t * fPosition.y + fAnchorPoint.y)
             * SkMatrix::RotateDeg(t * fRotation)
             * SkMatrix::Scale(std::pow(fScale.x, t),
                               std::pow(fScale.y, t))
             * SkMatrix::Translate(-fAnchorPoint.x,
                                   -fAnchorPoint.y);
    }

    SkRect onRevalidate(sksg::InvalidationController* ic, const SkMatrix& ctm) override {
        fChildrenBounds = SkRect::MakeEmpty();
        for (const auto& child : this->children()) {
            fChildrenBounds.join(child->revalidate(ic, ctm));
        }

        auto bounds = SkRect::MakeEmpty();
        for (size_t i = 0; i < fCount; ++i) {
            bounds.join(this->instanceTransform(i).mapRect(fChildrenBounds));
        }

        return bounds;
    }

    void onRender(SkCanvas* canvas, const RenderContext* ctx) const override {
        // To cover the full opacity range, the denominator below should be (fCount - 1).
        // Interstingly, that's not what AE does.  Off-by-one bug?
        const auto dOpacity = fCount > 1 ? (fEndOpacity - fStartOpacity) / fCount : 0.0f;

        for (size_t i = 0; i < fCount; ++i) {
            const auto render_index = fMode == CompositeMode::kAbove ? i : fCount - i - 1;
            const auto opacity      = fStartOpacity + dOpacity * render_index;

            if (opacity <= 0) {
                continue;
            }

            SkAutoCanvasRestore acr(canvas, true);
            canvas->concat(this->instanceTransform(render_index));

            const auto& children = this->children();
            const auto local_ctx = ScopedRenderContext(canvas, ctx)
                                        .modulateOpacity(opacity)
                                        .setIsolation(fChildrenBounds,
                                                      canvas->getTotalMatrix(),
                                                      children.size() > 1);
            for (const auto& child : children) {
                child->render(canvas, local_ctx);
            }
        }
    }

    const CompositeMode           fMode;

    SkRect fChildrenBounds = SkRect::MakeEmpty(); // cached

    size_t fCount          = 0;
    float  fOffset         = 0,
           fRotation       = 0,
           fStartOpacity   = 1,
           fEndOpacity     = 1;
    SkV2   fAnchorPoint    = {0,0},
           fPosition       = {0,0},
           fScale          = {1,1};

    using INHERITED = sksg::CustomRenderNode;
};

class RepeaterAdapter final : public DiscardableAdapterBase<RepeaterAdapter, RepeaterRenderNode> {
public:
    RepeaterAdapter(const skjson::ObjectValue& jrepeater,
                    const skjson::ObjectValue& jtransform,
                    const AnimationBuilder& abuilder,
                    std::vector<sk_sp<sksg::RenderNode>>&& draws)
        : INHERITED(sk_make_sp<RepeaterRenderNode>(std::move(draws),
                                                   (ParseDefault(jrepeater["m"], 1) == 1)
                                                       ? RepeaterRenderNode::CompositeMode::kBelow
                                                       : RepeaterRenderNode::CompositeMode::kAbove))
    {
        this->bind(abuilder, jrepeater["c"], fCount);
        this->bind(abuilder, jrepeater["o"], fOffset);

        this->bind(abuilder, jtransform["a" ], fAnchorPoint);
        this->bind(abuilder, jtransform["p" ], fPosition);
        this->bind(abuilder, jtransform["s" ], fScale);
        this->bind(abuilder, jtransform["r" ], fRotation);
        this->bind(abuilder, jtransform["so"], fStartOpacity);
        this->bind(abuilder, jtransform["eo"], fEndOpacity);
    }

private:
    void onSync() override {
        static constexpr SkScalar kMaxCount = 1024;
        this->node()->setCount(static_cast<size_t>(SkTPin(fCount, 0.0f, kMaxCount) + 0.5f));
        this->node()->setOffset(fOffset);
        this->node()->setAnchorPoint(fAnchorPoint);
        this->node()->setPosition(fPosition);
        this->node()->setScale(fScale * 0.01f);
        this->node()->setRotation(fRotation);
        this->node()->setStartOpacity(SkTPin(fStartOpacity * 0.01f, 0.0f, 1.0f));
        this->node()->setEndOpacity  (SkTPin(fEndOpacity   * 0.01f, 0.0f, 1.0f));
    }

    // Repeater props
    ScalarValue fCount  = 0,
                fOffset = 0;

    // Transform props
    Vec2Value   fAnchorPoint  = {   0,   0 },
                fPosition     = {   0,   0 },
                fScale        = { 100, 100 };
    ScalarValue fRotation     = 0,
                fStartOpacity = 100,
                fEndOpacity   = 100;

    using INHERITED = DiscardableAdapterBase<RepeaterAdapter, RepeaterRenderNode>;
};

} // namespace

std::vector<sk_sp<sksg::RenderNode>> ShapeBuilder::AttachRepeaterDrawEffect(
        const skjson::ObjectValue& jrepeater,
        const AnimationBuilder* abuilder,
        std::vector<sk_sp<sksg::RenderNode>>&& draws) {
    std::vector<sk_sp<sksg::RenderNode>> repeater_draws;

    if (const skjson::ObjectValue* jtransform = jrepeater["tr"]) {
        // input draws are in top->bottom order - reverse for paint order
        std::reverse(draws.begin(), draws.end());

        repeater_draws.reserve(1);
        repeater_draws.push_back(
                    abuilder->attachDiscardableAdapter<RepeaterAdapter>(jrepeater,
                                                                        *jtransform,
                                                                        *abuilder,
                                                                        std::move(draws)));
    } else {
        repeater_draws = std::move(draws);
    }

    return repeater_draws;
}

} // namespace internal
} // namespace skottie
