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

#include "Benchmark.h"
#include "SkData.h"
#include "SkJSON.h"
#include "SkStream.h"

#if defined(SK_BUILD_FOR_ANDROID)
static constexpr const char* kBenchFile = "/data/local/tmp/bench.json";
#else
static constexpr const char* kBenchFile = "/tmp/bench.json";
#endif

class JsonBench : public Benchmark {
public:

protected:
    const char* onGetName() override { return "json_skjson"; }

    bool isSuitableFor(Backend backend) override { return backend == kNonRendering_Backend; }

    void onPerCanvasPreDraw(SkCanvas*) override {
        fData = SkData::MakeFromFileName(kBenchFile);
        if (!fData) {
            SkDebugf("!! Could not open bench file: %s\n", kBenchFile);
        }
    }

    void onPerCanvasPostDraw(SkCanvas*) override {
        fData = nullptr;
    }

    void onDraw(int loops, SkCanvas*) override {
        if (!fData) return;

        for (int i = 0; i < loops; i++) {
            skjson::DOM dom(static_cast<const char*>(fData->data()), fData->size());
            if (dom.root().is<skjson::NullValue>()) {
                SkDebugf("!! Parsing failed.\n");
                return;
            }
        }
    }

private:
    sk_sp<SkData> fData;

    using INHERITED = Benchmark;
};

DEF_BENCH( return new JsonBench; )

#if (0)

#include "rapidjson/document.h"

class RapidJsonBench : public Benchmark {
public:

protected:
    const char* onGetName() override { return "json_rapidjson"; }

    bool isSuitableFor(Backend backend) override { return backend == kNonRendering_Backend; }

    void onPerCanvasPreDraw(SkCanvas*) override {
        if (auto stream = SkStream::MakeFromFile(kBenchFile)) {
            SkASSERT(stream->hasLength());
            fCStringData = SkData::MakeUninitialized(stream->getLength() + 1);
            auto* data8 = reinterpret_cast<uint8_t*>(fCStringData->writable_data());
            SkAssertResult(stream->read(data8, stream->getLength()) == stream->getLength());
            data8[stream->getLength()] = '\0';

        } else {
            SkDebugf("!! Could not open bench file: %s\n", kBenchFile);
        }
    }

    void onPerCanvasPostDraw(SkCanvas*) override {
        fCStringData = nullptr;
    }

    void onDraw(int loops, SkCanvas*) override {
        if (!fCStringData) return;

        for (int i = 0; i < loops; i++) {
            rapidjson::Document doc;
            doc.Parse(static_cast<const char*>(fCStringData->data()));
            if (doc.HasParseError()) {
                SkDebugf("!! Parsing failed.\n");
                return;
            }
        }
    }

private:
    sk_sp<SkData> fCStringData;

    using INHERITED = Benchmark;
};

DEF_BENCH( return new RapidJsonBench; )

#endif

#if (0)

#include "pjson.h"

class PJsonBench : public Benchmark {
public:

protected:
    const char* onGetName() override { return "json_pjson"; }

    bool isSuitableFor(Backend backend) override { return backend == kNonRendering_Backend; }

    void onPerCanvasPreDraw(SkCanvas*) override {
        if (auto stream = SkStream::MakeFromFile(kBenchFile)) {
            SkASSERT(stream->hasLength());
            fCStringData = SkData::MakeUninitialized(stream->getLength() + 1);
            auto* data8 = reinterpret_cast<uint8_t*>(fCStringData->writable_data());
            SkAssertResult(stream->read(data8, stream->getLength()) == stream->getLength());
            data8[stream->getLength()] = '\0';

        } else {
            SkDebugf("!! Could not open bench file: %s\n", kBenchFile);
        }
    }

    void onPerCanvasPostDraw(SkCanvas*) override {
        fCStringData = nullptr;
    }

    void onDraw(int loops, SkCanvas*) override {
        if (!fCStringData) return;

        for (int i = 0; i < loops; i++) {
            // Copy needed for in-place operation.
            auto data = SkData::MakeWithCopy(fCStringData->data(), fCStringData->size());
            pjson::document doc;
            if (!doc.deserialize_in_place(static_cast<char*>(data->writable_data()))) {
                SkDebugf("!! Parsing failed.\n");
                return;
            }
        }
    }

private:
    sk_sp<SkData> fCStringData;

    using INHERITED = Benchmark;
};

DEF_BENCH( return new PJsonBench; )

#endif