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

#include "modules/skottie/src/Transform.h"

#include "include/core/SkRefCnt.h"
#include "include/core/SkScalar.h"
#include "include/private/SkAssert.h"
#include "include/private/SkTPin.h"
#include "modules/jsonreader/SkJSONReader.h"
#include "modules/skottie/src/SkottiePriv.h"
#include "modules/sksg/include/SkSGTransform.h"

#include <cmath>

namespace skottie {
namespace internal {

TransformAdapter2D::TransformAdapter2D(const AnimationBuilder& abuilder,
                                       const skjson::ObjectValue* janchor_point,
                                       const skjson::ObjectValue* jposition,
                                       const skjson::ObjectValue* jscale,
                                       const skjson::ObjectValue* jrotation,
                                       const skjson::ObjectValue* jskew,
                                       const skjson::ObjectValue* jskew_axis,
                                       bool auto_orient)
    : INHERITED(sksg::Matrix<SkMatrix>::Make(SkMatrix::I())) {

    this->bind(abuilder, janchor_point, fAnchorPoint);
    this->bind(abuilder, jscale       , fScale);
    this->bind(abuilder, jrotation    , fRotation);
    this->bind(abuilder, jskew        , fSkew);
    this->bind(abuilder, jskew_axis   , fSkewAxis);

    this->bindAutoOrientable(abuilder, jposition, &fPosition, auto_orient ? &fOrientation
                                                                          : nullptr);
}

TransformAdapter2D::~TransformAdapter2D() {}

void TransformAdapter2D::onSync() {
    this->node()->setMatrix(this->totalMatrix());
}

SkMatrix TransformAdapter2D::totalMatrix() const {
    auto skew_matrix = [](float sk, float sa) {
        if (!sk) return SkMatrix::I();

        // AE control limit.
        static constexpr float kMaxSkewAngle = 85;
        sk = -SkDegreesToRadians(SkTPin(sk, -kMaxSkewAngle, kMaxSkewAngle));
        sa =  SkDegreesToRadians(sa);

        // Similar to CSS/SVG SkewX [1] with an explicit rotation.
        // [1] https://www.w3.org/TR/css-transforms-1/#SkewXDefined
        return SkMatrix::RotateRad(sa)
             * SkMatrix::Skew(std::tan(sk), 0)
             * SkMatrix::RotateRad(-sa);
    };

    return SkMatrix::Translate(fPosition.x, fPosition.y)
         * SkMatrix::RotateDeg(fRotation + fOrientation)
         * skew_matrix        (fSkew, fSkewAxis)
         * SkMatrix::Scale    (fScale.x / 100, fScale.y / 100) // 100% based
         * SkMatrix::Translate(-fAnchorPoint.x, -fAnchorPoint.y);
}

SkPoint TransformAdapter2D::getAnchorPoint() const {
    return { fAnchorPoint.x, fAnchorPoint.y };
}

void TransformAdapter2D::setAnchorPoint(const SkPoint& ap) {
    fAnchorPoint = { ap.x(), ap.y() };
    this->onSync();
}

SkPoint TransformAdapter2D::getPosition() const {
    return { fPosition.x, fPosition.y };
}

void TransformAdapter2D::setPosition(const SkPoint& p) {
    fPosition = { p.x(), p.y() };
    this->onSync();
}

SkVector TransformAdapter2D::getScale() const {
    return { fScale.x, fScale.y };
}

void TransformAdapter2D::setScale(const SkVector& s) {
    fScale = { s.x(), s.y() };
    this->onSync();
}

void TransformAdapter2D::setRotation(float r) {
    fRotation = r;
    this->onSync();
}

void TransformAdapter2D::setSkew(float sk) {
    fSkew = sk;
    this->onSync();
}

void TransformAdapter2D::setSkewAxis(float sa) {
    fSkewAxis = sa;
    this->onSync();
}

sk_sp<sksg::Transform> AnimationBuilder::attachMatrix2D(const skjson::ObjectValue& jtransform,
                                                        sk_sp<sksg::Transform> parent,
                                                        bool auto_orient) const {
    const auto* jrotation = &jtransform["r"];
    if (jrotation->is<skjson::NullValue>()) {
        // Some 2D rotations are disguised as 3D...
        jrotation = &jtransform["rz"];
    }

    auto adapter = TransformAdapter2D::Make(*this,
                                            jtransform["a"],
                                            jtransform["p"],
                                            jtransform["s"],
                                            *jrotation,
                                            jtransform["sk"],
                                            jtransform["sa"],
                                            auto_orient);
    SkASSERT(adapter);

    const auto dispatched = this->dispatchTransformProperty(adapter);

    if (adapter->isStatic()) {
        if (!dispatched && adapter->totalMatrix().isIdentity()) {
            // The transform has no observable effects - we can discard.
            return parent;
        }
        adapter->seek(0);
    } else {
        fCurrentAnimatorScope->push_back(adapter);
    }

    return sksg::Transform::MakeConcat(std::move(parent), adapter->node());
}

TransformAdapter3D::TransformAdapter3D(const skjson::ObjectValue& jtransform,
                                       const AnimationBuilder& abuilder)
    : INHERITED(sksg::Matrix<SkM44>::Make(SkM44())) {

    this->bind(abuilder, jtransform["a"], fAnchorPoint);
    this->bind(abuilder, jtransform["p"], fPosition);
    this->bind(abuilder, jtransform["s"], fScale);

    // Axis-wise rotation and orientation are mapped to the same rotation property (3D rotation).
    // The difference is in how they get interpolated (scalar/decomposed vs. vector).
    this->bind(abuilder, jtransform["rx"], fRx);
    this->bind(abuilder, jtransform["ry"], fRy);
    this->bind(abuilder, jtransform["rz"], fRz);
    this->bind(abuilder, jtransform["or"], fOrientation);
}

TransformAdapter3D::~TransformAdapter3D() = default;

void TransformAdapter3D::onSync() {
    this->node()->setMatrix(this->totalMatrix());
}

SkV3 TransformAdapter3D::anchor_point() const {
    return fAnchorPoint;
}

SkV3 TransformAdapter3D::position() const {
    return fPosition;
}

SkV3 TransformAdapter3D::rotation() const {
    // orientation and axis-wise rotation map onto the same property.
    return static_cast<SkV3>(fOrientation) + SkV3{ fRx, fRy, fRz };
}

SkM44 TransformAdapter3D::totalMatrix() const {
    const auto anchor_point = this->anchor_point(),
               position     = this->position(),
               scale        = static_cast<SkV3>(fScale),
               rotation     = this->rotation();

    return SkM44::Translate(position.x, position.y, position.z)
         * SkM44::Rotate({ 1, 0, 0 }, SkDegreesToRadians(rotation.x))
         * SkM44::Rotate({ 0, 1, 0 }, SkDegreesToRadians(rotation.y))
         * SkM44::Rotate({ 0, 0, 1 }, SkDegreesToRadians(rotation.z))
         * SkM44::Scale(scale.x / 100, scale.y / 100, scale.z / 100)
         * SkM44::Translate(-anchor_point.x, -anchor_point.y, -anchor_point.z);
}

sk_sp<sksg::Transform> AnimationBuilder::attachMatrix3D(const skjson::ObjectValue& jtransform,
                                                        sk_sp<sksg::Transform> parent,
                                                        bool /*TODO: auto_orient*/) const {
    auto adapter = TransformAdapter3D::Make(jtransform, *this);
    SkASSERT(adapter);

    if (adapter->isStatic()) {
        // TODO: SkM44::isIdentity?
        if (adapter->totalMatrix() == SkM44()) {
            // The transform has no observable effects - we can discard.
            return parent;
        }
        adapter->seek(0);
    } else {
        fCurrentAnimatorScope->push_back(adapter);
    }

    return sksg::Transform::MakeConcat(std::move(parent), adapter->node());
}

} // namespace internal
} // namespace skottie
