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

#include "SkSGTransform.h"

#include "SkCanvas.h"
#include "SkSGTransformPriv.h"

namespace sksg {

namespace {

template <typename T>
class Concat final : public Transform {
public:
    template <typename = std::enable_if<std::is_same<T, SkMatrix  >::value ||
                                        std::is_same<T, SkMatrix44>::value >>
    Concat(sk_sp<Transform> a, sk_sp<Transform> b)
        : fA(std::move(a)), fB(std::move(b)) {
        SkASSERT(fA);
        SkASSERT(fB);

        this->observeInval(fA);
        this->observeInval(fB);
    }

    ~Concat() override {
        this->unobserveInval(fA);
        this->unobserveInval(fB);
    }

protected:
    SkRect onRevalidate(InvalidationController* ic, const SkMatrix& ctm) override {
        fA->revalidate(ic, ctm);
        fB->revalidate(ic, ctm);

        fComposed.setConcat(TransformPriv::As<T>(fA),
                            TransformPriv::As<T>(fB));
        return SkRect::MakeEmpty();
    }

    bool is44() const override { return std::is_same<T, SkMatrix44>::value; }

    SkMatrix asMatrix() const override {
        return fComposed;
    }

    SkMatrix44 asMatrix44() const override {
        return fComposed;
    }

private:
    const sk_sp<Transform> fA, fB;
    T                      fComposed;

    using INHERITED = Transform;
};

} // namespace

// Transform nodes don't generate damage on their own, but via ancestor TransformEffects.
Transform::Transform() : INHERITED(kBubbleDamage_Trait) {}

sk_sp<Transform> Transform::MakeConcat(sk_sp<Transform> a, sk_sp<Transform> b) {
    if (!a) {
        return b;
    }

    if (!b) {
        return a;
    }

    return TransformPriv::Is44(a) || TransformPriv::Is44(b)
        ? sk_sp<Transform>(new Concat<SkMatrix44>(std::move(a), std::move(b)))
        : sk_sp<Transform>(new Concat<SkMatrix  >(std::move(a), std::move(b)));
}

TransformEffect::TransformEffect(sk_sp<RenderNode> child, sk_sp<Transform> transform)
    : INHERITED(std::move(child))
    , fTransform(std::move(transform)) {
    this->observeInval(fTransform);
}

TransformEffect::~TransformEffect() {
    this->unobserveInval(fTransform);
}

void TransformEffect::onRender(SkCanvas* canvas, const RenderContext* ctx) const {
    const auto m = TransformPriv::As<SkMatrix>(fTransform);
    SkAutoCanvasRestore acr(canvas, !m.isIdentity());
    canvas->concat(m);
    this->INHERITED::onRender(canvas, ctx);
}

const RenderNode* TransformEffect::onNodeAt(const SkPoint& p) const {
    const auto m = TransformPriv::As<SkMatrix>(fTransform);

    SkPoint mapped_p;
    m.mapPoints(&mapped_p, &p, 1);

    return this->INHERITED::onNodeAt(mapped_p);
}

SkRect TransformEffect::onRevalidate(InvalidationController* ic, const SkMatrix& ctm) {
    SkASSERT(this->hasInval());

    // We don't care about matrix reval results.
    fTransform->revalidate(ic, ctm);

    const auto m = TransformPriv::As<SkMatrix>(fTransform);
    auto bounds = this->INHERITED::onRevalidate(ic, SkMatrix::Concat(ctm, m));
    m.mapRect(&bounds);

    return bounds;
}

} // namespace sksg
