// 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 std::vector<std::string>& 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
