import * as Logger from "../../module/logger.js";

const _e = 0.09;
const _gameloopInterval = 16.67; //in milliseconds, 60 times a second
var gameloop = null;
var gamepadsPreviousButtonsStates = {};
var gamepadsPreviousAxesStates = {};
var gamepadsConnectedTimeStamp = {};
const _axisOffset = 100;
const _axisMultiplier = 1;
const _axisYInverted = -1;

class GamepadButtonEvent extends Event {
  constructor() {
    super(...arguments);
    this.index = arguments[1].index;
    this.id = arguments[1].id;
    this.value = arguments[1].value;
  }
}

class GamepadAxisEvent extends Event {
  constructor() {
    super(...arguments);
    this.index = arguments[1].index;
    this.x = arguments[1].x;
    this.y = arguments[1].y;
    this.id = arguments[1].id;
  }
}

function storePreviousState(gamepad) {
  gamepadsPreviousButtonsStates[gamepad.index] = {};
  gamepad.buttons.forEach(function (button, index) {
    gamepadsPreviousButtonsStates[gamepad.index][index] = { value: button.value, pressed: button.pressed };
  });

  gamepadsPreviousAxesStates[gamepad.index] = [gamepad.axes.length];
  for (var index = 0; index < gamepad.axes.length; index++)
    gamepadsPreviousAxesStates[gamepad.index][index] = gamepad.axes[index];
}

function checkAxes(gamepad, previousGamePad) {
  for (var i = 0; i < gamepad.axes.length; i += 2) {
    var absX = Math.abs(gamepad.axes[i]);
    var absY = Math.abs(gamepad.axes[i + 1]);
    var event = null;
    if ((absX > _e) ||
      (absY > _e)) {

      event = new GamepadAxisEvent('gamepadAxis', { id: gamepadsConnectedTimeStamp[gamepad.index], index: i / 2 + _axisOffset, x: gamepad.axes[i] * _axisMultiplier, y: gamepad.axes[i + 1] * _axisMultiplier * _axisYInverted });
      document.dispatchEvent(event);
    }
    else {
      var previousAbsX = Math.abs(previousGamePad[i]);
      var previousAbsY = Math.abs(previousGamePad[i + 1]);

      //have to send if previously was moved
      if ((previousAbsX > _e) ||
        (previousAbsY > _e)) {
        event = new GamepadAxisEvent('gamepadAxis', { id: gamepadsConnectedTimeStamp[gamepad.index], index: i / 2 + _axisOffset, x: 0.0, y: 0.0 });
        document.dispatchEvent(event);
      }
    }
  }
}

function gameLoop() {
  Object.keys(gamepadsPreviousAxesStates).forEach(function (gamepadIndex) {
    var gamepad = navigator.webkitGetGamepads ? navigator.webkitGetGamepads()[gamepadIndex] : navigator.getGamepads()[gamepadIndex];
    var previousButtons = gamepadsPreviousButtonsStates[gamepadIndex];
    gamepad.buttons.forEach(function (button, index) {
      var buttonStatus = navigator.webkitGetGamepads ? button == 1 : (button.value > 0 || button.pressed == true);
      var previousButtonStatus = navigator.webkitGetGamepads ? previousButtons[index].value == 1 : (previousButtons[index].value > 0 || previousButtons[index].pressed == true);
      var event;
      if (buttonStatus != previousButtonStatus) {
        if (buttonStatus) {
          event = new GamepadButtonEvent('gamepadButtonDown', { id: gamepadsConnectedTimeStamp[gamepad.index], index: index, value: button.value });
        }
        else {
          event = new GamepadButtonEvent('gamepadButtonUp', { id: gamepadsConnectedTimeStamp[gamepad.index], index: index, value: 0 });
        }
        document.dispatchEvent(event);
      }
      else if (buttonStatus) {
        event = new GamepadButtonEvent('gamepadButtonPressed', { id: gamepadsConnectedTimeStamp[gamepad.index], index: index, value: button.value });
        document.dispatchEvent(event);
      }

    });
    checkAxes(gamepad, gamepadsPreviousAxesStates[gamepadIndex]);
    storePreviousState(gamepad);
  });
}

function getCookie(cname) {
  var name = cname + "=";
  var decodedCookie = decodeURIComponent(document.cookie);
  var ca = decodedCookie.split(';');
  for (var i = 0; i < ca.length; i++) {
    var c = ca[i];
    while (c.charAt(0) == ' ') {
      c = c.substring(1);
    }
    if (c.indexOf(name) == 0) {
      return c.substring(name.length, c.length);
    }
  }
  return "";
}

export function gamepadHandler(event, connecting) {
  var gamepad = event.gamepad;

  var key = gamepad.id.replace(/\s/g, '');
  var cookieTimeStamp = getCookie(key);

  if (connecting) {
    storePreviousState(gamepad);
    if (Object.keys(gamepadsPreviousAxesStates).length == 1) {
      gameloop = setInterval(gameLoop, _gameloopInterval);
    }

    //try to find the timestamp
    //need to strip the : from the id

    if (cookieTimeStamp == "") {
      document.cookie = key + "=" + gamepad.timestamp;
      gamepadsConnectedTimeStamp[gamepad.index] = gamepad.timestamp;
    }
    else {
      gamepadsConnectedTimeStamp[gamepad.index] = cookieTimeStamp;
    }

    Logger.log("connected: " + gamepadsConnectedTimeStamp[gamepad.index]);

  } else {
    delete gamepadsPreviousAxesStates[gamepad.index];
    delete gamepadsPreviousButtonsStates[gamepad.index];
    if (Object.keys(gamepadsPreviousAxesStates).length == 0) {
      clearInterval(gameloop);
      gameloop = null;
    }
    Logger.log("disconnected: " + gamepad.id);
  }
}
