
function target_test(...args)
{
    if (args.length !== 2 && args.length !== 3) {
        console.error(`target_test expected 2 or 3 arguments but got ${args.length}.`);
        return;
    }

    const impliedOptions = args.length == 2;

    let options = impliedOptions ? { } : args[0];
    let continutation = args[impliedOptions ? 0 : 1];
    let description = args[impliedOptions ? 1 : 2];

    options.name = options.name || "div";
    options.x = options.x || 0;
    options.y = options.y || 0;
    options.width = options.width || "100%";
    options.height = options.height || "100%";

    async_test(test => {
        continutation(makeTarget(test, options), test);
    }, description);
}

function makeTarget(test, options)
{
    const target = document.body.appendChild(document.createElement(options.name));
    target.setAttribute("style", `
        position: absolute;
        left: ${options.x};
        top: ${options.y};
        width: ${options.width};
        height: ${options.height};
    `);
    test.add_cleanup(() => target.remove());
    return target;
}

class EventTracker
{
    constructor(target, eventNames)
    {
        this.target = target;
        this.events = [];
        this.pointerIdToTouchIdMap = {};

        for (let eventName of eventNames)
            target.addEventListener(eventName, this);
    }

    clear()
    {
        this.events = [];
    }

    handleEvent(event)
    {
        if (event instanceof PointerEvent)
            this._handlePointerEvent(event);
        else if (event instanceof MouseEvent)
            this._handleMouseEvent(event);
        else if (event instanceof TouchEvent)
            this._handleTouchEvent(event);
    }

    _handlePointerEvent(event)
    {
        if (!this.pointerIdToTouchIdMap[event.pointerId])
            this.pointerIdToTouchIdMap[event.pointerId] = Object.keys(this.pointerIdToTouchIdMap).length + 1;

        this.events.push({
            id: this.pointerIdToTouchIdMap[event.pointerId],
            type: event.type,
            x: event.clientX,
            y: event.clientY,
            pressure: event.pressure,
            isPrimary: event.isPrimary,
            isTrusted: event.isTrusted,
            button: event.button,
            buttons: event.buttons
        });
    }

    _handleMouseEvent(event)
    {
        this.events.push({
            type: event.type,
            x: event.clientX,
            y: event.clientY,
        });
    }

    _handleTouchEvent(event)
    {
        this.events.push({ type: event.type });
    }

    assertMatchesEvents(expectedEvents)
    {
        assert_true(!!this.events.length, "Event tracker saw some events.");
        assert_equals(this.events.length, expectedEvents.length, "Expected events and actual events have the same length.");
        for (let i = 0; i < expectedEvents.length; ++i) {
            const expectedEvent = expectedEvents[i];
            const actualEvent = this.events[i];
            for (let property of Object.getOwnPropertyNames(expectedEvent))
                assert_equals(actualEvent[property], expectedEvent[property], `Property ${property} matches for event at index ${i}.`);
        }
    }
}

const ui = new (class UIController {

    constructor()
    {
        this.fingers = {};
    }

    finger()
    {
        const id = Object.keys(this.fingers).length + 1;
        return this.fingers[id] = new Finger(id);
    }

    swipe(from, to)
    {
        const durationInSeconds = 0.1;
        return new Promise(resolve => this._run('dragFromPointToPoint', `${from.x}, ${from.y}, ${to.x}, ${to.y}, ${durationInSeconds}`).then(() =>
            setTimeout(resolve, durationInSeconds * 1000)
        ));
    }

    tap(options)
    {
        return this._run('singleTapAtPoint', `${options.x}, ${options.y}`);
    }

    doubleTap(options)
    {
        return this._run('doubleTapAtPoint', `${options.x}, ${options.y}, 0`);
    }

    doubleTapToZoom(options)
    {
        const durationInSeconds = 0.35;
        return new Promise(resolve => this._run('doubleTapAtPoint', `${options.x}, ${options.y}, 0`).then(() =>
            setTimeout(resolve, durationInSeconds * 1000)
        ));
    }

    pinchOut(options)
    {
        options.x = options.x || 0;
        options.y = options.y || 0;

        const startPoint = { x: options.x + options.width, y: options.y + options.height };
        const endPoint = { x: options.x + options.width * options.scale, y: options.y + options.height * options.scale };

        function step(factor)
        {
            return {
                x: endPoint.x + (startPoint.x - endPoint.x) * (1 - factor),
                y: endPoint.y + (startPoint.y - endPoint.y) * (1 - factor)
            };
        }

        const one = this.finger();
        const two = this.finger();
        return this.sequence([
            one.begin({ x: options.x, y: options.y }),
            two.begin(step(0)),
            two.move(step(0.2)),
            two.move(step(0.4)),
            two.move(step(0.6)),
            two.move(step(0.8)),
            two.move(step(1)),
            one.end(),
            two.end()
        ]);
    }

    sequence(touches)
    {
        const activeFingers = {};

        return this._runEvents(touches.map((touches, index) => {
            if (!Array.isArray(touches))
                touches = [touches];

            const processedIDs = {};

            // Update the list of active touches.
            touches.forEach(touch => {
                processedIDs[touch.id] = true;
                if (touch.phase === "ended")
                    delete activeFingers[touch.id];
                else
                    activeFingers[touch.id] = { x: touch.x, y: touch.y };
            });

            // Now go through the active touches and check that they're all listed in the new touches.
            for (let id in activeFingers) {
                if (!processedIDs[id])
                    touches.push(this.fingers[id].stationary(activeFingers[id]));
            }

            return {
                inputType : "hand",
                timeOffset : index * 0.05,
                coordinateSpace : "content",
                touches : touches
            }
        }));
    }

    tapStylus(options)
    {
        options.azimuthAngle = options.azimuthAngle || 0;
        options.altitudeAngle = options.altitudeAngle || 0;
        options.pressure = options.pressure || 0;
        return this._run('stylusTapAtPoint', `${options.x}, ${options.y}, ${options.azimuthAngle}, ${options.altitudeAngle}, ${options.pressure}`);
    }

    _runEvents(events)
    {
        return this._run('sendEventStream', `'${JSON.stringify({ events })}'`);
    }

    _run(command, args)
    {
        const script = `uiController.${command}(${args}, () => uiController.uiScriptComplete());`;
        return new Promise(resolve => testRunner.runUIScript(script, resolve));
    }

})();

class Finger
{

    constructor(id)
    {
        this.id = id;
    }

    begin(options)
    {
        return this._action("began", options.x || 0, options.y || 0);
    }

    move(options)
    {
        return this._action("moved", options.x || 0, options.y || 0);
    }

    end(options)
    {
        return this._action("ended", this._lastX, this._lastY);
    }

    stationary(options)
    {
        return this._action("stationary", options.x || this._lastX, options.y || this._lastY, options.pressure || 0);
    }

    _action(phase, x, y, pressure = 0)
    {
        this._lastX = x;
        this._lastY = y;
        return { inputType: "finger", id: this.id, phase, x, y, pressure };
    }

}
