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

#import <yoga/Yoga.h>

#import "RCTAssert.h"
#import "RCTShadowView+Layout.h"

RCTLayoutMetrics RCTLayoutMetricsFromYogaNode(YGNodeRef yogaNode)
{
RCTLayoutMetrics layoutMetrics;

CGRect frame = (CGRect){(CGPoint){RCTCoreGraphicsFloatFromYogaFloat(YGNodeLayoutGetLeft(yogaNode)),
RCTCoreGraphicsFloatFromYogaFloat(YGNodeLayoutGetTop(yogaNode))},
(CGSize){RCTCoreGraphicsFloatFromYogaFloat(YGNodeLayoutGetWidth(yogaNode)),
RCTCoreGraphicsFloatFromYogaFloat(YGNodeLayoutGetHeight(yogaNode))}};

UIEdgeInsets padding =
(UIEdgeInsets){RCTCoreGraphicsFloatFromYogaFloat(YGNodeLayoutGetPadding(yogaNode, YGEdgeTop)),
RCTCoreGraphicsFloatFromYogaFloat(YGNodeLayoutGetPadding(yogaNode, YGEdgeLeft)),
RCTCoreGraphicsFloatFromYogaFloat(YGNodeLayoutGetPadding(yogaNode, YGEdgeBottom)),
RCTCoreGraphicsFloatFromYogaFloat(YGNodeLayoutGetPadding(yogaNode, YGEdgeRight))};

UIEdgeInsets borderWidth =
(UIEdgeInsets){RCTCoreGraphicsFloatFromYogaFloat(YGNodeLayoutGetBorder(yogaNode, YGEdgeTop)),
RCTCoreGraphicsFloatFromYogaFloat(YGNodeLayoutGetBorder(yogaNode, YGEdgeLeft)),
RCTCoreGraphicsFloatFromYogaFloat(YGNodeLayoutGetBorder(yogaNode, YGEdgeBottom)),
RCTCoreGraphicsFloatFromYogaFloat(YGNodeLayoutGetBorder(yogaNode, YGEdgeRight))};

UIEdgeInsets compoundInsets = (UIEdgeInsets){borderWidth.top + padding.top,
borderWidth.left + padding.left,
borderWidth.bottom + padding.bottom,
borderWidth.right + padding.right};

CGRect bounds = (CGRect){CGPointZero, frame.size};
CGRect contentFrame = UIEdgeInsetsInsetRect(bounds, compoundInsets);

layoutMetrics.frame = frame;
layoutMetrics.borderWidth = borderWidth;
layoutMetrics.contentFrame = contentFrame;
layoutMetrics.displayType = RCTReactDisplayTypeFromYogaDisplayType(YGNodeStyleGetDisplay(yogaNode));
layoutMetrics.layoutDirection = RCTUIKitLayoutDirectionFromYogaLayoutDirection(YGNodeLayoutGetDirection(yogaNode));

return layoutMetrics;
}

/**
* Yoga and CoreGraphics have different opinions about how "infinity" value
* should be represented.
* Yoga uses `NAN` which requires additional effort to compare all those values,
* whereas GoreGraphics uses `GFLOAT_MAX` which can be easyly compared with
* standard `==` operator.
*/

float RCTYogaFloatFromCoreGraphicsFloat(CGFloat value)
{
if (value == CGFLOAT_MAX || isnan(value) || isinf(value)) {
return YGUndefined;
}

return value;
}

CGFloat RCTCoreGraphicsFloatFromYogaFloat(float value)
{
if (value == YGUndefined || isnan(value) || isinf(value)) {
return CGFLOAT_MAX;
}

return value;
}

CGFloat RCTCoreGraphicsFloatFromYogaValue(YGValue value, CGFloat baseFloatValue)
{
switch (value.unit) {
case YGUnitPoint:
return RCTCoreGraphicsFloatFromYogaFloat(value.value);
case YGUnitPercent:
return RCTCoreGraphicsFloatFromYogaFloat(value.value) * baseFloatValue;
case YGUnitAuto:
case YGUnitUndefined:
return baseFloatValue;
}
}

YGDirection RCTYogaLayoutDirectionFromUIKitLayoutDirection(UIUserInterfaceLayoutDirection direction)
{
switch (direction) {
case UIUserInterfaceLayoutDirectionRightToLeft:
return YGDirectionRTL;
case UIUserInterfaceLayoutDirectionLeftToRight:
return YGDirectionLTR;
}
}

UIUserInterfaceLayoutDirection RCTUIKitLayoutDirectionFromYogaLayoutDirection(YGDirection direction)
{
switch (direction) {
case YGDirectionInherit:
case YGDirectionLTR:
return UIUserInterfaceLayoutDirectionLeftToRight;
case YGDirectionRTL:
return UIUserInterfaceLayoutDirectionRightToLeft;
}
}

YGDisplay RCTYogaDisplayTypeFromReactDisplayType(RCTDisplayType displayType)
{
switch (displayType) {
case RCTDisplayTypeNone:
return YGDisplayNone;
case RCTDisplayTypeFlex:
return YGDisplayFlex;
case RCTDisplayTypeInline:
RCTAssert(NO, @"RCTDisplayTypeInline cannot be converted to YGDisplay value.");
return YGDisplayNone;
}
}

RCTDisplayType RCTReactDisplayTypeFromYogaDisplayType(YGDisplay displayType)
{
switch (displayType) {
case YGDisplayFlex:
return RCTDisplayTypeFlex;
case YGDisplayNone:
return RCTDisplayTypeNone;
}
}