/*
 * Copyright 2018 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 "rive/math/vec2d.hpp"
#include "rive/math/bezier_utils.hpp"
#include "rive/math/math_types.hpp"
#include "common/rand.hpp"

using namespace rivegm;
using namespace rive;
using namespace rive::math;

// Atomic mode uses 6:11 fixed point and clockwiseAtomic uses 7:8, so the
// winding number breaks if a shape has more than +/-32 [ == +/-2^(6-1)] levels
// of self overlap at any point.
constexpr static float SLICE_LENGTH = 2;

// Slices paths into sliver-size contours shaped like ice cream cones.
class MandolineSlicer
{
public:
  MandolineSlicer(Vec2D anchorPt, Vec2D p0) { this->reset(anchorPt, p0); }

  void reset(Vec2D anchorPt, Vec2D p0)
  {
    fPath = Path();
    fPath->fillRule(FillRule::evenOdd);
    fAnchorPt = anchorPt;
    fLastPt = p0;
  }

  void sliceLine(Vec2D pt)
  {
    if ((pt - fLastPt).length() < SLICE_LENGTH)
    {
      fPath->moveTo(fAnchorPt.x, fAnchorPt.y);
      fPath->lineTo(fLastPt.x, fLastPt.y);
      fPath->lineTo(pt.x, pt.y);
      fPath->close();
      fLastPt = pt;
      return;
    }
    float T = .5f;
    if (0 == T)
    {
      return;
    }
    Vec2D midpt = fLastPt * (1 - T) + pt * T;
    this->sliceLine(midpt);
    this->sliceLine(pt);
  }

  void sliceQuadratic(Vec2D p1, Vec2D p2)
  {
    if ((p2 - fLastPt).length() < SLICE_LENGTH)
    {
      fPath->moveTo(fAnchorPt.x, fAnchorPt.y);
      fPath->lineTo(fLastPt.x, fLastPt.y);
      fPath->cubicTo(
          fLastPt.x + (p1.x - fLastPt.x) * (2 / 3.f),
          fLastPt.y + (p1.y - fLastPt.y) * (2 / 3.f),
          p2.x + (p1.x - p2.x) * (2 / 3.f),
          p2.y + (p1.y - p2.y) * (2 / 3.f),
          p2.x,
          p2.y);
      fPath->close();
      fLastPt = p2;
      return;
    }
    Vec2D P[4] =
        {fLastPt,
         Vec2D::lerp(fLastPt, p1, 2 / 3.f),
         Vec2D::lerp(p2, p1, 2 / 3.f),
         p2},
          PP[7];
    math::chopCubicAt(P, PP, .5f);

    this->sliceCubic(PP[1], PP[2], PP[3]);
    this->sliceCubic(PP[4], PP[5], PP[6]);
  }

  void sliceCubic(Vec2D p1, Vec2D p2, Vec2D p3)
  {
    if ((p3 - fLastPt).length() < SLICE_LENGTH)
    {
      fPath->moveTo(fAnchorPt.x, fAnchorPt.y);
      fPath->lineTo(fLastPt.x, fLastPt.y);
      fPath->cubicTo(p1.x, p1.y, p2.x, p2.y, p3.x, p3.y);
      fPath->close();
      fLastPt = p3;
      return;
    }
    Vec2D P[4] = {fLastPt, p1, p2, p3}, PP[7];
    math::chopCubicAt(P, PP, .5f);
    this->sliceCubic(PP[1], PP[2], PP[3]);
    this->sliceCubic(PP[4], PP[5], PP[6]);
  }

  rive::RenderPath* path() const { return fPath; }

private:
  Rand fRand;
  Path fPath;
  Vec2D fAnchorPt;
  Vec2D fLastPt;
};

class MandolineGM : public GM
{
public:
  MandolineGM() : GM(560, 475) {}

protected:
  ColorInt clearColor() const override { return 0xff000000; }

  void onDraw(Renderer* renderer) override
  {
    Paint paint;
    paint->color(0xc0c0c0c0);

    MandolineSlicer mandoline({0, -500}, {41, 43});
    mandoline.sliceCubic({5, 277}, {381, -74}, {243, 162});
    mandoline.sliceLine({41, 43});
    renderer->drawPath(mandoline.path(), paint);

    mandoline.reset({700, 700}, {357.049988f, 446.049988f});
    mandoline.sliceCubic(
        {472.750000f, -71.950012f},
        {639.750000f, 531.950012f},
        {309.049988f, 347.950012f});
    mandoline.sliceLine({309.049988f, 419});
    mandoline.sliceLine({357.049988f, 446.049988f});
    renderer->drawPath(mandoline.path(), paint);

    renderer->save();
    renderer->translate(421, 105);
    renderer->scale(100, 81);
    mandoline.reset(
        {0, 500},
        {-cosf(degrees_to_radians(-60)), sinf(degrees_to_radians(-60))});
    mandoline.sliceQuadratic(
        {-2, 0},
        {-cosf(degrees_to_radians(60)), sinf(degrees_to_radians(60))});
    mandoline.sliceQuadratic(
        {-cosf(degrees_to_radians(120)) * 2, sinf(degrees_to_radians(120)) * 2},
        {1, 0});
    mandoline.sliceLine({0, 0});
    mandoline.sliceLine(
        {-cosf(degrees_to_radians(-60)), sinf(degrees_to_radians(-60))});
    renderer->drawPath(mandoline.path(), paint);
    renderer->restore();

    renderer->save();
    renderer->translate(150, 300);
    renderer->scale(75, 75);
    mandoline.reset({0, 0}, {1, 0});
    constexpr int nquads = 5;
    for (int i = 0; i < nquads; ++i)
    {
      float theta1 = 2 * PI / nquads * (i + .5f);
      float theta2 = 2 * PI / nquads * (i + 1);
      mandoline.sliceQuadratic(
          {cosf(theta1) * 2, sinf(theta1) * 2},
          {cosf(theta2), sinf(theta2)});
    }
    renderer->drawPath(mandoline.path(), paint);
    renderer->restore();
  }
};

GMREGISTER(mandoline, return new MandolineGM;)
