// Copyright 2021 The Dawn & Tint Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
//    list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
//    this list of conditions and the following disclaimer in the documentation
//    and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
//    contributors may be used to endorse or promote products derived from
//    this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#include "src/dawn/node/binding/GPUBuffer.h"

#include <memory>
#include <utility>

#include "src/dawn/node/binding/Converter.h"
#include "src/dawn/node/binding/Errors.h"
#include "src/utils/assert.h"
#include "src/utils/numeric.h"

namespace wgpu::binding {

////////////////////////////////////////////////////////////////////////////////
// wgpu::bindings::GPUBuffer
////////////////////////////////////////////////////////////////////////////////
GPUBuffer::GPUBuffer(wgpu::Buffer buffer,
                     wgpu::BufferDescriptor desc,
                     wgpu::Device device,
                     std::shared_ptr<AsyncRunner> async)
    : buffer_(std::move(buffer)),
      desc_(desc),
      device_(std::move(device)),
      async_(std::move(async)),
      mapped_(desc.mappedAtCreation),
      label_(CopyLabel(desc.label)) {}

interop::Promise<void> GPUBuffer::mapAsync(Napi::Env env,
                                           interop::GPUMapModeFlags modeIn,
                                           interop::GPUSize64 offset,
                                           std::optional<interop::GPUSize64> size) {
    // Convert the mapMode and reject with the TypeError if it happens.
    Converter conv(env, device_);
    wgpu::MapMode mode;
    if (!conv(mode, modeIn)) {
        return {env, interop::kUnusedPromise};
    }

    // Early rejection when there is already a mapping pending.
    if (pending_map_) {
        auto promise = interop::Promise<void>(env, PROMISE_INFO);
        promise.Reject(Errors::OperationError(env));
        return promise;
    }

    uint64_t rangeSize = size.has_value() ? size.value().value : (desc_.size - offset);

    auto ctx = std::make_unique<AsyncContext<void>>(env, PROMISE_INFO, async_);
    pending_map_.emplace(ctx->promise);

    buffer_.MapAsync(
        mode, dawn::checked_cast<size_t>(uint64_t{offset}), dawn::checked_cast<size_t>(rangeSize),
        wgpu::CallbackMode::AllowProcessEvents,
        [ctx = std::move(ctx), this](wgpu::MapAsyncStatus status, wgpu::StringView) {
            // The promise may already have been resolved with an AbortError if there was an early
            // destroy() or early unmap().
            if (ctx->promise.GetState() != interop::PromiseState::Pending) {
                DAWN_ASSERT(ctx->promise.GetState() == interop::PromiseState::Rejected);
                return;
            }

            switch (status) {
                case wgpu::MapAsyncStatus::Success:
                    ctx->promise.Resolve();
                    mapped_ = true;
                    break;
                case wgpu::MapAsyncStatus::CallbackCancelled:
                case wgpu::MapAsyncStatus::Aborted:
                    DAWN_ASSERT(status != wgpu::MapAsyncStatus::CallbackCancelled);
                    async_->Reject(ctx->env, ctx->promise, Errors::AbortError(ctx->env));
                    break;
                case wgpu::MapAsyncStatus::Error:
                    async_->Reject(ctx->env, ctx->promise, Errors::OperationError(ctx->env));
                    break;
            }

            // This captured promise is the currently pending mapping, reset it so we can start new
            // mappings.
            DAWN_ASSERT(*pending_map_ == ctx->promise);
            pending_map_.reset();
        });

    return pending_map_.value();
}

interop::ArrayBuffer GPUBuffer::getMappedRange(Napi::Env env,
                                               interop::GPUSize64 offset,
                                               std::optional<interop::GPUSize64> size) {
    uint64_t s = size.has_value() ? size.value().value : (desc_.size - offset);

    uint64_t start = offset;
    uint64_t end = offset + s;
    for (auto& mapping : mappings_) {
        if (mapping.Intersects(start, end)) {
            Errors::OperationError(env).ThrowAsJavaScriptException();
            return {};
        }
    }

    auto* ptr =
        (desc_.usage & wgpu::BufferUsage::MapWrite)
            ? buffer_.GetMappedRange(dawn::checked_cast<size_t>(uint64_t{offset}),
                                     dawn::checked_cast<size_t>(s))
            : const_cast<void*>(buffer_.GetConstMappedRange(
                  dawn::checked_cast<size_t>(uint64_t{offset}), dawn::checked_cast<size_t>(s)));
    if (!ptr) {
        Errors::OperationError(env).ThrowAsJavaScriptException();
        return {};
    }
    auto array_buffer = Napi::ArrayBuffer::New(env, ptr, dawn::checked_cast<size_t>(s));
    // TODO(crbug.com/dawn/1135): Ownership here is the wrong way around.
    mappings_.emplace_back(Mapping{start, end, Napi::Persistent(array_buffer)});
    return array_buffer;
}

void GPUBuffer::unmap(Napi::Env env) {
    DetachMappings(env);
    buffer_.Unmap();
}

void GPUBuffer::destroy(Napi::Env env) {
    DetachMappings(env);
    buffer_.Destroy();
}

interop::GPUSize64Out GPUBuffer::getSize(Napi::Env) {
    return buffer_.GetSize();
}

interop::GPUBufferMapState GPUBuffer::getMapState(Napi::Env env) {
    if (mapped_) {
        return interop::GPUBufferMapState::kMapped;
    }

    if (pending_map_) {
        DAWN_ASSERT(pending_map_->GetState() == interop::PromiseState::Pending);
        return interop::GPUBufferMapState::kPending;
    }

    return interop::GPUBufferMapState::kUnmapped;
}

interop::GPUFlagsConstant GPUBuffer::getUsage(Napi::Env env) {
    interop::GPUBufferUsageFlags result;

    Converter conv(env);
    if (!conv(result, buffer_.GetUsage())) {
        Napi::Error::New(env, "Couldn't convert usage to a JavaScript value.")
            .ThrowAsJavaScriptException();
        return 0u;  // Doesn't get used.
    }

    return result;
}

void GPUBuffer::DetachMappings(Napi::Env env) {
    mapped_ = false;

    if (pending_map_) {
        pending_map_->Reject(Errors::AbortError(env));
        pending_map_.reset();
    }

    for (auto& mapping : mappings_) {
        mapping.buffer.Value().Detach();
    }
    mappings_.clear();
}

std::string GPUBuffer::getLabel(Napi::Env) {
    return label_;
}

void GPUBuffer::setLabel(Napi::Env, std::string value) {
    buffer_.SetLabel(std::string_view(value));
    label_ = value;
}

}  // namespace wgpu::binding
