/*
 *   Copyright (c) 2022 Project CHIP Authors
 *   All rights reserved.
 *
 *   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.
 *
 */

#pragma once

#include "../common/CustomStringPrefix.h"

#include <json/json.h>
#include <lib/core/Optional.h>

#include <memory>
#include <sstream>
#include <string>
#include <vector>

class JsonParser
{
public:
    // Returns whether the parse succeeded.
    static bool ParseComplexArgument(const char * label, const char * json, Json::Value & value)
    {
        return Parse(label, json, /* strictRoot = */ true, value);
    }

    // Returns whether the parse succeeded.
    static bool ParseCustomArgument(const char * label, const char * json, Json::Value & value)
    {
        return Parse(label, json, /* strictRoot = */ false, value);
    }

private:
    static bool Parse(const char * label, const char * json, bool strictRoot, Json::Value & value)
    {
        Json::CharReaderBuilder readerBuilder;
        readerBuilder.settings_["strictRoot"]        = strictRoot;
        readerBuilder.settings_["allowSingleQuotes"] = true;
        readerBuilder.settings_["failIfExtra"]       = true;
        readerBuilder.settings_["rejectDupKeys"]     = true;

        auto reader = std::unique_ptr<Json::CharReader>(readerBuilder.newCharReader());
        std::string errors;
        if (reader->parse(json, json + strlen(json), &value, &errors))
        {
            return true;
        }

        // The CharReader API allows us to set failIfExtra, unlike Reader, but does
        // not allow us to get structured errors.  We get to try to manually undo
        // the work it did to create a string from the structured errors it had.
        ChipLogError(chipTool, "Error parsing JSON for %s:", label);

        // For each error "errors" has the following:
        //
        // 1) A line starting with "* " that has line/column info
        // 2) A line with the error message.
        // 3) An optional line with some extra info.
        //
        // We keep track of the last error column, in case the error message
        // reporting needs it.
        std::istringstream stream(errors);
        std::string error;
        chip::Optional<unsigned> errorColumn;
        while (getline(stream, error))
        {
            if (error.rfind("* ", 0) == 0)
            {
                // Flush out any pending error location.
                LogErrorLocation(errorColumn, json);

                // The format of this line is:
                //
                // * Line N, Column M
                //
                // Unfortunately it does not indicate end of error, so we can only
                // show its start.
                unsigned errorLine; // ignored in practice
                if (sscanf(error.c_str(), "* Line %u, Column %u", &errorLine, &errorColumn.Emplace()) != 2)
                {
                    ChipLogError(chipTool, "Unexpected location string: %s\n", error.c_str());
                    // We don't know how to make sense of this thing anymore.
                    break;
                }
                if (errorColumn.Value() == 0)
                {
                    ChipLogError(chipTool, "Expected error column to be at least 1");
                    // We don't know how to make sense of this thing anymore.
                    break;
                }
                // We are using our column numbers as offsets, so want them to be
                // 0-based.
                --errorColumn.Value();
            }
            else
            {
                ChipLogError(chipTool, "  %s", error.c_str());
                if (error == "  Missing ',' or '}' in object declaration" && errorColumn.HasValue() && errorColumn.Value() > 0 &&
                    json[errorColumn.Value() - 1] == '0' && (json[errorColumn.Value()] == 'x' || json[errorColumn.Value()] == 'X'))
                {
                    // Log the error location marker before showing the NOTE
                    // message.
                    LogErrorLocation(errorColumn, json);
                    ChipLogError(chipTool,
                                 "NOTE: JSON does not allow hex syntax beginning with 0x for numbers.  Try putting the hex number "
                                 "in quotes (like {\"name\": \"0x100\"}).");
                }
            }
        }

        // Write out the marker for our last error.
        LogErrorLocation(errorColumn, json);

        return false;
    }

private:
    static void LogErrorLocation(chip::Optional<unsigned> & errorColumn, const char * json)
    {
#if CHIP_ERROR_LOGGING
        if (!errorColumn.HasValue())
        {
            return;
        }

        const char * sourceText = json;
        unsigned error_start    = errorColumn.Value();
        // The whole JSON string might be too long to fit in our log
        // messages.  Just include 30 chars before the error.
        constexpr ptrdiff_t kMaxContext = 30;
        std::string errorMarker;
        if (error_start > kMaxContext)
        {
            sourceText += (error_start - kMaxContext);
            error_start = kMaxContext;
            ChipLogError(chipTool, "... %s", sourceText);
            // Add markers corresponding to the "... " above.
            errorMarker += "----";
        }
        else
        {
            ChipLogError(chipTool, "%s", sourceText);
        }
        for (unsigned i = 0; i < error_start; ++i)
        {
            errorMarker += "-";
        }
        errorMarker += "^";
        ChipLogError(chipTool, "%s", errorMarker.c_str());
        errorColumn.ClearValue();
#endif // CHIP_ERROR_LOGGING
    }
};
