// 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 "ash/shell_test_api.h"

#include <utility>

#include "ash/accelerators/accelerator_commands.h"
#include "ash/keyboard/ash_keyboard_controller.h"
#include "ash/root_window_controller.h"
#include "ash/shell.h"
#include "ash/system/power/backlights_forced_off_setter.h"
#include "ash/system/power/power_button_controller.h"
#include "ash/wm/overview/overview_controller.h"
#include "ash/wm/splitview/split_view_controller.h"
#include "ash/wm/tablet_mode/tablet_mode_controller.h"
#include "ash/ws/window_service_owner.h"
#include "components/prefs/testing_pref_service.h"
#include "mojo/public/cpp/bindings/strong_binding.h"
#include "services/ws/window_service.h"
#include "services/ws/window_tree.h"
#include "ui/events/gesture_detection/gesture_configuration.h"

namespace ash {

ShellTestApi::ShellTestApi() : ShellTestApi(Shell::Get()) {}

ShellTestApi::ShellTestApi(Shell* shell) : shell_(shell) {}

// static
void ShellTestApi::BindRequest(mojom::ShellTestApiRequest request) {
  mojo::MakeStrongBinding(std::make_unique<ShellTestApi>(), std::move(request));
}

MessageCenterController* ShellTestApi::message_center_controller() {
  return shell_->message_center_controller_.get();
}

SystemGestureEventFilter* ShellTestApi::system_gesture_event_filter() {
  return shell_->system_gesture_filter_.get();
}

WorkspaceController* ShellTestApi::workspace_controller() {
  return shell_->GetPrimaryRootWindowController()->workspace_controller();
}

ScreenPositionController* ShellTestApi::screen_position_controller() {
  return shell_->screen_position_controller_.get();
}

NativeCursorManagerAsh* ShellTestApi::native_cursor_manager_ash() {
  return shell_->native_cursor_manager_;
}

DragDropController* ShellTestApi::drag_drop_controller() {
  return shell_->drag_drop_controller_.get();
}

PowerPrefs* ShellTestApi::power_prefs() {
  return shell_->power_prefs_.get();
}

void ShellTestApi::OnLocalStatePrefServiceInitialized(
    std::unique_ptr<PrefService> pref_service) {
  shell_->OnLocalStatePrefServiceInitialized(std::move(pref_service));
}

void ShellTestApi::ResetPowerButtonControllerForTest() {
  shell_->backlights_forced_off_setter_->ResetForTest();
  shell_->power_button_controller_ = std::make_unique<PowerButtonController>(
      shell_->backlights_forced_off_setter_.get());
}

void ShellTestApi::SimulateModalWindowOpenForTest(bool modal_window_open) {
  shell_->simulate_modal_window_open_for_test_ = modal_window_open;
}

void ShellTestApi::IsSystemModalWindowOpen(IsSystemModalWindowOpenCallback cb) {
  std::move(cb).Run(Shell::IsSystemModalWindowOpen());
}

void ShellTestApi::EnableTabletModeWindowManager(bool enable) {
  shell_->tablet_mode_controller()->EnableTabletModeWindowManager(enable);
}

void ShellTestApi::EnableVirtualKeyboard(EnableVirtualKeyboardCallback cb) {
  // TODO(https://crbug.com/845780): The callers to this function have already
  // enabled the virtual keyboard. For some reason, in those tests, the virtual
  // keyboard requires a rebuild. Remove this function once we no longer need a
  // rebuild.
  shell_->ash_keyboard_controller()->RebuildKeyboardIfEnabled();
  std::move(cb).Run();
}

void ShellTestApi::SnapWindowInSplitView(const std::string& client_name,
                                         ws::Id window_id,
                                         bool left,
                                         SnapWindowInSplitViewCallback cb) {
  auto* window_service = shell_->window_service_owner()->window_service();
  aura::Window* window = nullptr;
  for (ws::WindowTree* window_tree : window_service->window_trees()) {
    if (client_name == window_tree->client_name()) {
      window = window_tree->GetWindowByTransportId(window_id);
      break;
    }
  }
  DCHECK(window);
  shell_->split_view_controller()->SnapWindow(
      window,
      left ? ash::SplitViewController::LEFT : ash::SplitViewController::RIGHT);
  shell_->split_view_controller()->FlushForTesting();
  std::move(cb).Run();
}

void ShellTestApi::ToggleFullscreen(ToggleFullscreenCallback cb) {
  ash::accelerators::ToggleFullscreen();
  std::move(cb).Run();
}

void ShellTestApi::ToggleOverviewMode(ToggleOverviewModeCallback cb) {
  shell_->overview_controller()->ToggleOverview();
  std::move(cb).Run();
}

void ShellTestApi::AddRemoveDisplay() {
  shell_->display_manager()->AddRemoveDisplay();
}

void ShellTestApi::SetMinFlingVelocity(float velocity) {
  ui::GestureConfiguration::GetInstance()->set_min_fling_velocity(velocity);
}

}  // namespace ash
