/*
 * Copyright 2014-present Facebook, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.facebook.litho.widget;

import static com.facebook.litho.widget.CardShadowDrawable.getShadowBottom;
import static com.facebook.litho.widget.CardShadowDrawable.getShadowHorizontal;
import static com.facebook.litho.widget.CardShadowDrawable.getShadowTop;
import static com.facebook.yoga.YogaEdge.ALL;
import static com.facebook.yoga.YogaEdge.BOTTOM;
import static com.facebook.yoga.YogaEdge.HORIZONTAL;
import static com.facebook.yoga.YogaEdge.TOP;
import static com.facebook.yoga.YogaPositionType.ABSOLUTE;

import android.content.res.Resources;
import android.graphics.Color;
import com.facebook.litho.Column;
import com.facebook.litho.Component;
import com.facebook.litho.ComponentContext;
import com.facebook.litho.annotations.LayoutSpec;
import com.facebook.litho.annotations.OnCreateLayout;
import com.facebook.litho.annotations.Prop;
import com.facebook.litho.annotations.PropDefault;
import com.facebook.litho.annotations.ResType;

/**
 * A component that renders a given component into a card border with shadow.
 *
 * @prop cardBackgroundColor Background color for the card.
 * @prop clippingColor Color for corner clipping.
 * @prop shadowStartColor Start color for shadow drawn underneath the card.
 * @prop shadowEndColor End color for shadow drawn underneath the card.
 * @prop cornerRadius Corner radius for the card.
 * @prop elevation Elevation of the card.
 * @prop shadowBottomOverride Override of size of shadow at bottom of card.
 */
@LayoutSpec(isPureRender = true)
class CardSpec {

  private static final int DEFAULT_CORNER_RADIUS_DP = 2;
  private static final int DEFAULT_SHADOW_SIZE_DP = 2;

  @PropDefault static final int cardBackgroundColor = Color.WHITE;
  @PropDefault static final int clippingColor = Color.WHITE;
  @PropDefault static final int shadowStartColor = 0x37000000;
  @PropDefault static final int shadowEndColor = 0x03000000;
  @PropDefault static final float cornerRadius = -1;
  @PropDefault static final float elevation = -1;
  @PropDefault static final int shadowBottomOverride = -1;

  private static float pixels(Resources resources, int dips) {
    final float scale = resources.getDisplayMetrics().density;
    return dips * scale + 0.5f;
  }

  @OnCreateLayout
  static Component onCreateLayout(
      ComponentContext c,
      @Prop Component content,
      @Prop(optional = true, resType = ResType.COLOR) int cardBackgroundColor,
      @Prop(optional = true, resType = ResType.COLOR) int clippingColor,
      @Prop(optional = true, resType = ResType.COLOR) int shadowStartColor,
      @Prop(optional = true, resType = ResType.COLOR) int shadowEndColor,
      @Prop(optional = true, resType = ResType.DIMEN_OFFSET) float cornerRadius,
      @Prop(optional = true, resType = ResType.DIMEN_OFFSET) float elevation,
      @Prop(optional = true, resType = ResType.DIMEN_OFFSET) int shadowBottomOverride) {

    final Resources resources = c.getBaseContext().getResources();

    if (cornerRadius == -1) {
      cornerRadius = pixels(resources, DEFAULT_CORNER_RADIUS_DP);
    }

    if (elevation == -1) {
      elevation = pixels(resources, DEFAULT_SHADOW_SIZE_DP);
    }

    final int shadowTop = getShadowTop(elevation);
    final int shadowBottom =
        shadowBottomOverride == -1 ? getShadowBottom(elevation) : shadowBottomOverride;
    final int shadowHorizontal = getShadowHorizontal(elevation);

    return Column.create(c)
        .child(
            Column.create(c)
                .marginPx(HORIZONTAL, shadowHorizontal)
                .marginPx(TOP, shadowTop)
                .marginPx(BOTTOM, shadowBottom)
                .backgroundColor(cardBackgroundColor)
                .child(content)
                .child(
                    CardClip.create(c)
                        .clippingColor(clippingColor)
                        .cornerRadiusPx(cornerRadius)
                        .positionType(ABSOLUTE)
                        .positionPx(ALL, 0)))
        .child(
            elevation > 0
                ? CardShadow.create(c)
                    .shadowStartColor(shadowStartColor)
                    .shadowEndColor(shadowEndColor)
                    .cornerRadiusPx(cornerRadius)
                    .shadowSizePx(elevation)
                    .positionType(ABSOLUTE)
                    .positionPx(ALL, 0)
                : null)
        .build();
  }
}

@@ -2059,16 +2059,528 @@
 f card.%0A
+ * @prop disableClipTopLeft If set, opt out of clipping the top-left corner, elevation will force to%0A *     0 in this case.%0A * @prop disableClipTopRight If set, opt out of clipping the top-right corner, elevation will force%0A *     to 0 in this case.%0A * @prop disableClipBottomLeft If set, opt out of clipping the bottom-left corner, elevation will%0A *     force to 0 in this case.%0A * @prop disableClipBottomRight If set, opt out of clipping the bottom-right corner, elevation will%0A *     force to 0 in this case.%0A
  */%0A@Lay
@@ -3973,16 +3973,252 @@
 Override
+,%0A      @Prop(optional = true) boolean disableClipTopLeft,%0A      @Prop(optional = true) boolean disableClipTopRight,%0A      @Prop(optional = true) boolean disableClipBottomLeft,%0A      @Prop(optional = true) boolean disableClipBottomRight
 ) %7B%0A%0A   
@@ -4392,16 +4392,172 @@
 %0A    if 
+(disableClipTopLeft%0A        %7C%7C disableClipTopRight%0A        %7C%7C disableClipBottomLeft%0A        %7C%7C disableClipBottomRight) %7B%0A      elevation = 0;%0A    %7D else if 
 (elevati
@@ -5437,16 +5437,288 @@
 (ALL, 0)
+%0A                        .disableClipTopLeft(disableClipTopLeft)%0A                        .disableClipTopRight(disableClipTopRight)%0A                        .disableClipBottomLeft(disableClipBottomLeft)%0A                        .disableClipBottomRight(disableClipBottomRight)
 ))%0A     

add disableClip API to CardSpec