/**
 * 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.flat;

import javax.annotation.Nullable;

import java.util.Map;

import android.graphics.Rect;
import android.os.Build;

import com.facebook.react.bridge.JSApplicationIllegalArgumentException;
import com.facebook.react.bridge.ReadableArray;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.common.MapBuilder;
import com.facebook.react.uimanager.PixelUtil;
import com.facebook.react.uimanager.PointerEvents;
import com.facebook.react.uimanager.ViewProps;
import com.facebook.react.uimanager.annotations.ReactProp;
import com.facebook.react.uimanager.ReactClippingViewGroupHelper;
import com.facebook.react.views.view.ReactDrawableHelper;

/**
 * ViewManager that creates instances of RCTView.
 */
public final class RCTViewManager extends FlatViewManager {

  private static final int[] TMP_INT_ARRAY = new int[2];

  private static final int CMD_HOTSPOT_UPDATE = 1;
  private static final int CMD_SET_PRESSED = 2;

  @Override
  public String getName() {
    return ViewProps.VIEW_CLASS_NAME;
  }

  public Map<String, Integer> getCommandsMap() {
    return MapBuilder.of("hotspotUpdate", CMD_HOTSPOT_UPDATE, "setPressed", CMD_SET_PRESSED);
  }

  @Override
  public RCTView createShadowNodeInstance() {
    return new RCTView();
  }

  @Override
  public Class<RCTView> getShadowNodeClass() {
    return RCTView.class;
  }

  @ReactProp(name = "nativeBackgroundAndroid")
  public void setHotspot(FlatViewGroup view, @Nullable ReadableMap bg) {
    view.setHotspot(bg == null ?
            null : ReactDrawableHelper.createDrawableFromJSDescription(view.getContext(), bg));
  }

  @Override
  public void receiveCommand(
      FlatViewGroup view,
      int commandId,
      @Nullable ReadableArray args) {
    switch (commandId) {
      case CMD_HOTSPOT_UPDATE: {
        if (args == null || args.size() != 2) {
          throw new JSApplicationIllegalArgumentException(
              "Illegal number of arguments for 'updateHotspot' command");
        }
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
          view.getLocationOnScreen(TMP_INT_ARRAY);
          float x = PixelUtil.toPixelFromDIP(args.getDouble(0)) - TMP_INT_ARRAY[0];
          float y = PixelUtil.toPixelFromDIP(args.getDouble(1)) - TMP_INT_ARRAY[1];
          view.drawableHotspotChanged(x, y);
        }
        break;
      }
      case CMD_SET_PRESSED: {
        if (args == null || args.size() != 1) {
          throw new JSApplicationIllegalArgumentException(
              "Illegal number of arguments for 'setPressed' command");
        }
        view.setPressed(args.getBoolean(0));
        break;
      }
    }
  }

  @ReactProp(name = ViewProps.NEEDS_OFFSCREEN_ALPHA_COMPOSITING)
  public void setNeedsOffscreenAlphaCompositing(
      FlatViewGroup view,
      boolean needsOffscreenAlphaCompositing) {
    view.setNeedsOffscreenAlphaCompositing(needsOffscreenAlphaCompositing);
  }

  @ReactProp(name = "pointerEvents")
  public void setPointerEvents(FlatViewGroup view, @Nullable String pointerEventsStr) {
    view.setPointerEvents(parsePointerEvents(pointerEventsStr));
  }

  @ReactProp(name = ReactClippingViewGroupHelper.PROP_REMOVE_CLIPPED_SUBVIEWS)
  public void setRemoveClippedSubviews(FlatViewGroup view, boolean removeClippedSubviews) {
    view.setRemoveClippedSubviews(removeClippedSubviews);
  }

  private static PointerEvents parsePointerEvents(@Nullable String pointerEventsStr) {
    if (pointerEventsStr != null) {
      switch (pointerEventsStr) {
        case "none":
          return PointerEvents.NONE;
        case "auto":
          return PointerEvents.AUTO;
        case "box-none":
          return PointerEvents.BOX_NONE;
        case "box-only":
          return PointerEvents.BOX_ONLY;
      }
    }
    // default or invalid
    return PointerEvents.AUTO;
  }

  @ReactProp(name = "hitSlop")
  public void setHitSlop(FlatViewGroup view, @Nullable ReadableMap hitSlop) {
    if (hitSlop == null) {
      view.setHitSlopRect(null);
    } else {
      view.setHitSlopRect(new Rect(
          (int) PixelUtil.toPixelFromDIP(hitSlop.getDouble("left")),
          (int) PixelUtil.toPixelFromDIP(hitSlop.getDouble("top")),
          (int) PixelUtil.toPixelFromDIP(hitSlop.getDouble("right")),
          (int) PixelUtil.toPixelFromDIP(hitSlop.getDouble("bottom"))
      ));
    }
  }
}
