/*
 * 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 "gm/gm.h"
#include "include/core/SkCanvas.h"
#include "include/core/SkColor.h"
#include "include/core/SkPaint.h"
#include "include/core/SkPath.h"
#include "include/core/SkPoint.h"
#include "include/core/SkScalar.h"
#include "include/core/SkSize.h"
#include "include/core/SkString.h"
#include "include/core/SkTypes.h"
#include "include/utils/SkRandom.h"
#include "src/core/SkGeometry.h"

#include <math.h>

namespace skiagm {

// Slices paths into sliver-size contours shaped like ice cream cones.
class MandolineSlicer {
public:
    inline static constexpr int kDefaultSubdivisions = 10;

    MandolineSlicer(SkPoint anchorPt) {
        fPath.setFillType(SkPathFillType::kEvenOdd);
        fPath.setIsVolatile(true);
        this->reset(anchorPt);
    }

    void reset(SkPoint anchorPt) {
        fPath.reset();
        fLastPt = fAnchorPt = anchorPt;
    }

    void sliceLine(SkPoint pt, int numSubdivisions = kDefaultSubdivisions) {
        if (numSubdivisions <= 0) {
            fPath.moveTo(fAnchorPt);
            fPath.lineTo(fLastPt);
            fPath.lineTo(pt);
            fPath.close();
            fLastPt = pt;
            return;
        }
        float T = this->chooseChopT(numSubdivisions);
        if (0 == T) {
            return;
        }
        SkPoint midpt = fLastPt * (1 - T) + pt * T;
        this->sliceLine(midpt, numSubdivisions - 1);
        this->sliceLine(pt, numSubdivisions - 1);
    }

    void sliceQuadratic(SkPoint p1, SkPoint p2, int numSubdivisions = kDefaultSubdivisions) {
        if (numSubdivisions <= 0) {
            fPath.moveTo(fAnchorPt);
            fPath.lineTo(fLastPt);
            fPath.quadTo(p1, p2);
            fPath.close();
            fLastPt = p2;
            return;
        }
        float T = this->chooseChopT(numSubdivisions);
        if (0 == T) {
            return;
        }
        SkPoint P[3] = {fLastPt, p1, p2}, PP[5];
        SkChopQuadAt(P, PP, T);
        this->sliceQuadratic(PP[1], PP[2], numSubdivisions - 1);
        this->sliceQuadratic(PP[3], PP[4], numSubdivisions - 1);
    }

    void sliceCubic(SkPoint p1, SkPoint p2, SkPoint p3,
                    int numSubdivisions = kDefaultSubdivisions) {
        if (numSubdivisions <= 0) {
            fPath.moveTo(fAnchorPt);
            fPath.lineTo(fLastPt);
            fPath.cubicTo(p1, p2, p3);
            fPath.close();
            fLastPt = p3;
            return;
        }
        float T = this->chooseChopT(numSubdivisions);
        if (0 == T) {
            return;
        }
        SkPoint P[4] = {fLastPt, p1, p2, p3}, PP[7];
        SkChopCubicAt(P, PP, T);
        this->sliceCubic(PP[1], PP[2], PP[3], numSubdivisions - 1);
        this->sliceCubic(PP[4], PP[5], PP[6], numSubdivisions - 1);
    }

    void sliceConic(SkPoint p1, SkPoint p2, float w, int numSubdivisions = kDefaultSubdivisions) {
        if (numSubdivisions <= 0) {
            fPath.moveTo(fAnchorPt);
            fPath.lineTo(fLastPt);
            fPath.conicTo(p1, p2, w);
            fPath.close();
            fLastPt = p2;
            return;
        }
        float T = this->chooseChopT(numSubdivisions);
        if (0 == T) {
            return;
        }
        SkConic conic(fLastPt, p1, p2, w), halves[2];
        if (!conic.chopAt(T, halves)) {
            SK_ABORT("SkConic::chopAt failed");
        }
        this->sliceConic(halves[0].fPts[1], halves[0].fPts[2], halves[0].fW, numSubdivisions - 1);
        this->sliceConic(halves[1].fPts[1], halves[1].fPts[2], halves[1].fW, numSubdivisions - 1);
    }

    const SkPath& path() const { return fPath; }

private:
    float chooseChopT(int numSubdivisions) {
        SkASSERT(numSubdivisions > 0);
        if (numSubdivisions > 1) {
            return .5f;
        }
        float T = (0 == fRand.nextU() % 10) ? 0 : scalbnf(1, -(int)fRand.nextRangeU(10, 149));
        SkASSERT(T >= 0 && T < 1);
        return T;
    }

    SkRandom fRand;
    SkPath fPath;
    SkPoint fAnchorPt;
    SkPoint fLastPt;
};

class SliverPathsGM : public GM {
public:
    SliverPathsGM() {
        this->setBGColor(SK_ColorBLACK);
    }

protected:
    SkString onShortName() override {
        return SkString("mandoline");
    }

    SkISize onISize() override {
        return SkISize::Make(560, 475);
    }

    void onDraw(SkCanvas* canvas) override {
        SkPaint paint;
        paint.setColor(SK_ColorWHITE);
        paint.setAntiAlias(true);

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

        mandoline.reset({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});
        canvas->drawPath(mandoline.path(), paint);

        canvas->save();
        canvas->translate(421, 105);
        canvas->scale(100, 81);
        mandoline.reset({-cosf(SkDegreesToRadians(-60)), sinf(SkDegreesToRadians(-60))});
        mandoline.sliceConic({-2, 0},
                             {-cosf(SkDegreesToRadians(60)), sinf(SkDegreesToRadians(60))}, .5f);
        mandoline.sliceConic({-cosf(SkDegreesToRadians(120))*2, sinf(SkDegreesToRadians(120))*2},
                             {1, 0}, .5f);
        mandoline.sliceLine({0, 0});
        mandoline.sliceLine({-cosf(SkDegreesToRadians(-60)), sinf(SkDegreesToRadians(-60))});
        canvas->drawPath(mandoline.path(), paint);
        canvas->restore();

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

DEF_GM(return new SliverPathsGM;)

}  // namespace skiagm
