/**
 * Copyright (c) 2015-present, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 */

package com.facebook.react.uimanager.events;

import android.view.MotionEvent;

import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.WritableArray;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.uimanager.PixelUtil;

/**
 * Class responsible for generating catalyst touch events based on android {@link MotionEvent}.
 */
/*package*/ class TouchesHelper {

  private static final String PAGE_X_KEY = "pageX";
  private static final String PAGE_Y_KEY = "pageY";
  private static final String TARGET_KEY = "target";
  private static final String TIMESTAMP_KEY = "timeStamp";
  private static final String POINTER_IDENTIFIER_KEY = "identifier";

  private static final String LOCATION_X_KEY = "locationX";
  private static final String LOCATION_Y_KEY = "locationY";

  /**
   * Creates catalyst pointers array in format that is expected by RCTEventEmitter JS module from
   * given {@param event} instance. This method use {@param reactTarget} parameter to set as a
   * target view id associated with current gesture.
   */
  private static WritableArray createsPointersArray(int reactTarget, TouchEvent event) {
    WritableArray touches = Arguments.createArray();
    MotionEvent motionEvent = event.getMotionEvent();

    // Calculate the coordinates for the target view.
    // The MotionEvent contains the X,Y of the touch in the coordinate space of the root view
    // The TouchEvent contains the X,Y of the touch in the coordinate space of the target view
    // Subtracting them allows us to get the coordinates of the target view's top left corner
    // We then use this when computing the view specific touches below
    // Since only one view is actually handling even multiple touches, the values are all relative
    // to this one target view.
    float targetViewCoordinateX = motionEvent.getX() - event.getViewX();
    float targetViewCoordinateY = motionEvent.getY() - event.getViewY();

    for (int index = 0; index < motionEvent.getPointerCount(); index++) {
      WritableMap touch = Arguments.createMap();
      // pageX,Y values are relative to the RootReactView
      // the motionEvent already contains coordinates in that view
      touch.putDouble(PAGE_X_KEY, PixelUtil.toDIPFromPixel(motionEvent.getX(index)));
      touch.putDouble(PAGE_Y_KEY, PixelUtil.toDIPFromPixel(motionEvent.getY(index)));
      // locationX,Y values are relative to the target view
      // To compute the values for the view, we subtract that views location from the event X,Y
      float locationX = motionEvent.getX(index) - targetViewCoordinateX;
      float locationY = motionEvent.getY(index) - targetViewCoordinateY;
      touch.putDouble(LOCATION_X_KEY, PixelUtil.toDIPFromPixel(locationX));
      touch.putDouble(LOCATION_Y_KEY, PixelUtil.toDIPFromPixel(locationY));
      touch.putInt(TARGET_KEY, reactTarget);
      touch.putDouble(TIMESTAMP_KEY, motionEvent.getEventTime());
      touch.putDouble(POINTER_IDENTIFIER_KEY, motionEvent.getPointerId(index));
      touches.pushMap(touch);
    }

    return touches;
  }

  /**
   * Generate and send touch event to RCTEventEmitter JS module associated with the given
   * {@param context}. Touch event can encode multiple concurrent touches (pointers).
   *
   * @param rctEventEmitter Event emitter used to execute JS module call
   * @param type type of the touch event (see {@link TouchEventType})
   * @param reactTarget target view react id associated with this gesture
   * @param touchEvent native touch event to read pointers count and coordinates from
   */
  public static void sendTouchEvent(
      RCTEventEmitter rctEventEmitter,
      TouchEventType type,
      int reactTarget,
      TouchEvent touchEvent) {

    WritableArray pointers = createsPointersArray(reactTarget, touchEvent);
    MotionEvent motionEvent = touchEvent.getMotionEvent();

    // For START and END events send only index of the pointer that is associated with that event
    // For MOVE and CANCEL events 'changedIndices' array should contain all the pointers indices
    WritableArray changedIndices = Arguments.createArray();
    if (type == TouchEventType.MOVE || type == TouchEventType.CANCEL) {
      for (int i = 0; i < motionEvent.getPointerCount(); i++) {
        changedIndices.pushInt(i);
      }
    } else if (type == TouchEventType.START || type == TouchEventType.END) {
      changedIndices.pushInt(motionEvent.getActionIndex());
    } else {
      throw new RuntimeException("Unknown touch type: " + type);
    }

    rctEventEmitter.receiveTouches(
        type.getJSEventName(),
        pointers,
        changedIndices);
  }

}

@@ -1457,69 +1457,21 @@
 ent 
-event) %7B%0A    WritableArray touches = Arguments.createArray();
+touchEvent) %7B
 %0A   
@@ -1487,23 +1487,22 @@
 ent 
-motionE
+e
 vent = 
-e
+touchE
 vent
@@ -1529,592 +1529,281 @@
     
-// Calculate the coordinates for the target view.%0A    // The MotionEvent contains the X,Y of the touch in the coordinate space of the root view%0A    // The TouchEvent contains the X,Y of the touch in the coordinate space of the target view%0A    // Subtracting them allows us to get the coordinates of the target view's top left corner%0A    // We then use this when computing the view specific touches below%0A    // Since only one view is actually handling even multiple touches,
+WritableArray touches = Arguments.createArray();%0A%0A    // Calculate raw-to-relative offset as getRawX() and getRawY() can only return values for the%0A    // pointer at index 0. We use
  th
+os
 e value
-s are all relative%0A    // to this one target view.%0A    float targetViewCoordinateX = motionE
+ to calculate %22raw%22 coordinates for other pointers%0A    float offsetX = e
 vent.get
 X() 
@@ -1798,16 +1798,19 @@
 vent.get
+Raw
 X() - ev
@@ -1816,20 +1816,16 @@
 vent.get
-View
 X();%0A   
@@ -1835,47 +1835,27 @@
 oat 
-targetViewCoordinateY = motionE
+offsetY = e
 vent.get
 Y() 
@@ -1850,16 +1850,19 @@
 vent.get
+Raw
 Y() - ev
@@ -1868,20 +1868,16 @@
 vent.get
-View
 Y();%0A%0A  
@@ -1906,23 +1906,17 @@
 index %3C 
-motionE
+e
 vent.get
@@ -1995,133 +1995,8 @@
 ();%0A
-      // pageX,Y values are relative to the RootReactView%0A      // the motionEvent already contains coordinates in that view%0A
     
@@ -2042,39 +2042,33 @@
 .toDIPFromPixel(
-motionE
+e
 vent.getX(index)
@@ -2063,24 +2063,34 @@
 .getX(index)
+ + offsetX
 ));%0A      to
@@ -2140,23 +2140,17 @@
 omPixel(
-motionE
+e
 vent.get
@@ -2161,312 +2161,20 @@
 dex)
-));%0A      // locationX,Y values are relative to the target view%0A      // To compute the values for the view, we subtract that views location from the event X,Y%0A      float locationX = motionEvent.getX(index) - targetViewCoordinateX;%0A      float locationY = motionEvent.getY(index) - targetViewCoordinateY
+ + offsetY))
 ;%0A  
@@ -2234,25 +2234,33 @@
 omPixel(
-locationX
+event.getX(index)
 ));%0A    
@@ -2318,25 +2318,33 @@
 omPixel(
-locationY
+event.getY(index)
 ));%0A    
@@ -2417,31 +2417,25 @@
 ESTAMP_KEY, 
-motionE
+e
 vent.getEven
@@ -2490,23 +2490,17 @@
 ER_KEY, 
-motionE
+e
 vent.get

Fix Y-coord on touches