#include "content/test/mock_widget_input_handler.h"

#include "base/run_loop.h"
#include "testing/gtest/include/gtest/gtest.h"

using base::TimeDelta;
using blink::WebGestureEvent;
using blink::WebInputEvent;
using blink::WebMouseEvent;
using blink::WebMouseWheelEvent;
using blink::WebTouchEvent;
using blink::WebTouchPoint;

namespace content {

MockWidgetInputHandler::MockWidgetInputHandler() : binding_(this) {}

MockWidgetInputHandler::MockWidgetInputHandler(
    mojom::WidgetInputHandlerRequest request,
    mojom::WidgetInputHandlerHostPtr host)
    : binding_(this, std::move(request)), host_(std::move(host)) {}

MockWidgetInputHandler::~MockWidgetInputHandler() {}

void MockWidgetInputHandler::SetFocus(bool focused) {
  dispatched_messages_.emplace_back(
      std::make_unique<DispatchedFocusMessage>(focused));
}

void MockWidgetInputHandler::MouseCaptureLost() {
  dispatched_messages_.emplace_back(
      std::make_unique<DispatchedMessage>("MouseCaptureLost"));
}

void MockWidgetInputHandler::SetEditCommandsForNextKeyEvent(
    const std::vector<content::EditCommand>& commands) {
  dispatched_messages_.emplace_back(
      std::make_unique<DispatchedEditCommandMessage>(commands));
}

void MockWidgetInputHandler::CursorVisibilityChanged(bool visible) {
  dispatched_messages_.emplace_back(
      std::make_unique<DispatchedMessage>("CursorVisibilityChanged"));
}

void MockWidgetInputHandler::ImeSetComposition(
    const base::string16& text,
    const std::vector<ui::ImeTextSpan>& ime_text_spans,
    const gfx::Range& range,
    int32_t start,
    int32_t end) {
  dispatched_messages_.emplace_back(std::make_unique<DispatchedIMEMessage>(
      "SetComposition", text, ime_text_spans, range, start, end));
}

void MockWidgetInputHandler::ImeCommitText(
    const base::string16& text,
    const std::vector<ui::ImeTextSpan>& ime_text_spans,
    const gfx::Range& range,
    int32_t relative_cursor_position) {
  dispatched_messages_.emplace_back(std::make_unique<DispatchedIMEMessage>(
      "CommitText", text, ime_text_spans, range, relative_cursor_position,
      relative_cursor_position));
}

void MockWidgetInputHandler::ImeFinishComposingText(bool keep_selection) {
  dispatched_messages_.emplace_back(
      std::make_unique<DispatchedMessage>("FinishComposingText"));
}

void MockWidgetInputHandler::RequestTextInputStateUpdate() {
  dispatched_messages_.emplace_back(
      std::make_unique<DispatchedMessage>("RequestTextInputStateUpdate"));
}

void MockWidgetInputHandler::RequestCompositionUpdates(bool immediate_request,
                                                       bool monitor_request) {
  dispatched_messages_.emplace_back(
      std::make_unique<DispatchedRequestCompositionUpdatesMessage>(
          immediate_request, monitor_request));
}

void MockWidgetInputHandler::DispatchEvent(
    std::unique_ptr<content::InputEvent> event,
    DispatchEventCallback callback) {
  dispatched_messages_.emplace_back(std::make_unique<DispatchedEventMessage>(
      std::move(event), std::move(callback)));
}

void MockWidgetInputHandler::DispatchNonBlockingEvent(
    std::unique_ptr<content::InputEvent> event) {
  dispatched_messages_.emplace_back(std::make_unique<DispatchedEventMessage>(
      std::move(event), DispatchEventCallback()));
}

MockWidgetInputHandler::MessageVector
MockWidgetInputHandler::GetAndResetDispatchedMessages() {
  MessageVector dispatched_events;
  dispatched_messages_.swap(dispatched_events);
  return dispatched_events;
}

void MockWidgetInputHandler::AttachSynchronousCompositor(
    mojom::SynchronousCompositorControlHostPtr control_host,
    mojom::SynchronousCompositorHostAssociatedPtrInfo host,
    mojom::SynchronousCompositorAssociatedRequest compositor_request) {}

MockWidgetInputHandler::DispatchedMessage::DispatchedMessage(
    const std::string& name)
    : name_(name) {}

MockWidgetInputHandler::DispatchedMessage::~DispatchedMessage() {}

MockWidgetInputHandler::DispatchedEditCommandMessage*
MockWidgetInputHandler::DispatchedMessage::ToEditCommand() {
  return nullptr;
}
MockWidgetInputHandler::DispatchedEventMessage*
MockWidgetInputHandler::DispatchedMessage::ToEvent() {
  return nullptr;
}
MockWidgetInputHandler::DispatchedFocusMessage*
MockWidgetInputHandler::DispatchedMessage::ToFocus() {
  return nullptr;
}
MockWidgetInputHandler::DispatchedIMEMessage*
MockWidgetInputHandler::DispatchedMessage::ToIME() {
  return nullptr;
}

MockWidgetInputHandler::DispatchedRequestCompositionUpdatesMessage*
MockWidgetInputHandler::DispatchedMessage::ToRequestCompositionUpdates() {
  return nullptr;
}

MockWidgetInputHandler::DispatchedIMEMessage::DispatchedIMEMessage(
    const std::string& name,
    const base::string16& text,
    const std::vector<ui::ImeTextSpan>& text_spans,
    const gfx::Range& range,
    int32_t start,
    int32_t end)
    : DispatchedMessage(name),
      text_(text),
      text_spans_(text_spans),
      range_(range),
      start_(start),
      end_(end) {}

MockWidgetInputHandler::DispatchedIMEMessage::~DispatchedIMEMessage() {}

MockWidgetInputHandler::DispatchedIMEMessage*
MockWidgetInputHandler::DispatchedIMEMessage::ToIME() {
  return this;
}

bool MockWidgetInputHandler::DispatchedIMEMessage::Matches(
    const base::string16& text,
    const std::vector<ui::ImeTextSpan>& ime_text_spans,
    const gfx::Range& range,
    int32_t start,
    int32_t end) const {
  return text_ == text && text_spans_ == ime_text_spans && range_ == range &&
         start_ == start && end_ == end;
}

MockWidgetInputHandler::DispatchedEditCommandMessage::
    DispatchedEditCommandMessage(
        const std::vector<content::EditCommand>& commands)
    : DispatchedMessage("SetEditComamnds"), commands_(commands) {}

MockWidgetInputHandler::DispatchedEditCommandMessage::
    ~DispatchedEditCommandMessage() {}
MockWidgetInputHandler::DispatchedEditCommandMessage*
MockWidgetInputHandler::DispatchedEditCommandMessage::ToEditCommand() {
  return this;
}

const std::vector<content::EditCommand>&
MockWidgetInputHandler::DispatchedEditCommandMessage::Commands() const {
  return commands_;
}

MockWidgetInputHandler::DispatchedEventMessage::DispatchedEventMessage(
    std::unique_ptr<content::InputEvent> event,
    DispatchEventCallback callback)
    : DispatchedMessage(
          blink::WebInputEvent::GetName(event->web_event->GetType())),
      event_(std::move(event)),
      callback_(std::move(callback)) {}

MockWidgetInputHandler::DispatchedEventMessage::~DispatchedEventMessage() {
  if (callback_) {
    std::move(callback_).Run(InputEventAckSource::UNKNOWN, ui::LatencyInfo(),
                             INPUT_EVENT_ACK_STATE_NOT_CONSUMED, base::nullopt,
                             base::nullopt);
    base::RunLoop().RunUntilIdle();
  }
}

MockWidgetInputHandler::DispatchedEventMessage*
MockWidgetInputHandler::DispatchedEventMessage::ToEvent() {
  return this;
}

void MockWidgetInputHandler::DispatchedEventMessage::CallCallback(
    InputEventAckState state) {
  if (callback_) {
    std::move(callback_).Run(InputEventAckSource::MAIN_THREAD,
                             ui::LatencyInfo(), state, base::nullopt,
                             base::nullopt);
    base::RunLoop().RunUntilIdle();
  }
}

void MockWidgetInputHandler::DispatchedEventMessage::CallCallback(
    InputEventAckSource source,
    const ui::LatencyInfo& latency_info,
    InputEventAckState state,
    const base::Optional<ui::DidOverscrollParams>& overscroll,
    const base::Optional<cc::TouchAction>& touch_action) {
  if (callback_) {
    std::move(callback_).Run(source, latency_info, state, overscroll,
                             touch_action);
    base::RunLoop().RunUntilIdle();
  }
}

bool MockWidgetInputHandler::DispatchedEventMessage::HasCallback() const {
  return !!callback_;
}

const content::InputEvent*
MockWidgetInputHandler::DispatchedEventMessage::Event() const {
  return event_.get();
}

MockWidgetInputHandler::DispatchedRequestCompositionUpdatesMessage::
    DispatchedRequestCompositionUpdatesMessage(bool immediate_request,
                                               bool monitor_request)
    : DispatchedMessage("RequestCompositionUpdates"),
      immediate_request_(immediate_request),
      monitor_request_(monitor_request) {}

MockWidgetInputHandler::DispatchedRequestCompositionUpdatesMessage::
    ~DispatchedRequestCompositionUpdatesMessage() {}

MockWidgetInputHandler::DispatchedRequestCompositionUpdatesMessage*
MockWidgetInputHandler::DispatchedRequestCompositionUpdatesMessage::
    ToRequestCompositionUpdates() {
  return this;
}

MockWidgetInputHandler::DispatchedFocusMessage::DispatchedFocusMessage(
    bool focused)
    : DispatchedMessage("SetFocus"), focused_(focused) {}

MockWidgetInputHandler::DispatchedFocusMessage::~DispatchedFocusMessage() {}

MockWidgetInputHandler::DispatchedFocusMessage*
MockWidgetInputHandler::DispatchedFocusMessage::ToFocus() {
  return this;
}

}
// Copyright 2017 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 "content/test/mock_widget_input_handler.h"

#include "base/run_loop.h"
#include "testing/gtest/include/gtest/gtest.h"

using base::TimeDelta;
using blink::WebGestureEvent;
using blink::WebInputEvent;
using blink::WebMouseEvent;
using blink::WebMouseWheelEvent;
using blink::WebTouchEvent;
using blink::WebTouchPoint;

namespace content {

MockWidgetInputHandler::MockWidgetInputHandler() : binding_(this) {}

MockWidgetInputHandler::MockWidgetInputHandler(
    mojom::WidgetInputHandlerRequest request,
    mojom::WidgetInputHandlerHostPtr host)
    : binding_(this, std::move(request)), host_(std::move(host)) {}

MockWidgetInputHandler::~MockWidgetInputHandler() {}

void MockWidgetInputHandler::SetFocus(bool focused) {
  dispatched_messages_.emplace_back(
      std::make_unique<DispatchedFocusMessage>(focused));
}

void MockWidgetInputHandler::MouseCaptureLost() {
  dispatched_messages_.emplace_back(
      std::make_unique<DispatchedMessage>("MouseCaptureLost"));
}

void MockWidgetInputHandler::SetEditCommandsForNextKeyEvent(
    const std::vector<content::EditCommand>& commands) {
  dispatched_messages_.emplace_back(
      std::make_unique<DispatchedEditCommandMessage>(commands));
}

void MockWidgetInputHandler::CursorVisibilityChanged(bool visible) {
  dispatched_messages_.emplace_back(
      std::make_unique<DispatchedMessage>("CursorVisibilityChanged"));
}

void MockWidgetInputHandler::ImeSetComposition(
    const base::string16& text,
    const std::vector<ui::ImeTextSpan>& ime_text_spans,
    const gfx::Range& range,
    int32_t start,
    int32_t end) {
  dispatched_messages_.emplace_back(std::make_unique<DispatchedIMEMessage>(
      "SetComposition", text, ime_text_spans, range, start, end));
}

void MockWidgetInputHandler::ImeCommitText(
    const base::string16& text,
    const std::vector<ui::ImeTextSpan>& ime_text_spans,
    const gfx::Range& range,
    int32_t relative_cursor_position) {
  dispatched_messages_.emplace_back(std::make_unique<DispatchedIMEMessage>(
      "CommitText", text, ime_text_spans, range, relative_cursor_position,
      relative_cursor_position));
}

void MockWidgetInputHandler::ImeFinishComposingText(bool keep_selection) {
  dispatched_messages_.emplace_back(
      std::make_unique<DispatchedMessage>("FinishComposingText"));
}

void MockWidgetInputHandler::RequestTextInputStateUpdate() {
  dispatched_messages_.emplace_back(
      std::make_unique<DispatchedMessage>("RequestTextInputStateUpdate"));
}

void MockWidgetInputHandler::RequestCompositionUpdates(bool immediate_request,
                                                       bool monitor_request) {
  dispatched_messages_.emplace_back(
      std::make_unique<DispatchedRequestCompositionUpdatesMessage>(
          immediate_request, monitor_request));
}

void MockWidgetInputHandler::DispatchEvent(
    std::unique_ptr<content::InputEvent> event,
    DispatchEventCallback callback) {
  dispatched_messages_.emplace_back(std::make_unique<DispatchedEventMessage>(
      std::move(event), std::move(callback)));
}

void MockWidgetInputHandler::DispatchNonBlockingEvent(
    std::unique_ptr<content::InputEvent> event) {
  dispatched_messages_.emplace_back(std::make_unique<DispatchedEventMessage>(
      std::move(event), DispatchEventCallback()));
}

MockWidgetInputHandler::MessageVector
MockWidgetInputHandler::GetAndResetDispatchedMessages() {
  MessageVector dispatched_events;
  dispatched_messages_.swap(dispatched_events);
  return dispatched_events;
}

void MockWidgetInputHandler::AttachSynchronousCompositor(
    mojom::SynchronousCompositorControlHostPtr control_host,
    mojom::SynchronousCompositorHostAssociatedPtrInfo host,
    mojom::SynchronousCompositorAssociatedRequest compositor_request) {}

MockWidgetInputHandler::DispatchedMessage::DispatchedMessage(
    const std::string& name)
    : name_(name) {}

MockWidgetInputHandler::DispatchedMessage::~DispatchedMessage() {}

MockWidgetInputHandler::DispatchedEditCommandMessage*
MockWidgetInputHandler::DispatchedMessage::ToEditCommand() {
  return nullptr;
}
MockWidgetInputHandler::DispatchedEventMessage*
MockWidgetInputHandler::DispatchedMessage::ToEvent() {
  return nullptr;
}
MockWidgetInputHandler::DispatchedFocusMessage*
MockWidgetInputHandler::DispatchedMessage::ToFocus() {
  return nullptr;
}
MockWidgetInputHandler::DispatchedIMEMessage*
MockWidgetInputHandler::DispatchedMessage::ToIME() {
  return nullptr;
}

MockWidgetInputHandler::DispatchedRequestCompositionUpdatesMessage*
MockWidgetInputHandler::DispatchedMessage::ToRequestCompositionUpdates() {
  return nullptr;
}

MockWidgetInputHandler::DispatchedIMEMessage::DispatchedIMEMessage(
    const std::string& name,
    const base::string16& text,
    const std::vector<ui::ImeTextSpan>& text_spans,
    const gfx::Range& range,
    int32_t start,
    int32_t end)
    : DispatchedMessage(name),
      text_(text),
      text_spans_(text_spans),
      range_(range),
      start_(start),
      end_(end) {}

MockWidgetInputHandler::DispatchedIMEMessage::~DispatchedIMEMessage() {}

MockWidgetInputHandler::DispatchedIMEMessage*
MockWidgetInputHandler::DispatchedIMEMessage::ToIME() {
  return this;
}

bool MockWidgetInputHandler::DispatchedIMEMessage::Matches(
    const base::string16& text,
    const std::vector<ui::ImeTextSpan>& ime_text_spans,
    const gfx::Range& range,
    int32_t start,
    int32_t end) const {
  return text_ == text && text_spans_ == ime_text_spans && range_ == range &&
         start_ == start && end_ == end;
}

MockWidgetInputHandler::DispatchedEditCommandMessage::
    DispatchedEditCommandMessage(
        const std::vector<content::EditCommand>& commands)
    : DispatchedMessage("SetEditComamnds"), commands_(commands) {}

MockWidgetInputHandler::DispatchedEditCommandMessage::
    ~DispatchedEditCommandMessage() {}
MockWidgetInputHandler::DispatchedEditCommandMessage*
MockWidgetInputHandler::DispatchedEditCommandMessage::ToEditCommand() {
  return this;
}

const std::vector<content::EditCommand>&
MockWidgetInputHandler::DispatchedEditCommandMessage::Commands() const {
  return commands_;
}

MockWidgetInputHandler::DispatchedEventMessage::DispatchedEventMessage(
    std::unique_ptr<content::InputEvent> event,
    DispatchEventCallback callback)
    : DispatchedMessage(
          blink::WebInputEvent::GetName(event->web_event->GetType())),
      event_(std::move(event)),
      callback_(std::move(callback)) {}

MockWidgetInputHandler::DispatchedEventMessage::~DispatchedEventMessage() {
  if (callback_) {
    std::move(callback_).Run(InputEventAckSource::UNKNOWN, ui::LatencyInfo(),
                             INPUT_EVENT_ACK_STATE_NOT_CONSUMED, base::nullopt,
                             base::nullopt);
    base::RunLoop().RunUntilIdle();
  }
}

MockWidgetInputHandler::DispatchedEventMessage*
MockWidgetInputHandler::DispatchedEventMessage::ToEvent() {
  return this;
}

void MockWidgetInputHandler::DispatchedEventMessage::CallCallback(
    InputEventAckState state) {
  if (callback_) {
    std::move(callback_).Run(InputEventAckSource::MAIN_THREAD,
                             ui::LatencyInfo(), state, base::nullopt,
                             base::nullopt);
    base::RunLoop().RunUntilIdle();
  }
}

void MockWidgetInputHandler::DispatchedEventMessage::CallCallback(
    InputEventAckSource source,
    const ui::LatencyInfo& latency_info,
    InputEventAckState state,
    const base::Optional<ui::DidOverscrollParams>& overscroll,
    const base::Optional<cc::TouchAction>& touch_action) {
  if (callback_) {
    std::move(callback_).Run(source, latency_info, state, overscroll,
                             touch_action);
    base::RunLoop().RunUntilIdle();
  }
}

bool MockWidgetInputHandler::DispatchedEventMessage::HasCallback() const {
  return !!callback_;
}

const content::InputEvent*
MockWidgetInputHandler::DispatchedEventMessage::Event() const {
  return event_.get();
}

MockWidgetInputHandler::DispatchedRequestCompositionUpdatesMessage::
    DispatchedRequestCompositionUpdatesMessage(bool immediate_request,
                                               bool monitor_request)
    : DispatchedMessage("RequestCompositionUpdates"),
      immediate_request_(immediate_request),
      monitor_request_(monitor_request) {}

MockWidgetInputHandler::DispatchedRequestCompositionUpdatesMessage::
    ~DispatchedRequestCompositionUpdatesMessage() {}

MockWidgetInputHandler::DispatchedRequestCompositionUpdatesMessage*
MockWidgetInputHandler::DispatchedRequestCompositionUpdatesMessage::
    ToRequestCompositionUpdates() {
  return this;
}

MockWidgetInputHandler::DispatchedFocusMessage::DispatchedFocusMessage(
    bool focused)
    : DispatchedMessage("SetFocus"), focused_(focused) {}

MockWidgetInputHandler::DispatchedFocusMessage::~DispatchedFocusMessage() {}

MockWidgetInputHandler::DispatchedFocusMessage*
MockWidgetInputHandler::DispatchedFocusMessage::ToFocus() {
  return this;
}

}  // namespace content
