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

#include "bench/Benchmark.h"
#include "include/core/SkCanvas.h"
#include "include/core/SkPaint.h"
#include "include/core/SkPath.h"
#include "include/core/SkPathBuilder.h"
#include "include/private/SkTDArray.h"
#include "src/core/SkRandom.h"

/**
 * This is a conversion of samplecode/SampleChart.cpp into a bench. It sure would be nice to be able
 * to write one subclass that can be a GM, bench, and/or Sample.
 */

// Generates y values for the chart plots.
static void gen_data(SkScalar yAvg, SkScalar ySpread, int count,
                     SkRandom* random, SkTDArray<SkScalar>* dataPts) {
    dataPts->resize(count);
    for (int i = 0; i < count; ++i) {
        (*dataPts)[i] = random->nextRangeScalar(yAvg - (ySpread / 2.f),
                                                yAvg + (ySpread / 2.f));
    }
}

// Generates a path to stroke along the top of each plot and a fill path for the area below each
// plot. The fill path is bounded below by the bottomData plot points or a horizontal line at
// yBase if bottomData == nullptr.
// The plots are animated by rotating the data points by leftShift.
static void gen_paths(const SkTDArray<SkScalar>& topData,
                      const SkTDArray<SkScalar>* bottomData,
                      SkScalar yBase,
                      SkScalar xLeft, SkScalar xDelta,
                      int leftShift,
                      SkPath* plotOut, SkPath* fillOut) {
    SkPathBuilder plot, fill;
    plot.incReserve(topData.size());
    if (nullptr == bottomData) {
        fill.incReserve(topData.size() + 2);
    } else {
        fill.incReserve(2 * topData.size());
    }

    leftShift %= topData.size();
    SkScalar x = xLeft;

    // Account for the leftShift using two loops
    int shiftToEndCount = topData.size() - leftShift;
    plot.moveTo(x, topData[leftShift]);
    fill.moveTo(x, topData[leftShift]);

    for (int i = 1; i < shiftToEndCount; ++i) {
        plot.lineTo(x, topData[i + leftShift]);
        fill.lineTo(x, topData[i + leftShift]);
        x += xDelta;
    }

    for (int i = 0; i < leftShift; ++i) {
        plot.lineTo(x, topData[i]);
        fill.lineTo(x, topData[i]);
        x += xDelta;
    }

    if (bottomData) {
        SkASSERT(bottomData->size() == topData.size());
        // iterate backwards over the previous graph's data to generate the bottom of the filled
        // area (and account for leftShift).
        for (int i = 0; i < leftShift; ++i) {
            x -= xDelta;
            fill.lineTo(x, (*bottomData)[leftShift - 1 - i]);
        }
        for (int i = 0; i < shiftToEndCount; ++i) {
            x -= xDelta;
            fill.lineTo(x, (*bottomData)[bottomData->size() - 1 - i]);
        }
    } else {
        fill.lineTo(x - xDelta, yBase);
        fill.lineTo(xLeft, yBase);
    }

    *plotOut = plot.detach();
    *fillOut = fill.detach();
}

// A set of scrolling line plots with the area between each plot filled. Stresses out GPU path
// filling
class ChartBench : public Benchmark {
public:
    ChartBench(bool aa) {
        fShift = 0;
        fAA = aa;
        fSize.fWidth = -1;
        fSize.fHeight = -1;
    }

protected:
    const char* onGetName() override {
        if (fAA) {
            return "chart_aa";
        } else {
            return "chart_bw";
        }
    }

    void onDraw(int loops, SkCanvas* canvas) override {
        bool sizeChanged = false;
        if (canvas->getBaseLayerSize() != fSize) {
            fSize = canvas->getBaseLayerSize();
            sizeChanged = true;
        }

        SkScalar ySpread = SkIntToScalar(fSize.fHeight / 20);

        SkScalar height = SkIntToScalar(fSize.fHeight);
        if (sizeChanged) {
            int dataPointCount = std::max(fSize.fWidth / kPixelsPerTick + 1, 2);

            SkRandom random;
            for (int i = 0; i < kNumGraphs; ++i) {
                SkScalar y = (kNumGraphs - i) * (height - ySpread) / (kNumGraphs + 1);
                fData[i].reset();
                gen_data(y, ySpread, dataPointCount, &random, fData + i);
            }
        }

        SkRandom colorRand;
        SkColor colors[kNumGraphs];
        for (int i = 0; i < kNumGraphs; ++i) {
            colors[i] = colorRand.nextU() | 0xff000000;
        }

        for (int frame = 0; frame < loops; ++frame) {
            SkPath plotPath;
            SkPath fillPath;

            static const SkScalar kStrokeWidth = SkIntToScalar(2);
            SkPaint plotPaint;
            SkPaint fillPaint;
            plotPaint.setAntiAlias(fAA);
            plotPaint.setStyle(SkPaint::kStroke_Style);
            plotPaint.setStrokeWidth(kStrokeWidth);
            plotPaint.setStrokeCap(SkPaint::kRound_Cap);
            plotPaint.setStrokeJoin(SkPaint::kRound_Join);
            fillPaint.setAntiAlias(fAA);
            fillPaint.setStyle(SkPaint::kFill_Style);

            SkTDArray<SkScalar>* prevData = nullptr;
            for (int i = 0; i < kNumGraphs; ++i) {
                gen_paths(fData[i],
                          prevData,
                          height,
                          0,
                          SkIntToScalar(kPixelsPerTick),
                          fShift,
                          &plotPath,
                          &fillPath);

                // Make the fills partially transparent
                fillPaint.setColor((colors[i] & 0x00ffffff) | 0x80000000);
                canvas->drawPath(fillPath, fillPaint);

                plotPaint.setColor(colors[i]);
                canvas->drawPath(plotPath, plotPaint);

                prevData = fData + i;
            }

            fShift += kShiftPerFrame;
        }
    }

private:
    enum {
        kNumGraphs = 5,
        kPixelsPerTick = 3,
        kShiftPerFrame = 1,
    };
    int                 fShift;
    SkISize             fSize;
    SkTDArray<SkScalar> fData[kNumGraphs];
    bool                fAA;

    using INHERITED = Benchmark;
};

//////////////////////////////////////////////////////////////////////////////

DEF_BENCH( return new ChartBench(true); )
DEF_BENCH( return new ChartBench(false); )
