// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "remoting/protocol/input_event_tracker.h"

#include "base/logging.h"
#include "remoting/proto/event.pb.h"

namespace remoting {
namespace protocol {

InputEventTracker::InputEventTracker() = default;

InputEventTracker::InputEventTracker(InputStub* input_stub)
    : input_stub_(input_stub) {
}

InputEventTracker::~InputEventTracker() = default;

bool InputEventTracker::IsKeyPressed(ui::DomCode usb_keycode) const {
  return pressed_keys_.find(usb_keycode) != pressed_keys_.end();
}

int InputEventTracker::PressedKeyCount() const {
  return pressed_keys_.size();
}

void InputEventTracker::ReleaseAll() {
  DCHECK(input_stub_);

  // Release all pressed keys.
  for (auto keycode : pressed_keys_) {
    KeyEvent event;
    event.set_pressed(false);
    event.set_usb_keycode(static_cast<uint32_t>(keycode));
    input_stub_->InjectKeyEvent(event);
  }
  pressed_keys_.clear();

  // Release all mouse buttons.
  for (int i = MouseEvent::BUTTON_UNDEFINED + 1;
       i < MouseEvent::BUTTON_MAX; ++i) {
    if (mouse_button_state_ & (1 << (i - 1))) {
      MouseEvent mouse;

      // TODO(wez): EventInjectors should cope with positionless events by
      // using the current cursor position, and we wouldn't set position here.
      mouse.set_x(mouse_pos_.x());
      mouse.set_y(mouse_pos_.y());

      mouse.set_button((MouseEvent::MouseButton)i);
      mouse.set_button_down(false);
      input_stub_->InjectMouseEvent(mouse);
    }
  }
  mouse_button_state_ = 0;

  // Cancel all active touch points.
  if (!touch_point_ids_.empty()) {
    TouchEvent cancel_all_touch_event;
    cancel_all_touch_event.set_event_type(TouchEvent::TOUCH_POINT_CANCEL);
    for (uint32_t touch_point_id : touch_point_ids_) {
      TouchEventPoint* point = cancel_all_touch_event.add_touch_points();
      point->set_id(touch_point_id);
    }
    input_stub_->InjectTouchEvent(cancel_all_touch_event);
    touch_point_ids_.clear();
  }
  DCHECK(touch_point_ids_.empty());
}

void InputEventTracker::ReleaseAllIfModifiersStuck(bool alt_expected,
                                                   bool ctrl_expected,
                                                   bool os_expected,
                                                   bool shift_expected) {
  bool alt_down =
      pressed_keys_.find(ui::DomCode::ALT_LEFT) != pressed_keys_.end() ||
      pressed_keys_.find(ui::DomCode::ALT_RIGHT) != pressed_keys_.end();
  bool ctrl_down =
      pressed_keys_.find(ui::DomCode::CONTROL_LEFT) != pressed_keys_.end() ||
      pressed_keys_.find(ui::DomCode::CONTROL_RIGHT) != pressed_keys_.end();
  bool os_down =
      pressed_keys_.find(ui::DomCode::META_LEFT) != pressed_keys_.end() ||
      pressed_keys_.find(ui::DomCode::META_RIGHT) != pressed_keys_.end();
  bool shift_down =
      pressed_keys_.find(ui::DomCode::SHIFT_LEFT) != pressed_keys_.end() ||
      pressed_keys_.find(ui::DomCode::SHIFT_RIGHT) != pressed_keys_.end();

  if ((alt_down && !alt_expected) || (ctrl_down && !ctrl_expected) ||
      (os_down && !os_expected) || (shift_down && !shift_expected)) {
    ReleaseAll();
  }
}

void InputEventTracker::InjectKeyEvent(const KeyEvent& event) {
  DCHECK(input_stub_);

  // We don't need to track the keyboard lock states of key down events.
  // Pressed keys will be released with |lock_states| set to 0.
  // The lock states of auto generated key up events don't matter as long as
  // we release all the pressed keys at blurring/disconnection time.
  if (event.has_pressed()) {
    if (event.has_usb_keycode()) {
      if (event.pressed()) {
        pressed_keys_.insert(static_cast<ui::DomCode>(event.usb_keycode()));
      } else {
        pressed_keys_.erase(static_cast<ui::DomCode>(event.usb_keycode()));
      }
    }
  }
  input_stub_->InjectKeyEvent(event);
}

void InputEventTracker::InjectTextEvent(const TextEvent& event) {
  DCHECK(input_stub_);
  input_stub_->InjectTextEvent(event);
}

void InputEventTracker::InjectMouseEvent(const MouseEvent& event) {
  DCHECK(input_stub_);

  if (event.has_x() && event.has_y()) {
    mouse_pos_ = webrtc::DesktopVector(event.x(), event.y());
  }
  if (event.has_button() && event.has_button_down()) {
    // Button values are defined in remoting/proto/event.proto.
    if (event.button() >= 1 && event.button() < MouseEvent::BUTTON_MAX) {
      uint32_t button_change = 1 << (event.button() - 1);
      if (event.button_down()) {
        mouse_button_state_ |= button_change;
      } else {
        mouse_button_state_ &= ~button_change;
      }
    }
  }
  input_stub_->InjectMouseEvent(event);
}

void InputEventTracker::InjectTouchEvent(const TouchEvent& event) {
  DCHECK(input_stub_);
  // We only need the IDs to cancel all touch points in ReleaseAll(). Other
  // fields do not have to be tracked here as long as the host keeps track of
  // them.
  switch (event.event_type()) {
    case TouchEvent::TOUCH_POINT_START:
      for (const TouchEventPoint& touch_point : event.touch_points()) {
        DCHECK(touch_point_ids_.find(touch_point.id()) ==
               touch_point_ids_.end());
        touch_point_ids_.insert(touch_point.id());
      }
      break;
    case TouchEvent::TOUCH_POINT_END:
    case TouchEvent::TOUCH_POINT_CANCEL:
      for (const TouchEventPoint& touch_point : event.touch_points()) {
        DCHECK(touch_point_ids_.find(touch_point.id()) !=
               touch_point_ids_.end());
        touch_point_ids_.erase(touch_point.id());
      }
      break;
    default:
      break;
  }
  input_stub_->InjectTouchEvent(event);
}

}  // namespace protocol
}  // namespace remoting
