// 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) {
            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
