// Copyright 2015 The Cobalt Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "cobalt/input/input_device_manager_desktop.h"

#include <cmath>
#include <string>

#include "base/time/time.h"
#include "cobalt/base/token.h"
#include "cobalt/base/tokens.h"
#include "cobalt/dom/input_event.h"
#include "cobalt/dom/input_event_init.h"
#include "cobalt/dom/keyboard_event.h"
#include "cobalt/dom/keyboard_event_init.h"
#include "cobalt/dom/pointer_event.h"
#include "cobalt/dom/pointer_event_init.h"
#include "cobalt/dom/wheel_event.h"
#include "cobalt/dom/wheel_event_init.h"
#include "cobalt/input/create_default_camera_3d.h"
#include "cobalt/input/input_poller_impl.h"
#include "cobalt/overlay_info/overlay_info_registry.h"
#include "cobalt/system_window/input_event.h"
#include "cobalt/web/event.h"
#include "cobalt/web/event_init.h"

namespace cobalt {
namespace input {

namespace {
void UpdateEventInit(const system_window::InputEvent* input_event,
                     web::EventInit* event) {
  if (input_event->timestamp() != 0) {
    // Convert monotonic int64_t to DOMTimeStamp.
    event->set_time_stamp(
        cobalt::web::Event::GetEventTime(input_event->timestamp()));
  }
}
}  // namespace

InputDeviceManagerDesktop::InputDeviceManagerDesktop(
    const KeyboardEventCallback& keyboard_event_callback,
    const PointerEventCallback& pointer_event_callback,
    const WheelEventCallback& wheel_event_callback,
    const InputEventCallback& input_event_callback,
    system_window::SystemWindow* system_window)
    : system_window_(system_window),
      system_window_input_event_callback_(
          base::Bind(&InputDeviceManagerDesktop::HandleSystemWindowInputEvent,
                     base::Unretained(this))),
      input_event_callback_(input_event_callback),
      keypress_generator_filter_(keyboard_event_callback),
      pointer_event_callback_(pointer_event_callback),
      wheel_event_callback_(wheel_event_callback) {
  input_poller_ = new InputPollerImpl();
  DCHECK(system_window_);
  camera_3d_ =
      CreatedDefaultCamera3D(system_window->GetSbWindow(), input_poller_);

  if (system_window_) {
    // Add this object's keyboard event callback to the system window.
    system_window_->event_dispatcher()->AddEventCallback(
        system_window::InputEvent::TypeId(),
        system_window_input_event_callback_);
  }
}

InputDeviceManagerDesktop::~InputDeviceManagerDesktop() {
  // If we have an associated system window, remove our callback from it.
  if (system_window_) {
    system_window_->event_dispatcher()->RemoveEventCallback(
        system_window::InputEvent::TypeId(),
        system_window_input_event_callback_);
  }
}

namespace {

COMPILE_ASSERT(static_cast<uint32_t>(kSbKeyModifiersNone) ==
                       system_window::InputEvent::kNoModifier &&
                   static_cast<uint32_t>(kSbKeyModifiersAlt) ==
                       system_window::InputEvent::kAltKey &&
                   static_cast<uint32_t>(kSbKeyModifiersCtrl) ==
                       system_window::InputEvent::kCtrlKey &&
                   static_cast<uint32_t>(kSbKeyModifiersMeta) ==
                       system_window::InputEvent::kMetaKey &&
                   static_cast<uint32_t>(kSbKeyModifiersShift) ==
                       system_window::InputEvent::kShiftKey,
               Mismatched_modifier_enums);
COMPILE_ASSERT(static_cast<uint32_t>(kSbKeyModifiersPointerButtonLeft) ==
                       system_window::InputEvent::kLeftButton &&
                   static_cast<uint32_t>(kSbKeyModifiersPointerButtonRight) ==
                       system_window::InputEvent::kRightButton &&
                   static_cast<uint32_t>(kSbKeyModifiersPointerButtonMiddle) ==
                       system_window::InputEvent::kMiddleButton &&
                   static_cast<uint32_t>(kSbKeyModifiersPointerButtonBack) ==
                       system_window::InputEvent::kBackButton &&
                   static_cast<uint32_t>(kSbKeyModifiersPointerButtonForward) ==
                       system_window::InputEvent::kForwardButton,
               Mismatched_modifier_enums);

void UpdateEventModifierInit(const system_window::InputEvent* input_event,
                             dom::EventModifierInit* event) {
  const uint32_t modifiers = input_event->modifiers();
  event->set_ctrl_key(modifiers & system_window::InputEvent::kCtrlKey);
  event->set_shift_key(modifiers & system_window::InputEvent::kShiftKey);
  event->set_alt_key(modifiers & system_window::InputEvent::kAltKey);
  event->set_meta_key(modifiers & system_window::InputEvent::kMetaKey);
}

void UpdateMouseEventInitButtons(const system_window::InputEvent* input_event,
                                 dom::MouseEventInit* event) {
  // The value of the button attribute MUST be as follows:
  //  https://www.w3.org/TR/uievents/#ref-for-dom-mouseevent-button-1
  switch (input_event->key_code()) {
    case kSbKeyMouse1:
      // 0 MUST indicate the primary button of the device (in general, the left
      // button or the only button on single-button devices, used to activate a
      // user interface control or select text) or the un-initialized value.
      event->set_button(0);
      break;
    case kSbKeyMouse2:
      // 1 MUST indicate the auxiliary button (in general, the middle button,
      // often combined with a mouse wheel).
      event->set_button(1);
      break;
    case kSbKeyMouse3:
      // 2 MUST indicate the secondary button (in general, the right button,
      // often used to display a context menu).
      event->set_button(2);
      break;
    default:
      break;
  }

  // The value of the buttons attribute MUST be as follows:
  //  https://www.w3.org/TR/uievents/#ref-for-dom-mouseevent-buttons-3

  // 0 MUST indicate no button is currently active.
  uint32 modifiers = input_event->modifiers();
  uint16 buttons = 0;
  if (modifiers & system_window::InputEvent::kLeftButton) {
    // 1 MUST indicate the primary button of the device (in general, the left
    // button or the only button on single-button devices, used to activate a
    // user interface control or select text).
    buttons |= 1;
  }
  if (modifiers & system_window::InputEvent::kRightButton) {
    // 2 MUST indicate the secondary button (in general, the right button, often
    // used to display a context menu), if present.
    buttons |= 2;
  }
  if (modifiers & system_window::InputEvent::kMiddleButton) {
    // 4 MUST indicate the auxiliary button (in general, the middle button,
    // often combined with a mouse wheel).
    buttons |= 4;
  }

  // The buttons attribute reflects the state of the mouse's buttons for any
  // MouseEvent object (while it is being dispatched).
  //   https://www.w3.org/TR/2016/WD-uievents-20160804/#ref-for-dom-mouseevent-buttons-2
  switch (input_event->type()) {
    case system_window::InputEvent::kTouchpadDown:
    case system_window::InputEvent::kTouchscreenDown:
    case system_window::InputEvent::kPointerDown:
      // For 'down' events, ensure that the buttons state includes the currently
      // reported button press.
      buttons |= 1 << event->button();
      break;
    case system_window::InputEvent::kTouchpadUp:
    case system_window::InputEvent::kTouchscreenUp:
    case system_window::InputEvent::kPointerUp:
      // For 'up' events, ensure that the buttons state excludes the currently
      // reported button press.
      buttons &= ~(1 << event->button());
      break;
    case system_window::InputEvent::kKeyDown:
    case system_window::InputEvent::kKeyUp:
    case system_window::InputEvent::kKeyMove:
    case system_window::InputEvent::kInput:
    case system_window::InputEvent::kPointerMove:
    case system_window::InputEvent::kTouchpadMove:
    case system_window::InputEvent::kTouchscreenMove:
    case system_window::InputEvent::kWheel:
      break;
  }

  event->set_buttons(buttons);
}

void UpdateMouseEventInit(const system_window::InputEvent* input_event,
                          dom::MouseEventInit* mouse_event) {
  UpdateEventModifierInit(input_event, mouse_event);
  UpdateMouseEventInitButtons(input_event, mouse_event);

  const math::PointF& position = input_event->position();
  mouse_event->set_screen_x(static_cast<float>(position.x()));
  mouse_event->set_screen_y(static_cast<float>(position.y()));
  mouse_event->set_client_x(static_cast<float>(position.x()));
  mouse_event->set_client_y(static_cast<float>(position.y()));
}

// Returns the value or the default_value when value is NaN.
float value_or(float value, float default_value) {
  return std::isnan(value) ? default_value : value;
}
}  // namespace

void InputDeviceManagerDesktop::HandleKeyboardEvent(
    bool is_key_down, const system_window::InputEvent* input_event,
    int key_code) {
  base::Token type =
      is_key_down ? base::Tokens::keydown() : base::Tokens::keyup();
  dom::KeyboardEvent::KeyLocationCode location =
      dom::KeyboardEvent::KeyCodeToKeyLocation(key_code);
  dom::KeyboardEventInit keyboard_event;
  UpdateEventInit(input_event, &keyboard_event);
  UpdateEventModifierInit(input_event, &keyboard_event);
  keyboard_event.set_location(location);
  keyboard_event.set_repeat(input_event->is_repeat());
  keyboard_event.set_char_code(key_code);
  keyboard_event.set_key_code(key_code);
  keypress_generator_filter_.HandleKeyboardEvent(type, keyboard_event);

  int32_t key_code_in_int32 = static_cast<int32_t>(key_code);
  overlay_info::OverlayInfoRegistry::Register("keydown", key_code_in_int32);
}

void InputDeviceManagerDesktop::HandlePointerEvent(
    base::Token type, const system_window::InputEvent* input_event) {
  dom::PointerEventInit pointer_event;
  UpdateEventInit(input_event, &pointer_event);
  UpdateMouseEventInit(input_event, &pointer_event);

  switch (input_event->type()) {
    case system_window::InputEvent::kTouchpadDown:
    case system_window::InputEvent::kTouchpadUp:
    case system_window::InputEvent::kTouchpadMove:
      pointer_event.set_pointer_type("touchpad");
      break;
    case system_window::InputEvent::kTouchscreenDown:
    case system_window::InputEvent::kTouchscreenUp:
    case system_window::InputEvent::kTouchscreenMove:
      pointer_event.set_pointer_type("touch");
      break;
    case system_window::InputEvent::kKeyDown:
    case system_window::InputEvent::kKeyUp:
    case system_window::InputEvent::kKeyMove:
    case system_window::InputEvent::kInput:
    case system_window::InputEvent::kPointerDown:
    case system_window::InputEvent::kPointerMove:
    case system_window::InputEvent::kPointerUp:
    case system_window::InputEvent::kWheel:
      pointer_event.set_pointer_type("mouse");
      break;
  }
  pointer_event.set_pointer_id(input_event->device_id());
  pointer_event.set_width(value_or(input_event->size().x(), 0.0f));
  pointer_event.set_height(value_or(input_event->size().y(), 0.0f));
  pointer_event.set_pressure(value_or(input_event->pressure(),
                                      input_event->modifiers() ? 0.5f : 0.0f));
  pointer_event.set_tilt_x(
      value_or(static_cast<float>(input_event->tilt().x()), 0.0f));
  pointer_event.set_tilt_y(
      value_or(static_cast<float>(input_event->tilt().y()), 0.0f));
  pointer_event.set_is_primary(true);
  pointer_event_callback_.Run(type, pointer_event);
}

void InputDeviceManagerDesktop::HandleWheelEvent(
    const system_window::InputEvent* input_event) {
  base::Token type = base::Tokens::wheel();
  dom::WheelEventInit wheel_event;
  UpdateEventInit(input_event, &wheel_event);
  UpdateMouseEventInit(input_event, &wheel_event);

  wheel_event.set_delta_x(input_event->delta().x());
  wheel_event.set_delta_y(input_event->delta().y());
  wheel_event.set_delta_z(0);
  wheel_event.set_delta_mode(dom::WheelEvent::kDomDeltaLine);

  wheel_event_callback_.Run(type, wheel_event);
}

void InputDeviceManagerDesktop::HandleInputEvent(
    const system_window::InputEvent* event) {
  // Note: we currently treat all dom::InputEvents as input (never beforeinput).
  base::Token type = base::Tokens::input();

  dom::InputEventInit input_event;
  UpdateEventInit(event, &input_event);
  input_event.set_data(event->input_text());
  input_event.set_is_composing(event->is_composing());
  input_event_callback_.Run(type, input_event);
}

void InputDeviceManagerDesktop::HandleSystemWindowInputEvent(
    const base::Event* event) {
  // The user has pressed a key on the keyboard.
  const system_window::InputEvent* input_event =
      base::polymorphic_downcast<const system_window::InputEvent*>(event);
  SB_DCHECK(input_event);
  int key_code = input_event->key_code();

  switch (input_event->type()) {
    case system_window::InputEvent::kKeyDown:
      HandleKeyboardEvent(true, input_event, key_code);
      break;
    case system_window::InputEvent::kKeyUp:
      HandleKeyboardEvent(false, input_event, key_code);
      break;
    case system_window::InputEvent::kPointerDown:
    case system_window::InputEvent::kPointerUp: {
      if ((kSbKeyBrowserBack == key_code) ||
          (kSbKeyBrowserForward == key_code) || (kSbKeyMouse2 == key_code)) {
        // For consistency with behavior on current browsers, the 'Forward' and
        // 'Back' mouse buttons are reported as keypress input for the 'Forward'
        // and 'Back' navigation keys, not as Pointer Events for the X1 and X2
        // buttons.

        if (kSbKeyMouse2 == key_code) {
          // Temporarily Report middle button presses as the enter key.
          key_code = kSbKeyReturn;
        }
        HandleKeyboardEvent(
            input_event->type() == system_window::InputEvent::kPointerDown,
            input_event, key_code);
      } else {
        base::Token type =
            input_event->type() == system_window::InputEvent::kPointerDown
                ? base::Tokens::pointerdown()
                : base::Tokens::pointerup();
        HandlePointerEvent(type, input_event);
      }
      break;
    }
    case system_window::InputEvent::kPointerMove:
    case system_window::InputEvent::kTouchpadMove:
    case system_window::InputEvent::kTouchscreenMove: {
      HandlePointerEvent(base::Tokens::pointermove(), input_event);
      break;
    }
    case system_window::InputEvent::kTouchpadDown:
    case system_window::InputEvent::kTouchscreenDown:
      HandlePointerEvent(base::Tokens::pointerdown(), input_event);
      break;
    case system_window::InputEvent::kTouchpadUp:
    case system_window::InputEvent::kTouchscreenUp:
      HandlePointerEvent(base::Tokens::pointerup(), input_event);
      break;
    case system_window::InputEvent::kWheel:
      HandleWheelEvent(input_event);
      break;
    case system_window::InputEvent::kInput:
      HandleInputEvent(input_event);
      break;
    case system_window::InputEvent::kKeyMove:
      break;
  }

  InputPollerImpl* input_poller_impl =
      static_cast<InputPollerImpl*>(input_poller_.get());
  input_poller_impl->UpdateInputEvent(input_event);
}

}  // namespace input
}  // namespace cobalt
