// Copyright 2019 The Dawn Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "dawn/wire/client/Client.h"

#include "dawn/common/Compiler.h"
#include "dawn/wire/client/Device.h"

namespace dawn::wire::client {

namespace {

class NoopCommandSerializer final : public CommandSerializer {
  public:
    static NoopCommandSerializer* GetInstance() {
        static NoopCommandSerializer gNoopCommandSerializer;
        return &gNoopCommandSerializer;
    }

    ~NoopCommandSerializer() = default;

    size_t GetMaximumAllocationSize() const final { return 0; }
    void* GetCmdSpace(size_t size) final { return nullptr; }
    bool Flush() final { return false; }
};

}  // anonymous namespace

Client::Client(CommandSerializer* serializer, MemoryTransferService* memoryTransferService)
    : ClientBase(), mSerializer(serializer), mMemoryTransferService(memoryTransferService) {
    if (mMemoryTransferService == nullptr) {
        // If a MemoryTransferService is not provided, fall back to inline memory.
        mOwnedMemoryTransferService = CreateInlineMemoryTransferService();
        mMemoryTransferService = mOwnedMemoryTransferService.get();
    }
}

Client::~Client() {
    DestroyAllObjects();
}

void Client::DestroyAllObjects() {
    for (auto& objectList : mObjects) {
        ObjectType objectType = static_cast<ObjectType>(&objectList - mObjects.data());
        if (objectType == ObjectType::Device) {
            continue;
        }
        while (!objectList.empty()) {
            ObjectBase* object = objectList.head()->value();

            DestroyObjectCmd cmd;
            cmd.objectType = objectType;
            cmd.objectId = object->id;
            SerializeCommand(cmd);
            FreeObject(objectType, object);
        }
    }

    while (!mObjects[ObjectType::Device].empty()) {
        ObjectBase* object = mObjects[ObjectType::Device].head()->value();

        DestroyObjectCmd cmd;
        cmd.objectType = ObjectType::Device;
        cmd.objectId = object->id;
        SerializeCommand(cmd);
        FreeObject(ObjectType::Device, object);
    }
}

ReservedTexture Client::ReserveTexture(WGPUDevice device) {
    auto* allocation = TextureAllocator().New(this);

    ReservedTexture result;
    result.texture = ToAPI(allocation->object.get());
    result.id = allocation->object->id;
    result.generation = allocation->generation;
    result.deviceId = FromAPI(device)->id;
    result.deviceGeneration = DeviceAllocator().GetGeneration(FromAPI(device)->id);
    return result;
}

ReservedSwapChain Client::ReserveSwapChain(WGPUDevice device) {
    auto* allocation = SwapChainAllocator().New(this);

    ReservedSwapChain result;
    result.swapchain = ToAPI(allocation->object.get());
    result.id = allocation->object->id;
    result.generation = allocation->generation;
    result.deviceId = FromAPI(device)->id;
    result.deviceGeneration = DeviceAllocator().GetGeneration(FromAPI(device)->id);
    return result;
}

ReservedDevice Client::ReserveDevice() {
    auto* allocation = DeviceAllocator().New(this);

    ReservedDevice result;
    result.device = ToAPI(allocation->object.get());
    result.id = allocation->object->id;
    result.generation = allocation->generation;
    return result;
}

ReservedInstance Client::ReserveInstance() {
    auto* allocation = InstanceAllocator().New(this);

    ReservedInstance result;
    result.instance = ToAPI(allocation->object.get());
    result.id = allocation->object->id;
    result.generation = allocation->generation;
    return result;
}

void Client::ReclaimTextureReservation(const ReservedTexture& reservation) {
    TextureAllocator().Free(FromAPI(reservation.texture));
}

void Client::ReclaimSwapChainReservation(const ReservedSwapChain& reservation) {
    SwapChainAllocator().Free(FromAPI(reservation.swapchain));
}

void Client::ReclaimDeviceReservation(const ReservedDevice& reservation) {
    DeviceAllocator().Free(FromAPI(reservation.device));
}

void Client::ReclaimInstanceReservation(const ReservedInstance& reservation) {
    InstanceAllocator().Free(FromAPI(reservation.instance));
}

void Client::Disconnect() {
    mDisconnected = true;
    mSerializer = ChunkedCommandSerializer(NoopCommandSerializer::GetInstance());

    auto& deviceList = mObjects[ObjectType::Device];
    {
        for (LinkNode<ObjectBase>* device = deviceList.head(); device != deviceList.end();
             device = device->next()) {
            static_cast<Device*>(device->value())
                ->HandleDeviceLost(WGPUDeviceLostReason_Undefined, "GPU connection lost");
        }
    }
    for (auto& objectList : mObjects) {
        for (LinkNode<ObjectBase>* object = objectList.head(); object != objectList.end();
             object = object->next()) {
            object->value()->CancelCallbacksForDisconnect();
        }
    }
}

bool Client::IsDisconnected() const {
    return mDisconnected;
}

}  // namespace dawn::wire::client
