<!-- Any copyright is dedicated to the Public Domain.
   - http://creativecommons.org/publicdomain/zero/1.0/ -->
<!DOCTYPE HTML>
<html>
<head>
  <title>Test gamepad</title>
  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<script type="text/javascript" src="mock_gamepad.js"></script>
<script class="testbody" type="text/javascript">
let ok = window.parent.ok;
let is = window.parent.is;
let SimpleTest = window.parent.SimpleTest;
let SpecialPowers = window.parent.SpecialPowers;

var tests = [
  poseadd,
  posecheck,
  touchadd,
  touchcheck,
  haptictest // Keep haptictest at the last because it will test removing gamepad from the service.
];
var gamepad_index = 0;
var testNum = 0;
var poseOrient = new Float32Array([-0.203, -0.235, 0.740, -0.596]);
var posePos = new Float32Array([-0.0233, -0.707, -0.763]);
var poseAngVel = new Float32Array([-0.0008, 0.00147, 0.001]);
var poseAngAcc = new Float32Array([-0.494, 0.476, -0.241]);
var poseLinVel = new Float32Array([0.003,0.024,-0.068]);
var poseLinAcc = new Float32Array([-1.211,21.427,-2.348]);
var touchData = [{touchId: 0, surfaceId: 0, pos: new Float32Array([-0.5, 0.5]), surf: new Float32Array([100, 100])},
                 {touchId: 1, surfaceId: 0, pos: new Float32Array([-0.1, 1.0]), surf: new Float32Array([100, 100])}];

window.addEventListener("gamepadconnected", connecthandler);
window.addEventListener("gamepadbuttondown", function() {
  // Wait to ensure that all frames received the button press as well.
  SpecialPowers.executeSoon(async ()=> {
    await tests[testNum++]()
  });
});

async function pressButton() {
  await GamepadService.newButtonEvent(gamepad_index, 0, true, true);
  await GamepadService.newButtonEvent(gamepad_index, 0, false, false);
}

async function startTest() {
  await SpecialPowers.pushPrefEnv({ "set": [
                                    ["dom.gamepad.extensions.enabled", true],
                                    ["dom.gamepad.extensions.lightindicator", true],
                                    ["dom.gamepad.extensions.multitouch", true]] });
  // Add a gamepad
  gamepad_index = await GamepadService.addGamepad("test gamepad", // id
                      GamepadService.standardMapping,
                      GamepadService.leftHand,
                      4,
                      2,
                      1,
                      1,
                      2);

  // Simulate button events on the gamepad we added
  await pressButton();

}

function connecthandler(e) {
  ok(e.gamepad.timestamp <= performance.now(),
     "gamepad.timestamp should less than or equal to performance.now()");
  is(e.gamepad.index, 0, "correct gamepad index");
  is(e.gamepad.id, "test gamepad", "correct gamepad name");
  is(e.gamepad.mapping, "standard", "standard mapping");
  is(e.gamepad.hand, "left", "left hand");
  is(e.gamepad.buttons.length, 4, "correct number of buttons");
  is(e.gamepad.axes.length, 2, "correct number of axes");
  is(e.gamepad.hapticActuators.length, 1, "correct number of haptics");
  is(e.gamepad.lightIndicators.length, 1, "correct number of light indicators");
  is(e.gamepad.touchEvents.length, 2, "correct number of touches");
}

function checkValueInFloat32Array(array1, array2) {
  if (array1.length != array2.length) {
    return false;
  }
  var index = 0;
  while (index < array2.length) {
    if (array1[index] != array2[index]) {
      return false;
    }
    ++index;
  }
  return true;
}

async function poseadd() {
  await GamepadService.newPoseMove(gamepad_index, poseOrient,
                             posePos, poseAngVel, poseAngAcc,
                             poseLinVel, poseLinAcc);
  await pressButton();
}

async function posecheck() {
  var gamepads = navigator.getGamepads();
  var pose = gamepads[0].pose;
  is(gamepads[0].pose.hasOrientation, true,
     "correct gamepadPose hasOrientation");
  is(gamepads[0].pose.hasPosition, true,
     "correct gamepadPose hasPosition");
  is(checkValueInFloat32Array(pose.orientation, poseOrient), true,
     "correct gamepadPose orientation");
  is(checkValueInFloat32Array(pose.position, posePos), true,
     "correct gamepadPose position");
  is(checkValueInFloat32Array(pose.angularVelocity, poseAngVel), true,
     "correct gamepadPose angularVelocity");
  is(checkValueInFloat32Array(pose.angularAcceleration, poseAngAcc), true,
     "correct gamepadPose angularAcceleration");
  is(checkValueInFloat32Array(pose.linearVelocity, poseLinVel), true,
     "correct gamepadPose linearVelocity");
  is(checkValueInFloat32Array(pose.linearAcceleration, poseLinAcc), true,
     "correct gamepadPose linearAcceleration");
  await pressButton();
}

function setFrameVisible(f, visible) {
  SpecialPowers.wrap(f.contentWindow).browsingContext.isActive = visible;
}

function haptictest() {
  var gamepads = navigator.getGamepads();
  var hapticActuators = gamepads[0].hapticActuators[0];
  hapticActuators.pulse(1, 100).then(async function(result) {
    is(result, true, "gamepad hapticActuators test success.");
    await GamepadService.removeGamepad(gamepad_index);
    SimpleTest.finish();
  });
  // When page is background, we should stop our haptics and still
  // can get the promise.
  var f1 = document.getElementById('f1');
  setFrameVisible(f1, false);
}

async function touchadd() {
  for(var count = 0; count < touchData.length; count++) {
    const touch = touchData[count];
    await GamepadService.newTouch(gamepad_index, count, touch.touchId,
                            touch.surfaceId, touch.pos,
                            touch.surf);
  }
  await pressButton();
}

async function touchcheck() {
  var gamepads = navigator.getGamepads();
  var touches = gamepads[0].touchEvents;

  is(touches.length, 2, " number of touches");

  var count = 0;
  touches.forEach(function(touch) {
    is(touch.touchId, touchData[count].touchId,
     "correct GamepadTouch touchId");
    is(touch.surfaceId, touchData[count].surfaceId,
     "correct GamepadTouch surfaceId");
    is(checkValueInFloat32Array(touch.position, touchData[count].pos), true,
      "correct touch position");
    is(checkValueInFloat32Array(touch.surfaceDimensions, touchData[count].surf), true,
      "correct touch surfaceDimensions");

    ++count;
  });

  await pressButton();
}

</script>
<iframe id="f1" src="gamepad_frame_state.html" onload="runGamepadTest(startTest)"></iframe>
</body>
</html>
