// 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_native/ErrorScope.h"

#include "common/Assert.h"

namespace dawn_native {

    namespace {

        wgpu::ErrorType ErrorFilterToErrorType(wgpu::ErrorFilter filter) {
            switch (filter) {
                case wgpu::ErrorFilter::None:
                    return wgpu::ErrorType::NoError;
                case wgpu::ErrorFilter::Validation:
                    return wgpu::ErrorType::Validation;
                case wgpu::ErrorFilter::OutOfMemory:
                    return wgpu::ErrorType::OutOfMemory;
            }
            UNREACHABLE();
        }

    }  // namespace

    ErrorScope::ErrorScope(wgpu::ErrorFilter errorFilter)
        : mMatchedErrorType(ErrorFilterToErrorType(errorFilter)) {
    }

    wgpu::ErrorType ErrorScope::GetErrorType() const {
        return mCapturedError;
    }

    const char* ErrorScope::GetErrorMessage() const {
        return mErrorMessage.c_str();
    }

    void ErrorScopeStack::Push(wgpu::ErrorFilter filter) {
        mScopes.push_back(ErrorScope(filter));
    }

    ErrorScope ErrorScopeStack::Pop() {
        ASSERT(!mScopes.empty());
        ErrorScope scope = std::move(mScopes.back());
        mScopes.pop_back();
        return scope;
    }

    bool ErrorScopeStack::Empty() const {
        return mScopes.empty();
    }

    bool ErrorScopeStack::HandleError(wgpu::ErrorType type, const char* message) {
        ASSERT(type != wgpu::ErrorType::NoError);
        for (auto it = mScopes.rbegin(); it != mScopes.rend(); ++it) {
            if (it->mMatchedErrorType != type) {
                // Error filter does not match. Move on to the next scope.
                continue;
            }

            // Filter matches.
            // Record the error if the scope doesn't have one yet.
            if (it->mCapturedError == wgpu::ErrorType::NoError) {
                it->mCapturedError = type;
                it->mErrorMessage = message;
            }

            if (type == wgpu::ErrorType::DeviceLost) {
                if (it->mCapturedError != wgpu::ErrorType::DeviceLost) {
                    // DeviceLost overrides any other error that is not a DeviceLost.
                    it->mCapturedError = type;
                    it->mErrorMessage = message;
                }
            } else {
                // Errors that are not device lost are captured and stop propogating.
                return true;
            }
        }

        // The error was not captured.
        return false;
    }

}  // namespace dawn_native
