/*
 * Copyright 2014 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/SkClipOp.h"
#include "include/core/SkColor.h"
#include "include/core/SkFont.h"
#include "include/core/SkPaint.h"
#include "include/core/SkPathBuilder.h"
#include "include/core/SkRect.h"
#include "include/core/SkScalar.h"
#include "include/core/SkSize.h"
#include "include/core/SkString.h"
#include "include/core/SkTypeface.h"
#include "include/core/SkTypes.h"
#include "tools/ToolUtils.h"

#include <utility>

namespace skiagm {

constexpr SkColor gPathColor = SK_ColorYELLOW;

class ComplexClip3GM : public GM {
public:
    ComplexClip3GM(bool doSimpleClipFirst)
        : fDoSimpleClipFirst(doSimpleClipFirst) {
        this->setBGColor(0xFFDDDDDD);
    }

protected:

    SkString onShortName() override {
        SkString str;
        str.printf("complexclip3_%s", fDoSimpleClipFirst ? "simple" : "complex");
        return str;
    }

    SkISize onISize() override { return SkISize::Make(400, 950); }

    void onDraw(SkCanvas* canvas) override {
        SkPath clipSimple = SkPath::Circle(70, 50, 20);

        SkRect r1 = { 10, 20, 70, 80 };
        SkPath clipComplex = SkPathBuilder().moveTo(40,  50)
                                            .arcTo(r1, 30, 300, false)
                                            .close()
                                            .detach();

        SkPath* firstClip = &clipSimple;
        SkPath* secondClip = &clipComplex;
        if (!fDoSimpleClipFirst) {
            std::swap(firstClip, secondClip);
        }

        SkPaint paint;
        paint.setAntiAlias(true);

        SkFont font(ToolUtils::create_portable_typeface(), 20);

        constexpr struct {
            SkClipOp    fOp;
            const char* fName;
        } gOps[] = {
            {SkClipOp::kIntersect,         "I"},
            {SkClipOp::kDifference,        "D" },
        };

        canvas->translate(SkIntToScalar(20), SkIntToScalar(20));
        canvas->scale(3 * SK_Scalar1 / 4, 3 * SK_Scalar1 / 4);

        SkPaint pathPaint;
        pathPaint.setAntiAlias(true);
        pathPaint.setColor(gPathColor);

        for (int invA = 0; invA < 2; ++invA) {
            for (int aaBits = 0; aaBits < 4; ++aaBits) {
                canvas->save();
                for (size_t op = 0; op < std::size(gOps); ++op) {
                    for (int invB = 0; invB < 2; ++invB) {
                        bool doAAA = SkToBool(aaBits & 1);
                        bool doAAB = SkToBool(aaBits & 2);
                        bool doInvA = SkToBool(invA);
                        bool doInvB = SkToBool(invB);
                        canvas->save();
                        // set clip
                        firstClip->setFillType(doInvA ? SkPathFillType::kInverseEvenOdd :
                                               SkPathFillType::kEvenOdd);
                        secondClip->setFillType(doInvB ? SkPathFillType::kInverseEvenOdd :
                                                SkPathFillType::kEvenOdd);
                        canvas->clipPath(*firstClip, doAAA);
                        canvas->clipPath(*secondClip, gOps[op].fOp, doAAB);

                        // draw rect clipped
                        SkRect r = { 0, 0, 100, 100 };
                        canvas->drawRect(r, pathPaint);
                        canvas->restore();


                        SkScalar txtX = SkIntToScalar(10);
                        paint.setColor(SK_ColorBLACK);
                        SkString str;
                        str.printf("%s%s %s %s%s", doAAA ? "A" : "B",
                                                   doInvA ? "I" : "N",
                                                   gOps[op].fName,
                                                   doAAB ? "A" : "B",
                                                   doInvB ? "I" : "N");

                        canvas->drawString(str.c_str(), txtX, SkIntToScalar(130), font, paint);
                        if (doInvB) {
                            canvas->translate(SkIntToScalar(150),0);
                        } else {
                            canvas->translate(SkIntToScalar(120),0);
                        }
                    }
                }
                canvas->restore();
                canvas->translate(0, SkIntToScalar(150));
            }
        }
    }

private:
    bool fDoSimpleClipFirst;

    using INHERITED = GM;
};

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

// Simple clip first
DEF_GM( return new ComplexClip3GM(true); )
// Complex clip first
DEF_GM( return new ComplexClip3GM(false); )
}  // namespace skiagm
