import BABYLON from 'babylonjs';
import EventEmitter from 'events';
import {Buttons} from '../input.js';

const keyButtonMap = {
  'Escape': Buttons.Menu,
  'u': Buttons.A,
  'i': Buttons.B,
  'o': Buttons.X,
  'p': Buttons.Y,
  'f': Buttons.RB,
  'e': Buttons.LB,
};

const keyJoyMap = {
  'a': new BABYLON.Vector2(-1, 0), // left
  'd': new BABYLON.Vector2(1, 0), // right
  'w': new BABYLON.Vector2(0, 1), // up
  's': new BABYLON.Vector2(0, -1), // down
};
const joyKeys = Object.keys(keyJoyMap);

const maxMutualJoy = Math.sqrt(Math.pow(1, 2)/2);

export default class KeyboardInput extends EventEmitter {
  constructor(game) {
    super();

    const keyState = Object.keys(keyButtonMap).concat(joyKeys).reduce((acc, name) => {
      acc[name] = false;
      return acc;
    }, Object.create(null));

    const joyVector = new BABYLON.Vector2(0, 0);

    const updateJoy = () => {
      joyVector.x = 0;
      joyVector.y = 0;
      for (const joyKey of joyKeys) {
        if (keyState[joyKey]) {
          joyVector.addInPlace(keyJoyMap[joyKey]);
        }
      }
      // Enforce joystick being circular.
      if (joyVector.x && joyVector.y) {
        joyVector.x *= maxMutualJoy;
        joyVector.y *= maxMutualJoy;
      }
      this.emit('joychanged', joyVector);
    };

    window.addEventListener('keydown', e => {
      const key = e.key;
      const alreadyPressed = keyState[key];
      // Either we have already handled it or it is a key we don’t
      // care about.
      if (alreadyPressed || alreadyPressed === undefined) {
        return;
      }

      // Mark as pressed.
      keyState[key] = true;

      // Is it a joy key?
      if (keyJoyMap[key]) {
        updateJoy();
        return;
      }

      // Is it a button?
      var button = keyButtonMap[key];
      if (button) {
        this.emit('buttondown', button);
        return;
      }
    });

    window.addEventListener('keyup', e => {
      const key = e.key;

      // Do we care about this key?
      if (keyState[key] === undefined) {
        return;
      }

      keyState[key] = false;

      // Is it a joy key?
      if (keyJoyMap[key]) {
        updateJoy();
        return;
      }

      // Is it a button?
      var button = keyButtonMap[key];
      if (button) {
        this.emit('buttonup', button);
        return;
      }
    });

    game.addInput(this);
  }

  get name() {
    return 'keyboard';
  }
}

@@ -133,16 +133,14 @@
 %0D%0A  
-'
 Escape
-'
 : Bu
@@ -158,11 +158,12 @@
 %0D%0A  
-'u'
+KeyU
 : Bu
@@ -178,11 +178,12 @@
 %0D%0A  
-'i'
+KeyI
 : Bu
@@ -198,11 +198,12 @@
 %0D%0A  
-'o'
+KeyO
 : Bu
@@ -218,11 +218,12 @@
 %0D%0A  
-'p'
+KeyP
 : Bu
@@ -238,11 +238,17 @@
 %0D%0A  
-'f'
+ShiftLeft
 : Bu
@@ -257,18 +257,20 @@
 ons.
-R
+L
 B,%0D%0A  
-'e'
+Space
 : Bu
@@ -271,25 +271,25 @@
 ce: Buttons.
-L
+R
 B,%0D%0A%7D;%0D%0A%0D%0Aco
@@ -313,11 +313,12 @@
 %0D%0A  
-'a'
+KeyA
 : ne
@@ -358,11 +358,12 @@
 %0D%0A  
-'d'
+KeyD
 : ne
@@ -403,11 +403,12 @@
 %0D%0A  
-'w'
+KeyW
 : ne
@@ -445,11 +445,12 @@
 %0D%0A  
-'s'
+KeyS
 : ne
@@ -1397,33 +1397,289 @@
 %0D%0A      
-const key = e.key
+// Code represents the actual key itself rather than the%0D%0A      // character that would be printed as a result of pressing the%0D%0A      // key. For example, if you%E2%80%99re holding shift, key would give%0D%0A      // uppercase characters for alphabetic keys.%0D%0A      const code = e.code
 ;%0D%0A     
@@ -1711,19 +1711,20 @@
 eyState%5B
-key
+code
 %5D;%0D%0A    
@@ -1936,27 +1936,28 @@
    keyState%5B
-key
+code
 %5D = true;%0D%0A%0D
@@ -1996,35 +1996,36 @@
   if (keyJoyMap%5B
-key
+code
 %5D) %7B%0D%0A        up
@@ -2114,35 +2114,36 @@
  = keyButtonMap%5B
-key
+code
 %5D;%0D%0A      if (bu
@@ -2291,19 +2291,21 @@
 nst 
-key
+code
  = e.
-key
+code
 ;%0D%0A%0D
@@ -2361,19 +2361,20 @@
 eyState%5B
-key
+code
 %5D === un
@@ -2428,19 +2428,20 @@
 eyState%5B
-key
+code
 %5D = fals
@@ -2493,19 +2493,20 @@
 yJoyMap%5B
-key
+code
 %5D) %7B%0D%0A  
@@ -2611,19 +2611,20 @@
 ttonMap%5B
-key
+code
 %5D;%0D%0A    

Fix keyboard to use KeyboardEvent.code instead of KeyboardEvent.key.