// Copyright 2018 The Fuchsia 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 "src/lib/ui/input/gesture_detector.h"

#include <lib/syslog/cpp/macros.h>

#include <glm/gtx/norm.hpp>

namespace input {
namespace {

GestureDetector::TapType ClassifyTap(const fuchsia::ui::input::PointerEvent& event,
                                     const Gesture& state) {
  // TODO(MI4-2402): Allow custom mappings.
  switch (event.type) {
    case fuchsia::ui::input::PointerEventType::MOUSE:
      if (event.buttons == fuchsia::ui::input::kMouseTertiaryButton) {
        // Map the tertiary mouse button to the same tap type (3) as left +
        // right click.
        return 3;
      } else {
        return event.buttons;
      }
    case fuchsia::ui::input::PointerEventType::TOUCH:
      return state.pointer_count();
    case fuchsia::ui::input::PointerEventType::STYLUS:
      // For stylus, map the buttonless case to tap type 1, and decorate with
      // buttons.
      return 1 + event.buttons;
    case fuchsia::ui::input::PointerEventType::INVERTED_STYLUS:
      // When the stylus is inverted, bump the tap type by 1 (e.g. the
      // buttonless case becomes tap type 2).
      return 2 + event.buttons;
  }
}

#ifndef NDEBUG

// A delegating |GestureDetector::Interaction| wrapper that checks that
// |tap_type > 0|.
class CheckedInteraction : public GestureDetector::Interaction {
 public:
  CheckedInteraction(std::unique_ptr<GestureDetector::Interaction> interaction)
      : interaction_(std::move(interaction)) {}

 private:
  void OnTapBegin(const glm::vec2& coordinate, GestureDetector::TapType tap_type) override {
    FX_CHECK(tap_type > 0);
    interaction_->OnTapBegin(coordinate, tap_type);
  }

  void OnTapUpdate(GestureDetector::TapType tap_type) override {
    FX_CHECK(tap_type > 0);
    interaction_->OnTapUpdate(tap_type);
  }

  void OnTapCommit() override { interaction_->OnTapCommit(); }

  void OnMultidrag(GestureDetector::TapType tap_type, const Gesture::Delta& delta) override {
    FX_CHECK(tap_type > 0);
    interaction_->OnMultidrag(tap_type, delta);
  }

  std::unique_ptr<GestureDetector::Interaction> interaction_;
};

#endif  // NDEBUG

}  // namespace

GestureDetector::Interaction::~Interaction() = default;

void GestureDetector::Interaction::OnTapBegin(const glm::vec2& coordinate,
                                              GestureDetector::TapType tap_type) {}
void GestureDetector::Interaction::OnTapUpdate(GestureDetector::TapType tap_type) {}
void GestureDetector::Interaction::OnTapCommit() {}
void GestureDetector::Interaction::OnMultidrag(GestureDetector::TapType tap_type,
                                               const Gesture::Delta& delta) {}

GestureDetector::Delegate::~Delegate() = default;

GestureDetector::DevicePointerState::DevicePointerState() : weak_ptr_factory_(this) {}

fxl::WeakPtr<GestureDetector::DevicePointerState>
GestureDetector::DevicePointerState::GetWeakPtr() {
  return weak_ptr_factory_.GetWeakPtr();
}

GestureDetector::GestureDetector(Delegate* delegate, float drag_threshold)
    : delegate_(delegate), drag_threshold_squared_(drag_threshold * drag_threshold) {}

void GestureDetector::OnPointerEvent(fuchsia::ui::input::PointerEvent event) {
  switch (event.phase) {
    case fuchsia::ui::input::PointerEventPhase::DOWN: {
      fxl::WeakPtr<DevicePointerState> state = devices_[event.device_id].GetWeakPtr();
      state->gesture.AddPointer(event.pointer_id, {event.x, event.y});

      if (!state->interaction) {
        std::unique_ptr<Interaction> interaction = delegate_->BeginInteraction(&state->gesture);
        // Store interaction in temporary variable so we can guard against state having been
        // destroyed in |BeginInteraction|. This can happen because the delegate can implement
        // |BeginInteraction| however it likes, including by resetting or destroying the
        // |GestureDetector|.
        if (!state) {
          return;
        }
        state->interaction = std::move(interaction);
#ifndef NDEBUG
        state->interaction = std::make_unique<CheckedInteraction>(std::move(state->interaction));
#endif
        // Only start a tap if we're the first pointer. Otherwise, if we've
        // already committed a tap, immediately enter a multidrag.
        if (state->gesture.pointer_count() == 1) {
          state->tap_type = ClassifyTap(event, state->gesture);
          state->interaction->OnTapBegin({event.x, event.y}, state->tap_type);
          if (!state) {
            return;
          }
        }
        state->origins[event.pointer_id] = {event.x, event.y};
      } else if (state->tap_type > 0) {
        TapType tap_type = ClassifyTap(event, state->gesture);
        if (tap_type > state->tap_type) {
          state->tap_type = tap_type;
          state->interaction->OnTapUpdate(tap_type);
          if (!state) {
            return;
          }
        }
        state->origins[event.pointer_id] = {event.x, event.y};
      } else {
        // This is an in-progress multidrag that we should update with the new
        // tap_type.
        state->interaction->OnMultidrag(ClassifyTap(event, state->gesture), {});
      }
      break;
    }
    case fuchsia::ui::input::PointerEventPhase::MOVE: {
      auto it = devices_.find(event.device_id);
      if (it == devices_.end()) {
        // TODO:(SCN-1439): This ignores the mouse move case, which happens
        // outside of a DOWN/UP pair.
        break;
      }

      DevicePointerState& state = it->second;
      FX_DCHECK(state.interaction);
      // Unlike in the other handlers, we don't need to guard state with a weak pointer here since
      // all the |Interaction| callbacks in this one are the last line in the method.

      Gesture::Delta delta = state.gesture.UpdatePointer(event.pointer_id, {event.x, event.y});
      if (!state.tap_type) {
        // 0 signifies in-progress multidrag (see |tap_type| docs for details).
        state.interaction->OnMultidrag(ClassifyTap(event, state.gesture), delta);
      } else {
        // Decide whether we've exceeded the threshold to start a multidrag.
        state.pending_delta += delta;

        if (glm::distance2(state.origins[event.pointer_id], {event.x, event.y}) >=
            drag_threshold_squared_) {
          // Kill the tap and handle as a multidrag from now on.
          state.tap_type = 0;
          state.origins.clear();
          state.interaction->OnMultidrag(ClassifyTap(event, state.gesture), state.pending_delta);
        }
      }
      break;
    }
    case fuchsia::ui::input::PointerEventPhase::UP: {
      auto it = devices_.find(event.device_id);
      if (it != devices_.end()) {
        fxl::WeakPtr<DevicePointerState> state = it->second.GetWeakPtr();
        if (state->tap_type > 0) {
          state->interaction->OnTapCommit();
          if (!state) {
            return;
          }
          state->tap_type = -state->tap_type;
        }
        state->gesture.RemovePointer(event.pointer_id);
        if (!state->gesture.has_pointers()) {
          devices_.erase(it);  // This destroys the interaction as well.
        } else if (!state->tap_type) {
          // If there's still a drag active, update the |tap_type|.
          state->interaction->OnMultidrag(ClassifyTap(event, state->gesture), {});
        }
      }
      break;
    }
    default:
      break;
  }
}

}  // namespace input
