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

#include "include/core/SkCanvas.h"
#include "include/core/SkTypes.h"
#include "include/utils/SkRandom.h"
#include "modules/particles/include/SkParticleEffect.h"
#include "modules/particles/include/SkParticleSerialization.h"
#include "modules/skresources/include/SkResources.h"
#include "src/sksl/SkSLByteCode.h"

#include <string>

#include "modules/canvaskit/WasmCommon.h"

#include <emscripten.h>
#include <emscripten/bind.h>

using namespace emscripten;

namespace {

class ParticleAssetProvider : public skresources::ResourceProvider {
public:
    ~ParticleAssetProvider() override = default;

    // Tried using a map, but that gave strange errors like
    // https://emscripten.org/docs/porting/guidelines/function_pointer_issues.html
    // Not entirely sure why, but perhaps the iterator in the map was
    // confusing enscripten.
    using AssetVec = std::vector<std::pair<SkString, sk_sp<SkData>>>;

    static sk_sp<ParticleAssetProvider> Make(AssetVec assets) {
        if (assets.empty()) {
            return nullptr;
        }

        return sk_sp<ParticleAssetProvider>(new ParticleAssetProvider(std::move(assets)));
    }

    sk_sp<skresources::ImageAsset> loadImageAsset(const char[] /* path */,
                                                  const char name[],
                                                  const char[] /* id */) const override {
        // For CK we ignore paths & IDs, and identify images based solely on name.
        if (auto data = this->findAsset(name)) {
            return skresources::MultiFrameImageAsset::Make(std::move(data));
        }

        return nullptr;
    }

    sk_sp<SkData> loadFont(const char name[], const char[] /* url */) const override {
        // Same as images paths, we ignore font URLs.
        return this->findAsset(name);
    }

private:
    explicit ParticleAssetProvider(AssetVec assets) : fAssets(std::move(assets)) {}

    sk_sp<SkData> findAsset(const char name[]) const {
        for (const auto& asset : fAssets) {
            if (asset.first.equals(name)) {
                return asset.second;
            }
        }

        SkDebugf("Could not find %s\n", name);
        return nullptr;
    }

    const AssetVec fAssets;
};

}

struct SimpleUniform {
    int columns;
    int rows;
    int slot; // the index into the uniforms array that this uniform begins.
};

SimpleUniform fromUniform(SkSL::ByteCode::Uniform u) {
    SimpleUniform su;
    su.columns = u.fColumns;
    su.rows = u.fRows;
    su.slot = u.fSlot;
    return su;
}

EMSCRIPTEN_BINDINGS(Particles) {
    class_<SkParticleEffect>("SkParticleEffect")
        .smart_ptr<sk_sp<SkParticleEffect>>("sk_sp<SkParticleEffect>")
        .function("draw", &SkParticleEffect::draw, allow_raw_pointers())
        .function("_effectUniformPtr", optional_override([](SkParticleEffect& self)->uintptr_t {
            return reinterpret_cast<uintptr_t>(self.effectUniforms());
        }))
        .function("_particleUniformPtr", optional_override([](SkParticleEffect& self)->uintptr_t {
            return reinterpret_cast<uintptr_t>(self.particleUniforms());
        }))
        .function("getEffectUniformCount", optional_override([](SkParticleEffect& self)->int {
            auto ec = self.effectCode();
            if (!ec) {
                return -1;
            }
            return ec->getUniformCount();
        }))
        .function("getEffectUniformFloatCount", optional_override([](SkParticleEffect& self)->int {
            auto ec = self.effectCode();
            if (!ec) {
                return -1;
            }
            return ec->getUniformSlotCount();
        }))
        .function("getEffectUniformName", optional_override([](SkParticleEffect& self, int i)->JSString {
            auto ec = self.effectCode();
            if (!ec) {
                return emscripten::val::null();
            }
            return emscripten::val(ec->getUniform(i).fName.c_str());
        }))
        .function("getEffectUniform", optional_override([](SkParticleEffect& self, int i)->SimpleUniform {
            SimpleUniform su;
            auto ec = self.effectCode();
            if (!ec) {
                return su;
            }
            su = fromUniform(ec->getUniform(i));
            return su;
        }))
        .function("getParticleUniformCount", optional_override([](SkParticleEffect& self)->int {
            auto ec = self.particleCode();
            if (!ec) {
                return -1;
            }
            return ec->getUniformCount();
        }))
        .function("getParticleUniformFloatCount", optional_override([](SkParticleEffect& self)->int {
            auto ec = self.particleCode();
            if (!ec) {
                return -1;
            }
            return ec->getUniformSlotCount();
        }))
        .function("getParticleUniformName", optional_override([](SkParticleEffect& self, int i)->JSString {
            auto ec = self.particleCode();
            if (!ec) {
                return emscripten::val::null();
            }
            return emscripten::val(ec->getUniform(i).fName.c_str());
        }))
        .function("getParticleUniform", optional_override([](SkParticleEffect& self, int i)->SimpleUniform {
            SimpleUniform su;
            auto ec = self.particleCode();
            if (!ec) {
                return su;
            }
            su = fromUniform(ec->getUniform(i));
            return su;
        }))
        .function("setPosition", select_overload<void (SkPoint)>(&SkParticleEffect::setPosition))
        .function("setRate", select_overload<void (float)>(&SkParticleEffect::setRate))
        .function("start", select_overload<void (double, bool)>(&SkParticleEffect::start))
        .function("update", select_overload<void (double)>(&SkParticleEffect::update));

    value_object<SimpleUniform>("SimpleUniform")
        .field("columns", &SimpleUniform::columns)
        .field("rows",    &SimpleUniform::rows)
        .field("slot",    &SimpleUniform::slot);

    function("_MakeParticles", optional_override([](std::string json,
                                                   size_t assetCount,
                                                   uintptr_t /* char**    */ nptr,
                                                   uintptr_t /* uint8_t** */ dptr,
                                                   uintptr_t /* size_t*   */ sptr)
                                                ->sk_sp<SkParticleEffect> {
        // See the comment in canvaskit_bindings.cpp about the use of uintptr_t
        static bool didInit = false;
        if (!didInit) {
            SkParticleEffect::RegisterParticleTypes();
            didInit = true;
        }

        const auto assetNames = reinterpret_cast<char**   >(nptr);
        const auto assetDatas = reinterpret_cast<uint8_t**>(dptr);
        const auto assetSizes = reinterpret_cast<size_t*  >(sptr);

        ParticleAssetProvider::AssetVec assets;
        assets.reserve(assetCount);

        for (size_t i = 0; i < assetCount; i++) {
            auto name  = SkString(assetNames[i]);
            auto bytes = SkData::MakeFromMalloc(assetDatas[i], assetSizes[i]);
            assets.push_back(std::make_pair(std::move(name), std::move(bytes)));
        }

        sk_sp<SkParticleEffectParams> params(new SkParticleEffectParams());
        skjson::DOM dom(json.c_str(), json.length());
        SkFromJsonVisitor fromJson(dom.root());
        params->visitFields(&fromJson);
        params->prepare(skresources::DataURIResourceProviderProxy::Make(
                            ParticleAssetProvider::Make(std::move(assets))).get());
        return sk_sp<SkParticleEffect>(new SkParticleEffect(std::move(params)));
    }));
    constant("particles", true);

}
