/*
 * Copyright 2021 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/effects/Effects.h"

#include "include/private/SkColorData.h"
#include "modules/skottie/src/Adapter.h"
#include "modules/skottie/src/SkottieValue.h"
#include "modules/sksg/include/SkSGColorFilter.h"
#include "modules/sksg/include/SkSGPaint.h"
#include "src/base/SkVx.h"
#include "src/core/SkSwizzlePriv.h"
#include "src/utils/SkJSON.h"

namespace skottie::internal {

namespace {

class CCTonerAdapter final : public DiscardableAdapterBase<CCTonerAdapter,
                                                           sksg::GradientColorFilter> {
    public:
        CCTonerAdapter(const skjson::ArrayValue& jprops,
                       sk_sp<sksg::RenderNode> layer,
                       const AnimationBuilder& abuilder,
                       std::vector<sk_sp<sksg::Color>> colorNodes)
            : INHERITED(sksg::GradientColorFilter::Make(std::move(layer), colorNodes))
            , fColorNodes(std::move(colorNodes))
        {
            enum : size_t {
                kTone_Index        = 0,
                kHiColor_Index     = 1,
                kBrightColor_Index = 2,
                kMidColor_Index    = 3,
                kDarkColor_Index   = 4,
                kShadowColor_Index = 5,
                kBlendAmount_Index = 6,
            };


            EffectBinder(jprops, abuilder, this)
                .bind(       kTone_Index, fTone)
                .bind(    kHiColor_Index, fHighlights)
                .bind(kBrightColor_Index, fBrights)
                .bind(   kMidColor_Index, fMidtones)
                .bind(  kDarkColor_Index, fDarktones)
                .bind(kShadowColor_Index, fShadows);

        }
    private:
        static SkColor lerpColor(SkColor c0, SkColor c1, float t) {
            const auto c0_4f = Sk4f_fromL32(c0),
                       c1_4f = Sk4f_fromL32(c1),
                       c_4f = c0_4f + (c1_4f - c0_4f) * t;

            return Sk4f_toL32(c_4f);
        }

        void onSync() override {
            switch (SkScalarRoundToInt(fTone)) {
                // duotone
                case 1: fColorNodes.at(0)->setColor(fShadows);
                        fColorNodes.at(1)->setColor(lerpColor(fShadows, fHighlights, 0.25));
                        fColorNodes.at(2)->setColor(lerpColor(fShadows, fHighlights, 0.5));
                        fColorNodes.at(3)->setColor(lerpColor(fShadows, fHighlights, 0.75));
                        fColorNodes.at(4)->setColor(fHighlights);
                        break;
                // tritone
                case 2: fColorNodes.at(0)->setColor(fShadows);
                        fColorNodes.at(1)->setColor(lerpColor(fShadows, fMidtones, 0.5));
                        fColorNodes.at(2)->setColor(fMidtones);
                        fColorNodes.at(3)->setColor(lerpColor(fMidtones, fHighlights, 0.5));
                        fColorNodes.at(4)->setColor(fHighlights);
                        break;
                // pentone
                case 3: fColorNodes.at(0)->setColor(fShadows);
                        fColorNodes.at(1)->setColor(fDarktones);
                        fColorNodes.at(2)->setColor(fMidtones);
                        fColorNodes.at(3)->setColor(fBrights);
                        fColorNodes.at(4)->setColor(fHighlights);
                        break;
                // solid
                default: fColorNodes.at(0)->setColor(fMidtones);
                        fColorNodes.at(1)->setColor(fMidtones);
                        fColorNodes.at(2)->setColor(fMidtones);
                        fColorNodes.at(3)->setColor(fMidtones);
                        fColorNodes.at(4)->setColor(fMidtones);
                        break;
            }

            this->node()->setWeight((100-fBlend)/100);
        }


        const std::vector<sk_sp<sksg::Color>> fColorNodes;

        ScalarValue fTone = 0;
        VectorValue fHighlights,
                    fBrights,
                    fMidtones,
                    fDarktones,
                    fShadows;
        ScalarValue fBlend = 0;

        using INHERITED = DiscardableAdapterBase<CCTonerAdapter, sksg::GradientColorFilter>;
};

} // namespace

sk_sp<sksg::RenderNode> EffectBuilder::attachCCTonerEffect(const skjson::ArrayValue& jprops,
                                                             sk_sp<sksg::RenderNode> layer) const {
    std::vector<sk_sp<sksg::Color>> colorNodes = {
        sksg::Color::Make(SK_ColorRED),
        sksg::Color::Make(SK_ColorRED),
        sksg::Color::Make(SK_ColorRED),
        sksg::Color::Make(SK_ColorRED),
        sksg::Color::Make(SK_ColorRED)
    };
    return fBuilder->attachDiscardableAdapter<CCTonerAdapter>(jprops,
                                                              std::move(layer),
                                                              *fBuilder,
                                                              std::move(colorNodes));
}

} // namespace skottie::internal
