/* LICENSE: This code is in the public domain */

/**
 * This is a library to handle keypresses by the Wiimote in the Wii Opera browser.
 * An event handler that can be used in Mozilla Firefox (for testing)
 * is also provided.
 *
 * @author bolinfest@gmail.com (Michael Bolin)
 */

// TODO(bolinfest): Add support for detecting when multiple buttons
// are being held down instead of only when they are clicked

/** wii namespace */
var wii = {};

wii.isWiiOperaBrowser = function() {
  return (navigator.userAgent.toLowerCase().indexOf("nintendo wii") >= 0);
}

// wii keycodes
wii.KEYCODE_MINUS_ = 170;
wii.KEYCODE_PLUS_ = 174;
wii.KEYCODE_1_ = 172;
wii.KEYCODE_2_ = 173;
wii.KEYCODE_B_ = 171;
wii.KEYCODE_UP_ = 175;
wii.KEYCODE_DOWN_ = 176;
wii.KEYCODE_RIGHT_ = 177;
wii.KEYCODE_LEFT_ = 178;

/** @type Array<Controller> */
wii.controllers_ = [];

/**
 * @param {Controller} controller
 * @return true if the controller is added; false otherwise
 */
wii.addController = function(controller) {
  if (!(controller instanceof wii.Controller)) {
    throw new Error("invalid argument passed to wii.addController");
  }
  var controllers = wii.controllers_;
  var alreadyAdded = false;
  for (var i = 0, len = controllers.length; i < len; ++i) {
    if (controllers[i] === controller) {
      alreadyAdded = true;
      break;
    }
  }
  if (!alreadyAdded) {
    controllers.push(controller);
  }
  return !alreadyAdded;
}

/**
 * @param {Controller} controller
 * @return true if the controller is removed; false otherwise
 */
wii.removeController = function(controller) {
  if (!(controller instanceof wii.Controller)) {
    throw new Error("invalid argument passed to wii.addController");
  }
  var controllers = wii.controllers_;
  var removed = false;
  for (var i = 0, len = controllers.length; i < len; ++i) {
    if (controllers[i] === controller) {
      controllers.splice(i, 1);
      removed = true;
      break;
    }
  }
  return removed;
}

/**
 * This should be called by the onload() handler of the page to add the
 * appropriate key and mouse listeners
 */
wii.setupHandlers = function() {
  document.onkeypress = wii.handleKeyPress_;
  document.onclick = wii.handleMouseClick_;
}

wii.handleKeyPress_ = function(e) {
  var keyCode = e.which;
  var controllers = wii.controllers_;
  var returnValue = true;
  for (var i = 0, len = controllers.length; i < len; ++i) {
    var controller = controllers[i];
    if (!controller.handleKeyPress(keyCode)) {
      returnValue = false;
    }
  }
  return returnValue;
}

wii.handleMouseClick_ = function(e) {
  if (e.which != 1) {
    // not the left mouse button
    return;
  }
  var returnValue = true;
  var controllers = wii.controllers_;
  for (var i = 0, len = controllers.length; i < len; ++i) {
    var controller = controllers[i];
    if (!controller.handleMouseClick()) {
      returnValue = false;
    }
  }
  return returnValue;
}

wii.Controller = function() {};
wii.Controller.prototype.handleMouseClick = function() { return true; };
wii.Controller.prototype.handleKeyPress = function(keyCode) { return true; };
wii.Controller.prototype.handleUp = function() { return true; };
wii.Controller.prototype.handleDown = function() { return true; };
wii.Controller.prototype.handleLeft = function() { return true; };
wii.Controller.prototype.handleRight = function() { return true; };
wii.Controller.prototype.handleMinus = function() { return true; };
wii.Controller.prototype.handlePlus = function() { return true; };
wii.Controller.prototype.handle1 = function() { return true; };
wii.Controller.prototype.handle2 = function() { return true; };
wii.Controller.prototype.handleA = function() { return true; };
wii.Controller.prototype.handleB = function() { return true; };

wii.Wiimote = function() {
  wii.Controller.call(null);
};
wii.Wiimote.prototype = new wii.Controller();
wii.Wiimote.prototype.toString = function() {
  return "[Wiimote]";
};
wii.Wiimote.prototype.handleMouseClick = function() {
  return this.handleA();
};
wii.Wiimote.prototype.handleKeyPress = function(keyCode) {
  switch (keyCode) {
    case wii.KEYCODE_UP_:
      this.handleUp();
      break;
    case wii.KEYCODE_DOWN_:
      this.handleDown();
      break;
    case wii.KEYCODE_LEFT_:
      this.handleLeft();
      break;
    case wii.KEYCODE_RIGHT_:
      this.handleRight();
      break;
    case wii.KEYCODE_MINUS_:
      this.handleMinus();
      break;
    case wii.KEYCODE_PLUS_:
      this.handlePlus();
      break;
    case wii.KEYCODE_1_:
      this.handle1();
      break;
    case wii.KEYCODE_2_:
      this.handle2();
      break;
    case wii.KEYCODE_B_:
      this.handleB();
      break;
    default:
      return true;
  }
  return false;
};

wii.HorizontalController = function() {
  wii.Controller.call(null);
};
wii.HorizontalController.prototype = new wii.Controller();
wii.HorizontalController.prototype.toString = function() {
  return "[HorizontalController]";
};
wii.HorizontalController.prototype.handleKeyPress = function(keyCode) {
  switch (keyCode) {
    case wii.KEYCODE_UP_:
      this.handleLeft();
      break;
    case wii.KEYCODE_DOWN_:
      this.handleRight();
      break;
    case wii.KEYCODE_LEFT_:
      this.handleDown();
      break;
    case wii.KEYCODE_RIGHT_:
      this.handleUp();
      break;
    case wii.KEYCODE_MINUS_:
      this.handleMinus();
      break;
    case wii.KEYCODE_PLUS_:
      this.handlePlus();
      break;
    case wii.KEYCODE_1_:
      this.handleB();
      break;
    case wii.KEYCODE_2_:
      this.handleA();
      break;
    default:
      return true;
  }
  return false;
};

wii.KeyboardController = function() {
  wii.Controller.call(null);
};
wii.KeyboardController.prototype = new wii.Controller();
wii.KeyboardController.prototype.toString = function() {
  return "[KeyboardController]";
};
wii.KeyboardController.prototype.handleKeyPress = function(keyCode) {
  switch (keyCode) {

    case 105: // I
      this.handleUp();
      break;
    case 107: // K
      this.handleDown();
      break;
    case 106: // J
      this.handleLeft();
      break;
    case 108: // L
      this.handleRight();
      break;
    case 45:  // -
      this.handleMinus();
      break;
    case 43:  // +
      this.handlePlus();
      break;
    case 49:  // 1
      this.handle1();
      break;
    case 50:  // 2
      this.handle2();
      break;
    case 98:  // B 
      this.handleB();
      break;
    case 97:  // A
      this.handleA();
      break;
    default:
      return true;
  }
  return false;
};

