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

#include "gm.hpp"
#include "gmutils.hpp"
#include "rive/renderer.hpp"
#include "common/rand.hpp"

using namespace rivegm;
using namespace rive;

namespace
{

class SkDoOnce
{
public:
  SkDoOnce() { fDidOnce = false; }

  bool alreadyDone() const { return fDidOnce; }
  void accomplished()
  {
    assert(!fDidOnce);
    fDidOnce = true;
  }

private:
  bool fDidOnce;
};

class ConvexPathsGM : public GM
{
public:
  ConvexPathsGM() : GM(1200, 1100) {}

private:
  SkDoOnce fOnce;

  void makePaths()
  {

    if (fOnce.alreadyDone())
    {
      return;
    }
    fOnce.accomplished();

    PathBuilder b;
    fPaths.push_back(
        b.moveTo(0, 0).quadTo(50, 100, 0, 100).lineTo(0, 0).detach());

    fPaths.push_back(
        b.moveTo(0, 50).quadTo(50, 0, 100, 50).quadTo(50, 100, 0, 50).detach());

    fPaths.push_back(
        PathBuilder::Rect({0, 0, 100, 100}, rivegm::PathDirection::cw));
    fPaths.push_back(
        PathBuilder::Rect({0, 0, 100, 100}, rivegm::PathDirection::ccw));
    fPaths.push_back(
        PathBuilder::Oval({0, 0, 100, 100}, rivegm::PathDirection::cw));
    fPaths.push_back(
        PathBuilder::Oval({0, 0, 50, 100}, rivegm::PathDirection::cw));
    fPaths.push_back(
        PathBuilder::Oval({0, 0, 100, 5}, rivegm::PathDirection::ccw));
    fPaths.push_back(
        PathBuilder::Oval({0, 0, 1, 100}, rivegm::PathDirection::ccw));
    fPaths.push_back(PathBuilder::RRect({0, 0, 100, 100}, 40, 20));

    // large number of points
    constexpr static int kLength = 100;
    constexpr static int kPtsPerSide = (1 << 12);
    b.moveTo(0, 0);
    for (int i = 1; i < kPtsPerSide; ++i)
    { // skip the first point due to moveTo.
      b.lineTo(kLength * (float)(i) / kPtsPerSide, 0);
    }
    for (int i = 0; i < kPtsPerSide; ++i)
    {
      b.lineTo(kLength, kLength * (float)(i) / kPtsPerSide);
    }
    for (int i = kPtsPerSide; i > 0; --i)
    {
      b.lineTo(kLength * (float)(i) / kPtsPerSide, kLength);
    }
    for (int i = kPtsPerSide; i > 0; --i)
    {
      b.lineTo(0, kLength * (float)(i) / kPtsPerSide);
    }
    fPaths.push_back(b.detach());

    // shallow diagonals
    fPaths.push_back(
        b.moveTo(0, 0).lineTo(100, 1).lineTo(98, 100).lineTo(3, 96).detach());
    fPaths.push_back(PathBuilder::Oval({0, 0, 50, 100}));

    // cubics
    fPaths.push_back(b.cubicTo(1, 1, 10, 90, 0, 100).detach());
    fPaths.push_back(b.cubicTo(100, 50, 20, 100, 0, 0).detach());

    // path that has a cubic with a repeated first control point and
    // a repeated last control point.
    fPaths.push_back(b.moveTo(10, 10)
                         .cubicTo(10, 10, 10, 0, 20, 0)
                         .lineTo(40, 0)
                         .cubicTo(40, 0, 50, 0, 50, 10)
                         .detach());

    // path that has two cubics with repeated middle control points.
    fPaths.push_back(b.moveTo(10, 10)
                         .cubicTo(10, 0, 10, 0, 20, 0)
                         .lineTo(40, 0)
                         .cubicTo(50, 0, 50, 0, 50, 10)
                         .detach());

    // cubic where last three points are almost a line
    fPaths.push_back(b.moveTo(0, 228.0f / 8)
                         .cubicTo(
                             628.0f / 8,
                             82.0f / 8,
                             1255.0f / 8,
                             141.0f / 8,
                             1883.0f / 8,
                             202.0f / 8)
                         .detach());

    // flat cubic where the at end point tangents both point outward.
    fPaths.push_back(b.moveTo(10, 0).cubicTo(0, 1, 30, 1, 20, 0).detach());

    // flat cubic where initial tangent is in, end tangent out
    fPaths.push_back(b.moveTo(0, 0).cubicTo(10, 1, 30, 1, 20, 0).detach());

    // flat cubic where initial tangent is out, end tangent in
    fPaths.push_back(b.moveTo(10, 0).cubicTo(0, 1, 20, 1, 30, 0).detach());

    // triangle where one edge is a degenerate quad
    fPaths.push_back(b.moveTo(8.59375f, 45)
                         .quadTo(16.9921875f, 45, 31.25f, 45)
                         .lineTo(100, 100)
                         .lineTo(8.59375f, 45)
                         .detach());

    // triangle where one edge is a quad with a repeated point
    fPaths.push_back(
        b.moveTo(0, 25).lineTo(50, 0).quadTo(50, 50, 50, 50).detach());

    // triangle where one edge is a cubic with a 2x repeated point
    fPaths.push_back(
        b.moveTo(0, 25).lineTo(50, 0).cubicTo(50, 0, 50, 50, 50, 50).detach());

    // triangle where one edge is a quad with a nearly repeated point
    fPaths.push_back(
        b.moveTo(0, 25).lineTo(50, 0).quadTo(50, 49.95f, 50, 50).detach());

    // triangle where one edge is a cubic with a 3x nearly repeated point
    fPaths.push_back(b.moveTo(0, 25)
                         .lineTo(50, 0)
                         .cubicTo(50, 49.95f, 50, 49.97f, 50, 50)
                         .detach());

    // triangle where there is a point degenerate cubic at one corner
    fPaths.push_back(b.moveTo(0, 25)
                         .lineTo(50, 0)
                         .lineTo(50, 50)
                         .cubicTo(50, 50, 50, 50, 50, 50)
                         .detach());

    // point line
    fPaths.push_back(b.moveTo(50, 50).lineTo(50, 50).detach());

    // point quad
    fPaths.push_back(b.moveTo(50, 50).quadTo(50, 50, 50, 50).detach());

    // point cubic
    fPaths.push_back(b.moveTo(50, 50).cubicTo(50, 50, 50, 50, 50, 50).detach());

    // moveTo only paths
    fPaths.push_back(b.moveTo(0, 0)
                         .moveTo(0, 0)
                         .moveTo(1, 1)
                         .moveTo(1, 1)
                         .moveTo(10, 10)
                         .detach());

    fPaths.push_back(b.moveTo(0, 0).moveTo(0, 0).detach());

    // line degenerate
    fPaths.push_back(b.lineTo(100, 100).detach());
    fPaths.push_back(b.quadTo(100, 100, 0, 0).detach());
    fPaths.push_back(b.quadTo(100, 100, 50, 50).detach());
    fPaths.push_back(b.quadTo(50, 50, 100, 100).detach());
    fPaths.push_back(b.cubicTo(0, 0, 0, 0, 100, 100).detach());

    // skbug.com/8928
    fPaths.push_back(Path());
    fPaths.back()->addRenderPath(
        b.moveTo(16.875f, 192.594f)
            .cubicTo(45.625f, 192.594f, 74.375f, 192.594f, 103.125f, 192.594f)
            .cubicTo(88.75f, 167.708f, 74.375f, 142.823f, 60, 117.938f)
            .cubicTo(45.625f, 142.823f, 31.25f, 167.708f, 16.875f, 192.594f)
            .close()
            .detach(),
        rive::Mat2D(0.1f, 0, 0, 0.115207f, -1, -2.64977f));

    // small circle. This is listed last so that it has device coords far
    // from the origin (small area relative to x,y values).
    fPaths.push_back(PathBuilder::Oval(
        {-1.2f, -1.2f, 1.2f, 1.2f},
        rivegm::PathDirection::ccw));
  }

  ColorInt clearColor() const override { return 0xFF000000; }

  void onDraw(Renderer* renderer) override
  {
    this->makePaths();

    Paint paint;
    Rand rand;
    renderer->translate(20, 20);

    // As we've added more paths this has gotten pretty big. Scale the whole
    // thing down.
    renderer->scale(2.0f / 3, 2.0f / 3);

    for (size_t i = 0; i < fPaths.size(); ++i)
    {
      renderer->save();
      // position the path, and make it at off-integer coords.
      renderer->translate(
          200.0f * (i % 5) + 1.0f / 10,
          200.0f * (int)(i / 5) + 9.0f / 10);
      ColorInt color = rand.u32();
      color |= 0xff000000;
      paint->color(color);
#if 0 // This hitting on 32bit Linux builds for some paths. Temporarily
      // disabling while it is debugged.
            SkASSERT(fPaths[i].isConvex());
#endif
      renderer->drawPath(fPaths[i], paint);
      renderer->restore();
    }
  }

  std::vector<Path> fPaths;
};
} // namespace

GMREGISTER(convexpaths, return new ConvexPathsGM;)
