/*
 * Copyright 2019 Google LLC
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "src/utils/SkShaderUtils.h"

#include "include/core/SkString.h"
#include "include/private/SkSLString.h"
#include "include/private/SkTArray.h"
#include "src/sksl/SkSLProgramSettings.h"

namespace SkShaderUtils {

class GLSLPrettyPrint {
public:
    GLSLPrettyPrint() {}

    std::string prettify(const std::string& string) {
        fTabs = 0;
        fFreshline = true;

        // If a string breaks while in the middle 'parse until' we need to continue parsing on the
        // next string
        fInParseUntilNewline = false;
        fInParseUntil = false;

        int parensDepth = 0;

        // setup pretty state
        fIndex = 0;
        fLength = string.length();
        fInput = string.c_str();

        while (fLength > fIndex) {
            /* the heart and soul of our prettification algorithm.  The rules should hopefully
             * be self explanatory.  For '#' and '//' tokens we parse until we reach a newline.
             *
             * For long style comments like this one, we search for the ending token.  We also
             * preserve whitespace in these comments WITH THE CAVEAT that we do the newlines
             * ourselves.  This allows us to remain in control of line numbers, and matching
             * tabs Existing tabs in the input string are copied over too, but this will look
             *  funny
             *
             * '{' and '}' are handled in basically the same way.  We add a newline if we aren't
             * on a fresh line, dirty the line, then add a second newline, ie braces are always
             * on their own lines indented properly.  The one funkiness here is structs print
             * with the semicolon on its own line.  Its not a problem for a glsl compiler though
             *
             * '(' and ')' are basically ignored, except as a sign we need to ignore ';' ala
             * in for loops.
             *
             * ';' means add a new line
             *
             * '\t' and '\n' are ignored in general parsing for backwards compatability with
             * existing shader code and we also have a special case for handling whitespace
             * at the beginning of fresh lines.
             *
             * Otherwise just add the new character to the pretty string, indenting if
             * necessary.
             */
            if (fInParseUntilNewline) {
                this->parseUntilNewline();
            } else if (fInParseUntil) {
                this->parseUntil(fInParseUntilToken);
            } else if (this->hasToken("#") || this->hasToken("//")) {
                this->parseUntilNewline();
            } else if (this->hasToken("/*")) {
                this->parseUntil("*/");
            } else if ('{' == fInput[fIndex]) {
                this->newline();
                this->appendChar('{');
                fTabs++;
                this->newline();
            } else if ('}' == fInput[fIndex]) {
                fTabs--;
                this->newline();
                this->appendChar('}');
                this->newline();
            } else if (this->hasToken(")")) {
                parensDepth--;
            } else if (this->hasToken("(")) {
                parensDepth++;
            } else if (!parensDepth && this->hasToken(";")) {
                this->newline();
            } else if ('\t' == fInput[fIndex] || '\n' == fInput[fIndex] ||
                        (fFreshline && ' ' == fInput[fIndex])) {
                fIndex++;
            } else {
                this->appendChar(fInput[fIndex]);
            }
        }

        return fPretty;
    }

private:
    void appendChar(char c) {
        this->tabString();
        SkSL::String::appendf(&fPretty, "%c", fInput[fIndex++]);
        fFreshline = false;
    }

    // hasToken automatically consumes the next token, if it is a match, and then tabs
    // if necessary, before inserting the token into the pretty string
    bool hasToken(const char* token) {
        size_t i = fIndex;
        for (size_t j = 0; token[j] && fLength > i; i++, j++) {
            if (token[j] != fInput[i]) {
                return false;
            }
        }
        this->tabString();
        fIndex = i;
        fPretty.append(token);
        fFreshline = false;
        return true;
    }

    void parseUntilNewline() {
        while (fLength > fIndex) {
            if ('\n' == fInput[fIndex]) {
                fIndex++;
                this->newline();
                fInParseUntilNewline = false;
                break;
            }
            SkSL::String::appendf(&fPretty, "%c", fInput[fIndex++]);
            fInParseUntilNewline = true;
        }
    }

    // this code assumes it is not actually searching for a newline.  If you need to search for a
    // newline, then use the function above.  If you do search for a newline with this function
    // it will consume the entire string and the output will certainly not be prettified
    void parseUntil(const char* token) {
        while (fLength > fIndex) {
            // For embedded newlines,  this code will make sure to embed the newline in the
            // pretty string, increase the linecount, and tab out the next line to the appropriate
            // place
            if ('\n' == fInput[fIndex]) {
                this->newline();
                this->tabString();
                fIndex++;
            }
            if (this->hasToken(token)) {
                fInParseUntil = false;
                break;
            }
            fFreshline = false;
            SkSL::String::appendf(&fPretty, "%c", fInput[fIndex++]);
            fInParseUntil = true;
            fInParseUntilToken = token;
        }
    }

    // We only tab if on a newline, otherwise consider the line tabbed
    void tabString() {
        if (fFreshline) {
            for (int t = 0; t < fTabs; t++) {
                fPretty.append("\t");
            }
        }
    }

    // newline is really a request to add a newline, if we are on a fresh line there is no reason
    // to add another newline
    void newline() {
        if (!fFreshline) {
            fFreshline = true;
            fPretty.append("\n");
        }
    }

    bool fFreshline;
    int fTabs;
    size_t fIndex, fLength;
    const char* fInput;
    std::string fPretty;

    // Some helpers for parseUntil when we go over a string length
    bool fInParseUntilNewline;
    bool fInParseUntil;
    const char* fInParseUntilToken;
};

std::string PrettyPrint(const std::string& string) {
    GLSLPrettyPrint pp;
    return pp.prettify(string);
}

void VisitLineByLine(const std::string& text,
                     const std::function<void(int lineNumber, const char* lineText)>& visitFn) {
    SkTArray<SkString> lines;
    SkStrSplit(text.c_str(), "\n", kStrict_SkStrSplitMode, &lines);
    for (int i = 0; i < lines.count(); ++i) {
        visitFn(i + 1, lines[i].c_str());
    }
}

std::string BuildShaderErrorMessage(const char* shader, const char* errors) {
    std::string abortText{"Shader compilation error\n"
                          "------------------------\n"};
    VisitLineByLine(shader, [&](int lineNumber, const char* lineText) {
        SkSL::String::appendf(&abortText, "%4i\t%s\n", lineNumber, lineText);
    });
    SkSL::String::appendf(&abortText, "Errors:\n%s", errors);
    return abortText;
}

void PrintShaderBanner(SkSL::ProgramKind programKind) {
    const char* typeName = "Unknown";
    if (SkSL::ProgramConfig::IsVertex(programKind)) {
        typeName = "Vertex";
    } else if (SkSL::ProgramConfig::IsFragment(programKind)) {
        typeName = "Fragment";
    }
    SkDebugf("---- %s shader ----------------------------------------------------\n", typeName);
}

}  // namespace SkShaderUtils
