// The increased timeout is especially needed with larger binaries
// like in the debug/gpu build
jasmine.DEFAULT_TIMEOUT_INTERVAL = 20000;

describe('CanvasKit\'s Path Behavior', function() {
    // Note, don't try to print the CanvasKit object - it can cause Karma/Jasmine to lock up.
    var CanvasKit = null;
    const LoadCanvasKit = new Promise(function(resolve, reject) {
        if (CanvasKit) {
            resolve();
        } else {
            CanvasKitInit({
                locateFile: (file) => '/canvaskit/'+file,
            }).ready().then((_CanvasKit) => {
                CanvasKit = _CanvasKit;
                resolve();
            });
        }
    });

    let container = document.createElement('div');
    document.body.appendChild(container);
    const CANVAS_WIDTH = 600;
    const CANVAS_HEIGHT = 600;

    beforeEach(function() {
        container.innerHTML = `
            <canvas width=600 height=600 id=test></canvas>
            <canvas width=600 height=600 id=report></canvas>`;
    });

    afterEach(function() {
        container.innerHTML = '';
    });

    function reportSurface(surface, testname, done) {
        // In docker, the webgl canvas is blank, but the surface has the pixel
        // data. So, we copy it out and draw it to a normal canvas to take a picture.
        // To be consistent across CPU and GPU, we just do it for all configurations
        // (even though the CPU canvas shows up after flush just fine).
        let pixels = surface.getCanvas().readPixels(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT);
        pixels = new Uint8ClampedArray(pixels.buffer);
        var imageData = new ImageData(pixels, CANVAS_WIDTH, CANVAS_HEIGHT);

        let reportingCanvas =  document.getElementById('report');
        reportingCanvas.getContext('2d').putImageData(imageData, 0, 0);
        reportCanvas(reportingCanvas, testname).then(() => {
            done();
        }).catch(reportError(done));
    }

    it('can draw a path', function(done) {
        LoadCanvasKit.then(catchException(done, () => {
            // This is taken from example.html
            const surface = CanvasKit.MakeCanvasSurface('test');
            expect(surface).toBeTruthy('Could not make surface')
            if (!surface) {
                done();
                return;
            }
            const canvas = surface.getCanvas();
            const paint = new CanvasKit.SkPaint();
            paint.setStrokeWidth(1.0);
            paint.setAntiAlias(true);
            paint.setColor(CanvasKit.Color(0, 0, 0, 1.0));
            paint.setStyle(CanvasKit.PaintStyle.Stroke);

            const path = new CanvasKit.SkPath();
            path.moveTo(20, 5);
            path.lineTo(30, 20);
            path.lineTo(40, 10);
            path.lineTo(50, 20);
            path.lineTo(60, 0);
            path.lineTo(20, 5);

            path.moveTo(20, 80);
            path.cubicTo(90, 10, 160, 150, 190, 10);

            path.moveTo(36, 148);
            path.quadTo(66, 188, 120, 136);
            path.lineTo(36, 148);

            path.moveTo(150, 180);
            path.arcTo(150, 100, 50, 200, 20);
            path.lineTo(160, 160);

            path.moveTo(20, 120);
            path.lineTo(20, 120);

            path.transform([2, 0, 0,
                            0, 2, 0,
                            0, 0, 1 ])

            canvas.drawPath(path, paint);

            let rrect = new CanvasKit.SkPath()
                               .addRoundRect(100, 10, 140, 62,
                                             10, 4, true);

            canvas.drawPath(rrect, paint);
            rrect.delete();

            surface.flush();

            path.delete();
            paint.delete();

            reportSurface(surface, 'path_api_example', done);
        }));
        // See PathKit for more tests, since they share implementation
    });

    it('can draw directly to a canvas', function(done) {
        LoadCanvasKit.then(catchException(done, () => {
            // This is taken from example.html
            const surface = CanvasKit.MakeCanvasSurface('test');
            expect(surface).toBeTruthy('Could not make surface')
            if (!surface) {
                done();
                return;
            }
            const canvas = surface.getCanvas();
            const paint = new CanvasKit.SkPaint();
            paint.setStrokeWidth(2.0);
            paint.setAntiAlias(true);
            paint.setColor(CanvasKit.Color(0, 0, 0, 1.0));
            paint.setStyle(CanvasKit.PaintStyle.Stroke);

            canvas.drawLine(3, 10, 30, 15, paint);
            canvas.drawRoundRect(CanvasKit.LTRBRect(5, 35, 45, 80), 15, 10, paint);

            canvas.drawOval(CanvasKit.LTRBRect(5, 35, 45, 80), paint);

            canvas.drawArc(CanvasKit.LTRBRect(55, 35, 95, 80), 15, 270, true, paint);

            const font = new CanvasKit.SkFont(null, 20);
            canvas.drawText('this is ascii text', 5, 100, font, paint);

            const blob = CanvasKit.SkTextBlob.MakeFromText('Unicode chars 💩 é É ص', font);
            canvas.drawTextBlob(blob, 5, 130, paint);

            surface.flush();
            font.delete();
            blob.delete();
            paint.delete();

            reportSurface(surface, 'canvas_api_example', done);
        }));
        // See canvas2d for more API tests
    });

    function starPath(CanvasKit, X=128, Y=128, R=116) {
        let p = new CanvasKit.SkPath();
        p.moveTo(X + R, Y);
        for (let i = 1; i < 8; i++) {
          let a = 2.6927937 * i;
          p.lineTo(X + R * Math.cos(a), Y + R * Math.sin(a));
        }
        return p;
      }

    it('can apply an effect and draw text', function(done) {
        LoadCanvasKit.then(catchException(done, () => {
            const surface = CanvasKit.MakeCanvasSurface('test');
            expect(surface).toBeTruthy('Could not make surface')
            if (!surface) {
                done();
                return;
            }
            const canvas = surface.getCanvas();
            const path = starPath(CanvasKit);

            const paint = new CanvasKit.SkPaint();

            const textPaint = new CanvasKit.SkPaint();
            textPaint.setColor(CanvasKit.Color(40, 0, 0, 1.0));
            textPaint.setAntiAlias(true);

            const textFont = new CanvasKit.SkFont(null, 30);

            const dpe = CanvasKit.MakeSkDashPathEffect([15, 5, 5, 10], 1);

            paint.setPathEffect(dpe);
            paint.setStyle(CanvasKit.PaintStyle.Stroke);
            paint.setStrokeWidth(5.0);
            paint.setAntiAlias(true);
            paint.setColor(CanvasKit.Color(66, 129, 164, 1.0));

            canvas.clear(CanvasKit.Color(255, 255, 255, 1.0));

            canvas.drawPath(path, paint);
            canvas.drawText('This is text', 10, 280, textFont, textPaint);
            surface.flush();
            dpe.delete();
            path.delete();

            reportSurface(surface, 'effect_and_text_example', done);
        }));
    });

    it('can create a path from an SVG string', function(done) {
        LoadCanvasKit.then(catchException(done, () => {
            //.This is a parallelagram from
            // https://upload.wikimedia.org/wikipedia/commons/e/e7/Simple_parallelogram.svg
            let path = CanvasKit.MakePathFromSVGString('M 205,5 L 795,5 L 595,295 L 5,295 L 205,5 z');

            let cmds = path.toCmds();
            expect(cmds).toBeTruthy();
            // 1 move, 4 lines, 1 close
            // each element in cmds is an array, with index 0 being the verb, and the rest being args
            expect(cmds.length).toBe(6);
            expect(cmds).toEqual([[CanvasKit.MOVE_VERB, 205, 5],
                                  [CanvasKit.LINE_VERB, 795, 5],
                                  [CanvasKit.LINE_VERB, 595, 295],
                                  [CanvasKit.LINE_VERB, 5, 295],
                                  [CanvasKit.LINE_VERB, 205, 5],
                                  [CanvasKit.CLOSE_VERB]]);
            path.delete();
            done();
        }));
    });

     it('can create an SVG string from a path', function(done) {
        LoadCanvasKit.then(catchException(done, () => {
            let cmds = [[CanvasKit.MOVE_VERB, 205, 5],
                       [CanvasKit.LINE_VERB, 795, 5],
                       [CanvasKit.LINE_VERB, 595, 295],
                       [CanvasKit.LINE_VERB, 5, 295],
                       [CanvasKit.LINE_VERB, 205, 5],
                       [CanvasKit.CLOSE_VERB]];
            let path = CanvasKit.MakePathFromCmds(cmds);

            let svgStr = path.toSVGString();
            // We output it in terse form, which is different than Wikipedia's version
            expect(svgStr).toEqual('M205 5L795 5L595 295L5 295L205 5Z');
            path.delete();
            done();
        }));
    });
});