// Copyright 2013 The Flutter 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 "flutter/shell/platform/windows/game_pad_cursor_winuwp.h"
#include "game_pad_cursor_winuwp.h"

namespace flutter {

static constexpr int32_t kDefaultPointerDeviceId = 0;

GamepadCursorWinUWP::GamepadCursorWinUWP(
    WindowBindingHandlerDelegate* view,
    DisplayHelperWinUWP* displayhelper,
    winrt::Windows::UI::Core::CoreWindow const& window,
    winrt::Windows::UI::Composition::Compositor const& compositor,
    winrt::Windows::UI::Composition::VisualCollection const& rootcollection) {
  window_ = window;
  root_collection_ = rootcollection;
  binding_handler_delegate_ = view;
  display_helper_ = displayhelper;
  compositor_ = compositor;
  cursor_visual_ = CreateCursorVisual();
  ConfigureGamepad();
}

void GamepadCursorWinUWP::StartGamepadTimer() {
  winrt::Windows::UI::Core::CoreDispatcher dispatcher = window_.Dispatcher();

  dispatcher.RunAsync(
      winrt::Windows::UI::Core::CoreDispatcherPriority::Normal,
      [this, dispatcher]() {
        auto queue =
            winrt::Windows::System::DispatcherQueue::GetForCurrentThread();

        if (cursor_move_timer_ == nullptr) {
          cursor_move_timer_ = queue.CreateTimer();
          cursor_move_timer_.Interval(
              std::chrono::milliseconds(kNormalPollingFrequency));
          cursor_move_timer_.Tick(
              [=](winrt::Windows::System::DispatcherQueueTimer timer,
                  winrt::Windows::Foundation::IInspectable const&) {
                game_pad_->Process();
              });
          cursor_move_timer_.Start();
        }
      });
}

void GamepadCursorWinUWP::StopGamepadTimer() {
  winrt::Windows::UI::Core::CoreDispatcher dispatcher = window_.Dispatcher();

  dispatcher.RunAsync(winrt::Windows::UI::Core::CoreDispatcherPriority::Normal,
                      [this, dispatcher]() {
                        if (cursor_move_timer_ != nullptr) {
                          cursor_move_timer_.Stop();
                          cursor_move_timer_ = nullptr;
                        }
                      });
}

void GamepadCursorWinUWP::ConfigureGamepad() {
  GamepadDualAxisCallback leftStick = [=](double x, double y) {
    OnGamepadLeftStickMoved(x, y);
  };

  GamepadDualAxisCallback rightStick = [=](double x, double y) {
    OnGamepadRightStickMoved(x, y);
  };

  GamepadButtonCallback pressedcallback =
      [=](winrt::Windows::Gaming::Input::GamepadButtons buttons) {
        OnGamepadButtonPressed(buttons);
      };

  GamepadButtonCallback releasedcallback =
      [=](winrt::Windows::Gaming::Input::GamepadButtons buttons) {
        OnGamepadButtonReleased(buttons);
      };
  GamepadAddedRemovedCallback changed = [=]() {
    OnGamepadControllersChanged();
  };

  game_pad_ = std::make_unique<GamepadWinUWP>(leftStick, rightStick, nullptr,
                                              nullptr, pressedcallback,
                                              releasedcallback, changed);
  game_pad_->Initialize();

  SetCursorTimeout();
}

void GamepadCursorWinUWP::SetCursorTimeout() {
  if (cursor_visual_ == nullptr) {
    return;
  }

  auto queue = winrt::Windows::System::DispatcherQueue::GetForCurrentThread();

  // Lazily create timer.
  if (emulated_cursor_hide_timer_ == nullptr) {
    emulated_cursor_hide_timer_ = queue.CreateTimer();
    emulated_cursor_hide_timer_.Interval(std::chrono::seconds(kInactivePeriod));
    emulated_cursor_hide_timer_.Tick(
        [=](winrt::Windows::System::DispatcherQueueTimer timer,
            winrt::Windows::Foundation::IInspectable const&) {
          // Timer fires when user has been inactive.  At this point stop the
          // timer.  It will be restarted next time controller interaction
          // happens triggering SetCursorTimeout
          timer.Stop();

          // If the timer fires, the user hasn't move the cursor for more than
          // the interval hence hide the cursor
          cursor_visual_.IsVisible(false);

          // Reduce mouse move polling frequency while user not interacting with
          // controller
          SetMouseMovePollingFrequency(kReducedPollingFrequency);
        });
  }

  // Ensure the cursor is visible and restart the timer as the user is
  // interacting.
  cursor_visual_.IsVisible(true);
  emulated_cursor_hide_timer_.Start();

  SetMouseMovePollingFrequency(kNormalPollingFrequency);
}

void GamepadCursorWinUWP::SetMouseMovePollingFrequency(int ms) {
  if (cursor_move_timer_ != nullptr) {
    cursor_move_timer_.Interval(std::chrono::milliseconds(ms));
  }
}

winrt::Windows::Foundation::Numerics::float3
GamepadCursorWinUWP::GetScaledInput(
    const winrt::Windows::Foundation::Numerics::float3 input) {
  if (!display_helper_->IsRunningOnLargeScreenDevice()) {
    const float inverse_dpi_scale = display_helper_->GetDpiScale();
    return {cursor_visual_.Offset().x * inverse_dpi_scale,
            cursor_visual_.Offset().y * inverse_dpi_scale, 1.0f};
  } else {
    return std::move(input);
  }
}

void GamepadCursorWinUWP::OnGamepadLeftStickMoved(double x, double y) {
  SetCursorTimeout();

  float new_x =
      cursor_visual_.Offset().x + (kCursorScale * static_cast<float>(x));

  float new_y =
      cursor_visual_.Offset().y + (kCursorScale * -static_cast<float>(y));

  WindowBoundsWinUWP logical_bounds = display_helper_->GetLogicalBounds();

  if (new_x > 0 && new_y > 0 && new_x < logical_bounds.width &&
      new_y < logical_bounds.height) {
    cursor_visual_.Offset({new_x, new_y, 0});

    winrt::Windows::Foundation::Numerics::float3 scaled =
        GetScaledInput(cursor_visual_.Offset());
    // TODO(dnfield): Support for gamepad as a distinct device type?
    // https://github.com/flutter/flutter/issues/80472
    binding_handler_delegate_->OnPointerMove(scaled.x, scaled.y,
                                             kFlutterPointerDeviceKindMouse,
                                             kDefaultPointerDeviceId);
  }
}

void GamepadCursorWinUWP::OnGamepadRightStickMoved(double x, double y) {
  winrt::Windows::Foundation::Numerics::float3 scaled =
      GetScaledInput(cursor_visual_.Offset());
  binding_handler_delegate_->OnScroll(
      scaled.x, scaled.y, x * kControllerScrollMultiplier,
      y * kControllerScrollMultiplier, 1, kFlutterPointerDeviceKindMouse,
      kDefaultPointerDeviceId);
}

void GamepadCursorWinUWP::OnGamepadButtonPressed(
    winrt::Windows::Gaming::Input::GamepadButtons buttons) {
  if ((buttons & winrt::Windows::Gaming::Input::GamepadButtons::A) ==
      winrt::Windows::Gaming::Input::GamepadButtons::A) {
    winrt::Windows::Foundation::Numerics::float3 scaled =
        GetScaledInput(cursor_visual_.Offset());

    // TODO(clarkezone) complete keyboard handling including
    // system key (back), unicode handling, shortcut support,
    // handling defered delivery, remove the need for action value.
    // https://github.com/flutter/flutter/issues/70202

    // TODO(dnfield): Support for gamepad as a distinct device type?
    // https://github.com/flutter/flutter/issues/80472
    binding_handler_delegate_->OnPointerDown(
        scaled.x, scaled.y, kFlutterPointerDeviceKindMouse,
        kDefaultPointerDeviceId,
        FlutterPointerMouseButtons::kFlutterPointerButtonMousePrimary);
  } else if ((buttons &
              winrt::Windows::Gaming::Input::GamepadButtons::DPadLeft) ==
             winrt::Windows::Gaming::Input::GamepadButtons::DPadLeft) {
    binding_handler_delegate_->OnKey(
        static_cast<int>(winrt::Windows::System::VirtualKey::Left), kScanLeft,
        0x0100, 0, true, true);
  } else if ((buttons &
              winrt::Windows::Gaming::Input::GamepadButtons::DPadRight) ==
             winrt::Windows::Gaming::Input::GamepadButtons::DPadRight) {
    binding_handler_delegate_->OnKey(
        static_cast<int>(winrt::Windows::System::VirtualKey::Right), kScanRight,
        0x0100, 0, true, true);
  } else if ((buttons &
              winrt::Windows::Gaming::Input::GamepadButtons::DPadUp) ==
             winrt::Windows::Gaming::Input::GamepadButtons::DPadUp) {
    binding_handler_delegate_->OnKey(
        static_cast<int>(winrt::Windows::System::VirtualKey::Up), kScanUp,
        0x0100, 0, true, true);
  } else if ((buttons &
              winrt::Windows::Gaming::Input::GamepadButtons::DPadDown) ==
             winrt::Windows::Gaming::Input::GamepadButtons::DPadDown) {
    binding_handler_delegate_->OnKey(
        static_cast<int>(winrt::Windows::System::VirtualKey::Down), kScanDown,
        0x0100, 0, true, true);
  }
}

void GamepadCursorWinUWP::OnGamepadButtonReleased(
    winrt::Windows::Gaming::Input::GamepadButtons buttons) {
  if ((buttons & winrt::Windows::Gaming::Input::GamepadButtons::A) ==
      winrt::Windows::Gaming::Input::GamepadButtons::A) {
    winrt::Windows::Foundation::Numerics::float3 scaled =
        GetScaledInput(cursor_visual_.Offset());

    // TODO(clarkezone) complete keyboard handling including
    // system key (back), unicode handling, shortcut support,
    // handling defered delivery, remove the need for action value.
    // https://github.com/flutter/flutter/issues/70202

    // TODO(dnfield): Support for gamepad as a distinct device type?
    // https://github.com/flutter/flutter/issues/80472
    binding_handler_delegate_->OnPointerUp(
        scaled.x, scaled.y, kFlutterPointerDeviceKindMouse,
        kDefaultPointerDeviceId,
        FlutterPointerMouseButtons::kFlutterPointerButtonMousePrimary);
  } else if ((buttons &
              winrt::Windows::Gaming::Input::GamepadButtons::DPadLeft) ==
             winrt::Windows::Gaming::Input::GamepadButtons::DPadLeft) {
    binding_handler_delegate_->OnKey(
        static_cast<int>(winrt::Windows::System::VirtualKey::Left), kScanLeft,
        0x0100, 0, true, false);
  } else if ((buttons &
              winrt::Windows::Gaming::Input::GamepadButtons::DPadRight) ==
             winrt::Windows::Gaming::Input::GamepadButtons::DPadRight) {
    binding_handler_delegate_->OnKey(
        static_cast<int>(winrt::Windows::System::VirtualKey::Right), kScanRight,
        0x0100, 0, true, false);
  } else if ((buttons &
              winrt::Windows::Gaming::Input::GamepadButtons::DPadUp) ==
             winrt::Windows::Gaming::Input::GamepadButtons::DPadUp) {
    binding_handler_delegate_->OnKey(
        static_cast<int>(winrt::Windows::System::VirtualKey::Up), kScanUp,
        0x0100, 0, true, false);
  } else if ((buttons &
              winrt::Windows::Gaming::Input::GamepadButtons::DPadDown) ==
             winrt::Windows::Gaming::Input::GamepadButtons::DPadDown) {
    binding_handler_delegate_->OnKey(
        static_cast<int>(winrt::Windows::System::VirtualKey::Down), kScanDown,
        0x0100, 0, true, false);
  }
}

void GamepadCursorWinUWP::OnGamepadControllersChanged() {
  if (game_pad_->HasController()) {
    if (!cursor_move_timer_) {
      if (cursor_visual_ != nullptr) {
        root_collection_.InsertAtTop(cursor_visual_);
      }
      StartGamepadTimer();
    } else {
      if (cursor_visual_ != nullptr) {
        root_collection_.Remove(cursor_visual_);
      }
      StopGamepadTimer();
    }
  }
}

winrt::Windows::UI::Composition::Visual
GamepadCursorWinUWP::CreateCursorVisual() {
  auto container = compositor_.CreateContainerVisual();
  container.Offset(
      {window_.Bounds().Width / 2, window_.Bounds().Height / 2, 1.0});

  // size of the simulated mouse cursor
  constexpr float size = 20;
  constexpr float container_size = size + 10;
  auto cursor_visual = compositor_.CreateShapeVisual();
  cursor_visual.Size({container_size, container_size});

  // compensate for overscan in cursor visual
  cursor_visual.Offset({display_helper_->GetRenderTargetXOffset(),
                        display_helper_->GetRenderTargetYOffset(), 1.0});

  winrt::Windows::UI::Composition::CompositionEllipseGeometry circle =
      compositor_.CreateEllipseGeometry();
  circle.Radius({size / 2, size / 2});

  auto circleshape = compositor_.CreateSpriteShape(circle);
  circleshape.FillBrush(
      compositor_.CreateColorBrush(winrt::Windows::UI::Colors::Black()));
  circleshape.StrokeBrush(
      compositor_.CreateColorBrush(winrt::Windows::UI::Colors::White()));
  circleshape.StrokeThickness(5.0);
  circleshape.Offset({container_size / 2, container_size / 2});

  cursor_visual.Shapes().Append(circleshape);

  winrt::Windows::UI::Composition::Visual visual =
      cursor_visual.as<winrt::Windows::UI::Composition::Visual>();

  visual.AnchorPoint({0.5, 0.5});
  container.Children().InsertAtTop(visual);

  return container;
}

}  // namespace flutter
