/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

package com.facebook.react.views.scroll;

import androidx.annotation.Nullable;
import androidx.core.util.Pools;
import com.facebook.infer.annotation.Assertions;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.uimanager.PixelUtil;
import com.facebook.react.uimanager.events.Event;
import com.facebook.react.uimanager.events.RCTEventEmitter;
import com.facebook.react.uimanager.events.RCTModernEventEmitter;

/** A event dispatched from a ScrollView scrolling. */
public class ScrollEvent extends Event<ScrollEvent> {

  private static final Pools.SynchronizedPool<ScrollEvent> EVENTS_POOL =
      new Pools.SynchronizedPool<>(3);

  private int mScrollX;
  private int mScrollY;
  private double mXVelocity;
  private double mYVelocity;
  private int mContentWidth;
  private int mContentHeight;
  private int mScrollViewWidth;
  private int mScrollViewHeight;
  private @Nullable ScrollEventType mScrollEventType;

  public static ScrollEvent obtain(
      int surfaceId,
      int viewTag,
      ScrollEventType scrollEventType,
      int scrollX,
      int scrollY,
      float xVelocity,
      float yVelocity,
      int contentWidth,
      int contentHeight,
      int scrollViewWidth,
      int scrollViewHeight) {
    ScrollEvent event = EVENTS_POOL.acquire();
    if (event == null) {
      event = new ScrollEvent();
    }
    event.init(
        surfaceId,
        viewTag,
        scrollEventType,
        scrollX,
        scrollY,
        xVelocity,
        yVelocity,
        contentWidth,
        contentHeight,
        scrollViewWidth,
        scrollViewHeight);
    return event;
  }

  @Override
  public void onDispose() {
    EVENTS_POOL.release(this);
  }

  private ScrollEvent() {}

  private void init(
      int surfaceId,
      int viewTag,
      ScrollEventType scrollEventType,
      int scrollX,
      int scrollY,
      float xVelocity,
      float yVelocity,
      int contentWidth,
      int contentHeight,
      int scrollViewWidth,
      int scrollViewHeight) {
    super.init(surfaceId, viewTag);
    mScrollEventType = scrollEventType;
    mScrollX = scrollX;
    mScrollY = scrollY;
    mXVelocity = xVelocity;
    mYVelocity = yVelocity;
    mContentWidth = contentWidth;
    mContentHeight = contentHeight;
    mScrollViewWidth = scrollViewWidth;
    mScrollViewHeight = scrollViewHeight;
  }

  @Override
  public String getEventName() {
    return ScrollEventType.getJSEventName(Assertions.assertNotNull(mScrollEventType));
  }

  @Override
  public short getCoalescingKey() {
    // All scroll events for a given view can be coalesced
    return 0;
  }

  @Override
  public boolean canCoalesce() {
    // Only SCROLL events can be coalesced, all others can not be
    if (mScrollEventType == ScrollEventType.SCROLL) {
      return true;
    }
    return false;
  }

  @Override
  public void dispatch(RCTEventEmitter rctEventEmitter) {
    rctEventEmitter.receiveEvent(getViewTag(), getEventName(), serializeEventData());
  }

  @Override
  public void dispatchModern(RCTModernEventEmitter rctEventEmitter) {
    rctEventEmitter.receiveEvent(
        getSurfaceId(), getViewTag(), getEventName(), serializeEventData());
  }

  private WritableMap serializeEventData() {
    WritableMap contentInset = Arguments.createMap();
    contentInset.putDouble("top", 0);
    contentInset.putDouble("bottom", 0);
    contentInset.putDouble("left", 0);
    contentInset.putDouble("right", 0);

    WritableMap contentOffset = Arguments.createMap();
    contentOffset.putDouble("x", PixelUtil.toDIPFromPixel(mScrollX));
    contentOffset.putDouble("y", PixelUtil.toDIPFromPixel(mScrollY));

    WritableMap contentSize = Arguments.createMap();
    contentSize.putDouble("width", PixelUtil.toDIPFromPixel(mContentWidth));
    contentSize.putDouble("height", PixelUtil.toDIPFromPixel(mContentHeight));

    WritableMap layoutMeasurement = Arguments.createMap();
    layoutMeasurement.putDouble("width", PixelUtil.toDIPFromPixel(mScrollViewWidth));
    layoutMeasurement.putDouble("height", PixelUtil.toDIPFromPixel(mScrollViewHeight));

    WritableMap velocity = Arguments.createMap();
    velocity.putDouble("x", mXVelocity);
    velocity.putDouble("y", mYVelocity);

    WritableMap event = Arguments.createMap();
    event.putMap("contentInset", contentInset);
    event.putMap("contentOffset", contentOffset);
    event.putMap("contentSize", contentSize);
    event.putMap("layoutMeasurement", layoutMeasurement);
    event.putMap("velocity", velocity);

    event.putInt("target", getViewTag());
    event.putBoolean("responderIgnoreScroll", true);
    return event;
  }
}

@@ -533,134 +533,8 @@
 ent;
-%0Aimport com.facebook.react.uimanager.events.RCTEventEmitter;%0Aimport com.facebook.react.uimanager.events.RCTModernEventEmitter;
 %0A%0A/*
@@ -976,32 +976,32 @@
 rollViewHeight;%0A
-
   private @Nulla
@@ -1039,16 +1039,561 @@
 tType;%0A%0A
+  @Deprecated%0A  public static ScrollEvent obtain(%0A      int viewTag,%0A      ScrollEventType scrollEventType,%0A      int scrollX,%0A      int scrollY,%0A      float xVelocity,%0A      float yVelocity,%0A      int contentWidth,%0A      int contentHeight,%0A      int scrollViewWidth,%0A      int scrollViewHeight) %7B%0A    return obtain(%0A        -1,%0A        viewTag,%0A        scrollEventType,%0A        scrollX,%0A        scrollY,%0A        xVelocity,%0A        yVelocity,%0A        contentWidth,%0A        contentHeight,%0A        scrollViewWidth,%0A        scrollViewHeight);%0A  %7D%0A%0A
   public
@@ -3483,373 +3483,40 @@
 %0A  @
-Override%0A  public void dispatch(RCTEventEmitter rctEventEmitter) %7B%0A    rctEventEmitter.receiveEvent(getViewTag(), getEventName(), serializeEventData());%0A  %7D%0A%0A  @Override%0A  public void dispatchModern(RCTModernEventEmitter rctEventEmitter) %7B%0A    rctEventEmitter.receiveEvent(%0A        getSurfaceId(), getViewTag(), getEventName(), serializeEventData());%0A  %7D%0A%0A  private
+Nullable%0A  @Override%0A  protected
  Wri
@@ -3528,17 +3528,11 @@
 Map 
-serialize
+get
 Even

Support RCTModernEventEmitter+RCTEventEmitter in ScrollEvent Event class