/*
 * 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>("ParticleEffect")
        .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);

}
