// 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 "ui/events/gestures/gesture_recognizer_impl.h"

#include <stddef.h>

#include <limits>
#include <memory>

#include "base/command_line.h"
#include "base/logging.h"
#include "base/memory/ptr_util.h"
#include "base/stl_util.h"
#include "base/time/time.h"
#include "ui/events/event.h"
#include "ui/events/event_constants.h"
#include "ui/events/event_switches.h"
#include "ui/events/event_utils.h"
#include "ui/events/gesture_detection/gesture_configuration.h"
#include "ui/events/gestures/gesture_recognizer_observer.h"
#include "ui/events/gestures/gesture_types.h"

namespace ui {

namespace {

void TransferConsumer(
    GestureConsumer* current_consumer,
    GestureConsumer* new_consumer,
    std::map<GestureConsumer*, std::unique_ptr<GestureProviderAura>>* map) {
  if (!map->empty() && base::ContainsKey(*map, current_consumer)) {
    (*map)[new_consumer] = std::move((*map)[current_consumer]);
    (*map)[new_consumer]->set_gesture_consumer(new_consumer);
    map->erase(current_consumer);
  }
}

// Generic function to remove every entry from a map having the given value.
template <class Key, class T, class Value>
bool RemoveValueFromMap(std::map<Key, T>* map, const Value& value) {
  bool removed = false;
  // This is a bandaid fix for crbug/732232 that requires further investigation.
  if (!map || map->empty())
    return removed;
  for (auto i = map->begin(); i != map->end();) {
    if (i->second == value) {
      map->erase(i++);
      removed = true;
    } else {
      ++i;
    }
  }
  return removed;
}

}  // namespace

////////////////////////////////////////////////////////////////////////////////
// GestureRecognizerImpl, public:

GestureRecognizerImpl::GestureRecognizerImpl() {
}

GestureRecognizerImpl::~GestureRecognizerImpl() {
}

// Checks if this finger is already down, if so, returns the current target.
// Otherwise, returns NULL.
GestureConsumer* GestureRecognizerImpl::GetTouchLockedTarget(
    const TouchEvent& event) {
  return touch_id_target_[event.pointer_details().id];
}

GestureConsumer* GestureRecognizerImpl::GetTargetForLocation(
    const gfx::PointF& location, int source_device_id) {
  const float max_distance =
      GestureConfiguration::GetInstance()
          ->max_separation_for_gesture_touches_in_pixels();

  gfx::PointF closest_point;
  int closest_touch_id = 0;
  double closest_distance_squared = std::numeric_limits<double>::infinity();

  for (const auto& provider_pair : consumer_gesture_provider_) {
    const MotionEventAura& pointer_state =
        provider_pair.second->pointer_state();
    for (size_t j = 0; j < pointer_state.GetPointerCount(); ++j) {
      if (source_device_id != pointer_state.GetSourceDeviceId(j))
        continue;
      gfx::PointF point(pointer_state.GetX(j), pointer_state.GetY(j));
      // Relative distance is all we need here, so LengthSquared() is
      // appropriate, and cheaper than Length().
      double distance_squared = (point - location).LengthSquared();
      if (distance_squared < closest_distance_squared) {
        closest_point = point;
        closest_touch_id = pointer_state.GetPointerId(j);
        closest_distance_squared = distance_squared;
      }
    }
  }

  if (closest_distance_squared < max_distance * max_distance)
    return touch_id_target_[closest_touch_id];
  return NULL;
}

void GestureRecognizerImpl::CancelActiveTouchesExcept(
    GestureConsumer* not_cancelled) {
  CancelActiveTouchesExceptImpl(not_cancelled, kNotifyObservers);
}

void GestureRecognizerImpl::TransferEventsTo(
    GestureConsumer* current_consumer,
    GestureConsumer* new_consumer,
    TransferTouchesBehavior transfer_touches_behavior) {
  // This method transfers the gesture stream from |current_consumer| to
  // |new_consumer|. If |transfer_touches_behavior| is kCancel, it ensures that
  // both consumers retain a touch event stream which is reasonably valid. In
  // order to do this we
  // - record what pointers are currently down on |current_consumer|
  // - cancel touches on consumers other than |current_consumer|
  // - move the gesture provider from |current_consumer| to |new_consumer|
  // - if |transfer_touches_behavior| is kCancel
  //     - synchronize the state of the new gesture provider associated with
  //       current_consumer with with the touch state of the consumer itself via
  //       OnTouchEnter.
  //     - synthesize touch cancels on |current_consumer|.
  // - retarget the pointers that were previously targeted to
  //   |current_consumer| to |new_consumer|.
  // NOTE: This currently doesn't synthesize touch press events on
  // |new_consumer|, so the event stream it sees is still invalid.
  DCHECK(current_consumer);
  DCHECK(new_consumer);
  GestureEventHelper* helper = FindDispatchHelperForConsumer(current_consumer);

  std::vector<int> touchids_targeted_at_current;

  for (const auto& touch_id_target: touch_id_target_) {
    if (touch_id_target.second == current_consumer)
      touchids_targeted_at_current.push_back(touch_id_target.first);
  }

  CancelActiveTouchesExceptImpl(current_consumer, kDontNotifyObservers);

  std::vector<std::unique_ptr<TouchEvent>> cancelling_touches =
      GetEventPerPointForConsumer(current_consumer, ET_TOUCH_CANCELLED);

  TransferConsumer(current_consumer, new_consumer, &consumer_gesture_provider_);

  // We're now in a situation where current_consumer has no gesture recognizer,
  // but has some pointers down which need cancelling. In order to ensure that
  // the GR sees a valid event stream, inform it of these pointers via
  // OnTouchEnter, and then synthesize a touch cancel per pointer.
  if (transfer_touches_behavior == TransferTouchesBehavior::kCancel && helper) {
    GestureProviderAura* gesture_provider =
        GetGestureProviderForConsumer(current_consumer);

    for (std::unique_ptr<TouchEvent>& event : cancelling_touches) {
      gesture_provider->OnTouchEnter(event->pointer_details().id, event->x(),
                                     event->y());
      helper->DispatchSyntheticTouchEvent(event.get());
    }
  }

  // The underlying gesture provider for current_consumer might have filtered
  // gesture detection for some reasons but that might not be applied to the new
  // consumer. See also:
  // https://docs.google.com/document/d/1AKeK8IuF-j2TJ-2sPsewORXdjnr6oAzy5nnR1zwrsfc/edit#
  if (base::ContainsKey(consumer_gesture_provider_, new_consumer))
    GetGestureProviderForConsumer(new_consumer)->ResetGestureHandlingState();

  for (int touch_id : touchids_targeted_at_current)
    touch_id_target_[touch_id] = new_consumer;
  for (GestureRecognizerObserver& observer : observers())
    observer.OnEventsTransferred(current_consumer, new_consumer,
                                 transfer_touches_behavior);
}

bool GestureRecognizerImpl::GetLastTouchPointForTarget(
    GestureConsumer* consumer,
    gfx::PointF* point) {
  if (consumer_gesture_provider_.empty())
    return false;
  if (!base::ContainsKey(consumer_gesture_provider_, consumer))
    return false;
  const MotionEvent& pointer_state =
      consumer_gesture_provider_[consumer]->pointer_state();
  if (!pointer_state.GetPointerCount())
    return false;
  *point = gfx::PointF(pointer_state.GetX(), pointer_state.GetY());
  return true;
}

std::vector<std::unique_ptr<TouchEvent>>
GestureRecognizerImpl::GetEventPerPointForConsumer(GestureConsumer* consumer,
                                                   EventType type) {
  std::vector<std::unique_ptr<TouchEvent>> cancelling_touches;
  if (consumer_gesture_provider_.empty())
    return cancelling_touches;

  if (!base::ContainsKey(consumer_gesture_provider_, consumer))
    return cancelling_touches;
  const MotionEventAura& pointer_state =
      consumer_gesture_provider_[consumer]->pointer_state();
  if (pointer_state.GetPointerCount() == 0)
    return cancelling_touches;
  for (size_t i = 0; i < pointer_state.GetPointerCount(); ++i) {
    std::unique_ptr<TouchEvent> touch_event(
        new TouchEvent(type, gfx::Point(), EventTimeForNow(),
                       PointerDetails(ui::EventPointerType::POINTER_TYPE_TOUCH,
                                      pointer_state.GetPointerId(i)),
                       EF_IS_SYNTHESIZED, 0.0f));
    gfx::PointF point(pointer_state.GetX(i), pointer_state.GetY(i));
    touch_event->set_location_f(point);
    touch_event->set_root_location_f(point);
    cancelling_touches.push_back(std::move(touch_event));
  }
  return cancelling_touches;
}

bool GestureRecognizerImpl::CancelActiveTouches(GestureConsumer* consumer) {
  return CancelActiveTouchesImpl(consumer, kNotifyObservers);
}

////////////////////////////////////////////////////////////////////////////////
// GestureRecognizerImpl, protected:

GestureProviderAura* GestureRecognizerImpl::GetGestureProviderForConsumer(
    GestureConsumer* consumer) {
  GestureProviderAura* gesture_provider = nullptr;

  if (!consumer_gesture_provider_.empty() &&
      base::ContainsKey(consumer_gesture_provider_, consumer)) {
    gesture_provider = consumer_gesture_provider_.at(consumer).get();
  }

  if (!gesture_provider) {
    gesture_provider = new GestureProviderAura(consumer, this);
    consumer_gesture_provider_[consumer] = base::WrapUnique(gesture_provider);
  }
  return gesture_provider;
}

bool GestureRecognizerImpl::ProcessTouchEventPreDispatch(
    TouchEvent* event,
    GestureConsumer* consumer) {
  SetupTargets(*event, consumer);

  if (event->result() & ER_CONSUMED)
    return false;

  GestureProviderAura* gesture_provider =
      GetGestureProviderForConsumer(consumer);
  return gesture_provider->OnTouchEvent(event);
}

////////////////////////////////////////////////////////////////////////////////
// GestureRecognizerImpl, private:

void GestureRecognizerImpl::SetupTargets(const TouchEvent& event,
                                         GestureConsumer* target) {
  event_to_gesture_provider_[event.unique_event_id()] =
      GetGestureProviderForConsumer(target);
  if (event.type() == ui::ET_TOUCH_RELEASED ||
      event.type() == ui::ET_TOUCH_CANCELLED) {
    touch_id_target_.erase(event.pointer_details().id);
  } else if (event.type() == ui::ET_TOUCH_PRESSED) {
    touch_id_target_[event.pointer_details().id] = target;
  }
}

void GestureRecognizerImpl::DispatchGestureEvent(
    GestureConsumer* raw_input_consumer,
    GestureEvent* event) {
  if (raw_input_consumer) {
    GestureEventHelper* helper =
        FindDispatchHelperForConsumer(raw_input_consumer);
    if (helper)
      helper->DispatchGestureEvent(raw_input_consumer, event);
  }
}

GestureRecognizer::Gestures GestureRecognizerImpl::AckTouchEvent(
    uint32_t unique_event_id,
    ui::EventResult result,
    bool is_source_touch_event_set_non_blocking,
    GestureConsumer* consumer) {
  GestureProviderAura* gesture_provider = nullptr;

  // Check if we have already processed this event before dispatch and have a
  // consumer associated with it.
  auto event_to_gesture_provider_iterator =
      event_to_gesture_provider_.find(unique_event_id);
  if (event_to_gesture_provider_iterator != event_to_gesture_provider_.end()) {
    gesture_provider = event_to_gesture_provider_iterator->second;
    event_to_gesture_provider_.erase(event_to_gesture_provider_iterator);
  } else {
    gesture_provider = GetGestureProviderForConsumer(consumer);
  }
  gesture_provider->OnTouchEventAck(unique_event_id, result != ER_UNHANDLED,
                                    is_source_touch_event_set_non_blocking);
  return gesture_provider->GetAndResetPendingGestures();
}

void GestureRecognizerImpl::CancelActiveTouchesExceptImpl(
    GestureConsumer* not_cancelled,
    ShouldNotifyObservers should_notify) {
  // Do not iterate directly over |consumer_gesture_provider_| because canceling
  // active touches may cause the consumer to be removed from
  // |consumer_gesture_provider_|. See https://crbug.com/651258 for more info.
  std::vector<GestureConsumer*> consumers(consumer_gesture_provider_.size());
  for (const auto& entry : consumer_gesture_provider_) {
    if (entry.first == not_cancelled)
      continue;

    consumers.push_back(entry.first);
  }

  for (auto* consumer : consumers)
    CancelActiveTouchesImpl(consumer, kDontNotifyObservers);

  if (should_notify == kDontNotifyObservers)
    return;
  for (GestureRecognizerObserver& observer : observers())
    observer.OnActiveTouchesCanceledExcept(not_cancelled);
}

bool GestureRecognizerImpl::CancelActiveTouchesImpl(
    GestureConsumer* consumer,
    ShouldNotifyObservers should_notify) {
  GestureEventHelper* helper = FindDispatchHelperForConsumer(consumer);

  if (!helper)
    return false;

  std::vector<std::unique_ptr<TouchEvent>> cancelling_touches =
      GetEventPerPointForConsumer(consumer, ET_TOUCH_CANCELLED);
  for (const std::unique_ptr<TouchEvent>& cancelling_touch : cancelling_touches)
    helper->DispatchSyntheticTouchEvent(cancelling_touch.get());
  if (should_notify == kNotifyObservers) {
    for (GestureRecognizerObserver& observer : observers())
      observer.OnActiveTouchesCanceled(consumer);
  }
  return !cancelling_touches.empty();
}

bool GestureRecognizerImpl::CleanupStateForConsumer(
    GestureConsumer* consumer) {
  bool state_cleaned_up = false;
  state_cleaned_up |= RemoveValueFromMap(&touch_id_target_, consumer);

  // This is a bandaid fix for crbug/732232 that should be further looked into.
  if (consumer_gesture_provider_.empty())
    return state_cleaned_up;

  auto consumer_gesture_provider_it = consumer_gesture_provider_.find(consumer);
  if (consumer_gesture_provider_it != consumer_gesture_provider_.end()) {
    // Remove gesture provider associated with the consumer from
    // |event_to_gesture_provider_| map.
    RemoveValueFromMap(&event_to_gesture_provider_,
                       consumer_gesture_provider_it->second.get());
    state_cleaned_up = true;
    consumer_gesture_provider_.erase(consumer_gesture_provider_it);
  }
  return state_cleaned_up;
}

void GestureRecognizerImpl::AddGestureEventHelper(GestureEventHelper* helper) {
  helpers_.push_back(helper);
}

void GestureRecognizerImpl::RemoveGestureEventHelper(
    GestureEventHelper* helper) {
  std::vector<GestureEventHelper*>::iterator it = std::find(helpers_.begin(),
      helpers_.end(), helper);
  if (it != helpers_.end())
    helpers_.erase(it);
}

void GestureRecognizerImpl::OnGestureEvent(GestureConsumer* raw_input_consumer,
                                           GestureEvent* event) {
  DispatchGestureEvent(raw_input_consumer, event);
}

GestureEventHelper* GestureRecognizerImpl::FindDispatchHelperForConsumer(
    GestureConsumer* consumer) {
  std::vector<GestureEventHelper*>::iterator it;
  for (it = helpers_.begin(); it != helpers_.end(); ++it) {
    if ((*it)->CanDispatchToConsumer(consumer))
      return (*it);
  }
  return NULL;
}

}  // namespace ui
