// Copyright 2021 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/CompilationMessages.h"

#include "common/Assert.h"
#include "dawn_native/dawn_platform.h"

#include <tint/tint.h>

namespace dawn::native {

    namespace {

        WGPUCompilationMessageType tintSeverityToMessageType(tint::diag::Severity severity) {
            switch (severity) {
                case tint::diag::Severity::Note:
                    return WGPUCompilationMessageType_Info;
                case tint::diag::Severity::Warning:
                    return WGPUCompilationMessageType_Warning;
                default:
                    return WGPUCompilationMessageType_Error;
            }
        }

    }  // anonymous namespace

    OwnedCompilationMessages::OwnedCompilationMessages() {
        mCompilationInfo.nextInChain = 0;
        mCompilationInfo.messageCount = 0;
        mCompilationInfo.messages = nullptr;
    }

    void OwnedCompilationMessages::AddMessageForTesting(std::string message,
                                                        wgpu::CompilationMessageType type,
                                                        uint64_t lineNum,
                                                        uint64_t linePos,
                                                        uint64_t offset,
                                                        uint64_t length) {
        // Cannot add messages after GetCompilationInfo has been called.
        ASSERT(mCompilationInfo.messages == nullptr);

        mMessageStrings.push_back(message);
        mMessages.push_back({nullptr, nullptr, static_cast<WGPUCompilationMessageType>(type),
                             lineNum, linePos, offset, length});
    }

    void OwnedCompilationMessages::AddMessage(const tint::diag::Diagnostic& diagnostic) {
        // Cannot add messages after GetCompilationInfo has been called.
        ASSERT(mCompilationInfo.messages == nullptr);

        // Tint line and column values are 1-based.
        uint64_t lineNum = diagnostic.source.range.begin.line;
        uint64_t linePos = diagnostic.source.range.begin.column;
        // The offset is 0-based.
        uint64_t offset = 0;
        uint64_t length = 0;

        if (lineNum && linePos && diagnostic.source.file_content) {
            const auto& lines = diagnostic.source.file_content->lines;
            size_t i = 0;
            // To find the offset of the message position, loop through each of the first lineNum-1
            // lines and add it's length (+1 to account for the line break) to the offset.
            for (; i < lineNum - 1; ++i) {
                offset += lines[i].length() + 1;
            }

            // If the end line is on a different line from the beginning line, add the length of the
            // lines in between to the ending offset.
            uint64_t endLineNum = diagnostic.source.range.end.line;
            uint64_t endLinePos = diagnostic.source.range.end.column;

            // If the range has a valid start but the end it not specified, clamp it to the start.
            if (endLineNum == 0 || endLinePos == 0) {
                endLineNum = lineNum;
                endLinePos = linePos;
            }

            // Negative ranges aren't allowed
            ASSERT(endLineNum >= lineNum);

            uint64_t endOffset = offset;
            for (; i < endLineNum - 1; ++i) {
                endOffset += lines[i].length() + 1;
            }

            // Add the line positions to the offset and endOffset to get their final positions
            // within the code string.
            offset += linePos - 1;
            endOffset += endLinePos - 1;

            // Negative ranges aren't allowed
            ASSERT(endOffset >= offset);

            // The length of the message is the difference between the starting offset and the
            // ending offset.
            length = endOffset - offset;
        }

        if (diagnostic.code) {
            mMessageStrings.push_back(std::string(diagnostic.code) + ": " + diagnostic.message);
        } else {
            mMessageStrings.push_back(diagnostic.message);
        }

        mMessages.push_back({nullptr, nullptr, tintSeverityToMessageType(diagnostic.severity),
                             lineNum, linePos, offset, length});
    }

    void OwnedCompilationMessages::AddMessages(const tint::diag::List& diagnostics) {
        // Cannot add messages after GetCompilationInfo has been called.
        ASSERT(mCompilationInfo.messages == nullptr);

        for (const auto& diag : diagnostics) {
            AddMessage(diag);
        }

        AddFormattedTintMessages(diagnostics);
    }

    void OwnedCompilationMessages::ClearMessages() {
        // Cannot clear messages after GetCompilationInfo has been called.
        ASSERT(mCompilationInfo.messages == nullptr);

        mMessageStrings.clear();
        mMessages.clear();
    }

    const WGPUCompilationInfo* OwnedCompilationMessages::GetCompilationInfo() {
        mCompilationInfo.messageCount = mMessages.size();
        mCompilationInfo.messages = mMessages.data();

        // Ensure every message points at the correct message string. Cannot do this earlier, since
        // vector reallocations may move the pointers around.
        for (size_t i = 0; i < mCompilationInfo.messageCount; ++i) {
            WGPUCompilationMessage& message = mMessages[i];
            std::string& messageString = mMessageStrings[i];
            message.message = messageString.c_str();
        }

        return &mCompilationInfo;
    }

    const std::vector<std::string>& OwnedCompilationMessages::GetFormattedTintMessages() {
        return mFormattedTintMessages;
    }

    void OwnedCompilationMessages::AddFormattedTintMessages(const tint::diag::List& diagnostics) {
        tint::diag::List messageList;
        size_t warningCount = 0;
        size_t errorCount = 0;
        for (auto& diag : diagnostics) {
            switch (diag.severity) {
                case (tint::diag::Severity::Fatal):
                case (tint::diag::Severity::Error):
                case (tint::diag::Severity::InternalCompilerError): {
                    errorCount++;
                    messageList.add(tint::diag::Diagnostic(diag));
                    break;
                }
                case (tint::diag::Severity::Warning): {
                    warningCount++;
                    messageList.add(tint::diag::Diagnostic(diag));
                    break;
                }
                default:
                    break;
            }
        }
        if (errorCount == 0 && warningCount == 0) {
            return;
        }
        tint::diag::Formatter::Style style;
        style.print_newline_at_end = false;
        std::ostringstream t;
        if (errorCount > 0) {
            t << errorCount << " error(s) ";
            if (warningCount > 0) {
                t << "and ";
            }
        }
        if (warningCount > 0) {
            t << warningCount << " warning(s) ";
        }
        t << "generated while compiling the shader:" << std::endl
          << tint::diag::Formatter{style}.format(messageList);
        mFormattedTintMessages.push_back(t.str());
    }

}  // namespace dawn::native
