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

#pragma once

#include <assert.h>
#include <math.h>
#include <stdarg.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>

#ifndef __cplusplus
#include <stdbool.h>
#endif

#include <yoga/YGEnums.h>
#include <yoga/YGMacros.h>
#include <yoga/YGValue.h>

YG_EXTERN_C_BEGIN

typedef struct YGSize {
  float width;
  float height;
} YGSize;

typedef struct YGConfig* YGConfigRef;

typedef struct YGNode* YGNodeRef;
typedef const struct YGNode* YGNodeConstRef;

typedef YGSize (*YGMeasureFunc)(
    YGNodeRef node,
    float width,
    YGMeasureMode widthMode,
    float height,
    YGMeasureMode heightMode);
typedef float (*YGBaselineFunc)(YGNodeRef node, float width, float height);
typedef void (*YGDirtiedFunc)(YGNodeRef node);
typedef void (*YGPrintFunc)(YGNodeRef node);
typedef void (*YGNodeCleanupFunc)(YGNodeRef node);
typedef int (*YGLogger)(
    YGConfigRef config,
    YGNodeRef node,
    YGLogLevel level,
    const char* format,
    va_list args);
typedef YGNodeRef (
    *YGCloneNodeFunc)(YGNodeRef oldNode, YGNodeRef owner, int childIndex);

// YGNode
YOGA_EXPORT YGNodeRef YGNodeNew(void);
YOGA_EXPORT YGNodeRef YGNodeNewWithConfig(YGConfigRef config);
YOGA_EXPORT YGNodeRef YGNodeClone(YGNodeRef node);
YOGA_EXPORT void YGNodeFree(YGNodeRef node);
YOGA_EXPORT void YGNodeFreeRecursiveWithCleanupFunc(
    YGNodeRef node,
    YGNodeCleanupFunc cleanup);
YOGA_EXPORT void YGNodeFreeRecursive(YGNodeRef node);
YOGA_EXPORT void YGNodeReset(YGNodeRef node);

YOGA_EXPORT void YGNodeInsertChild(
    YGNodeRef node,
    YGNodeRef child,
    uint32_t index);

YOGA_EXPORT void YGNodeSwapChild(
    YGNodeRef node,
    YGNodeRef child,
    uint32_t index);

YOGA_EXPORT void YGNodeRemoveChild(YGNodeRef node, YGNodeRef child);
YOGA_EXPORT void YGNodeRemoveAllChildren(YGNodeRef node);
YOGA_EXPORT YGNodeRef YGNodeGetChild(YGNodeRef node, uint32_t index);
YOGA_EXPORT YGNodeRef YGNodeGetOwner(YGNodeRef node);
YOGA_EXPORT YGNodeRef YGNodeGetParent(YGNodeRef node);
YOGA_EXPORT uint32_t YGNodeGetChildCount(YGNodeRef node);
YOGA_EXPORT void YGNodeSetChildren(
    YGNodeRef owner,
    const YGNodeRef* children,
    uint32_t count);

YOGA_EXPORT void YGNodeSetIsReferenceBaseline(
    YGNodeRef node,
    bool isReferenceBaseline);

YOGA_EXPORT bool YGNodeIsReferenceBaseline(YGNodeRef node);

YOGA_EXPORT void YGNodeCalculateLayout(
    YGNodeRef node,
    float availableWidth,
    float availableHeight,
    YGDirection ownerDirection);

// Mark a node as dirty. Only valid for nodes with a custom measure function
// set.
//
// Yoga knows when to mark all other nodes as dirty but because nodes with
// measure functions depend on information not known to Yoga they must perform
// this dirty marking manually.
YOGA_EXPORT void YGNodeMarkDirty(YGNodeRef node);

// Marks the current node and all its descendants as dirty.
//
// Intended to be used for Yoga benchmarks. Don't use in production, as calling
// `YGCalculateLayout` will cause the recalculation of each and every node.
YOGA_EXPORT void YGNodeMarkDirtyAndPropagateToDescendants(YGNodeRef node);

YOGA_EXPORT void YGNodePrint(YGNodeRef node, YGPrintOptions options);

YOGA_EXPORT bool YGFloatIsUndefined(float value);

YOGA_EXPORT bool YGNodeCanUseCachedMeasurement(
    YGMeasureMode widthMode,
    float width,
    YGMeasureMode heightMode,
    float height,
    YGMeasureMode lastWidthMode,
    float lastWidth,
    YGMeasureMode lastHeightMode,
    float lastHeight,
    float lastComputedWidth,
    float lastComputedHeight,
    float marginRow,
    float marginColumn,
    YGConfigRef config);

YOGA_EXPORT void YGNodeCopyStyle(YGNodeRef dstNode, YGNodeRef srcNode);

YOGA_EXPORT void* YGNodeGetContext(YGNodeRef node);
YOGA_EXPORT void YGNodeSetContext(YGNodeRef node, void* context);

YOGA_EXPORT YGConfigRef YGNodeGetConfig(YGNodeRef node);
YOGA_EXPORT void YGNodeSetConfig(YGNodeRef node, YGConfigRef config);

void YGConfigSetPrintTreeFlag(YGConfigRef config, bool enabled);
bool YGNodeHasMeasureFunc(YGNodeRef node);
YOGA_EXPORT void YGNodeSetMeasureFunc(
    YGNodeRef node,
    YGMeasureFunc measureFunc);
bool YGNodeHasBaselineFunc(YGNodeRef node);
void YGNodeSetBaselineFunc(YGNodeRef node, YGBaselineFunc baselineFunc);
YGDirtiedFunc YGNodeGetDirtiedFunc(YGNodeRef node);
void YGNodeSetDirtiedFunc(YGNodeRef node, YGDirtiedFunc dirtiedFunc);
void YGNodeSetPrintFunc(YGNodeRef node, YGPrintFunc printFunc);
YOGA_EXPORT bool YGNodeGetHasNewLayout(YGNodeRef node);
YOGA_EXPORT void YGNodeSetHasNewLayout(YGNodeRef node, bool hasNewLayout);
YGNodeType YGNodeGetNodeType(YGNodeRef node);
void YGNodeSetNodeType(YGNodeRef node, YGNodeType nodeType);
YOGA_EXPORT bool YGNodeIsDirty(YGNodeRef node);

YOGA_EXPORT void YGNodeStyleSetDirection(YGNodeRef node, YGDirection direction);
YOGA_EXPORT YGDirection YGNodeStyleGetDirection(YGNodeConstRef node);

YOGA_EXPORT void YGNodeStyleSetFlexDirection(
    YGNodeRef node,
    YGFlexDirection flexDirection);
YOGA_EXPORT YGFlexDirection YGNodeStyleGetFlexDirection(YGNodeConstRef node);

YOGA_EXPORT void YGNodeStyleSetJustifyContent(
    YGNodeRef node,
    YGJustify justifyContent);
YOGA_EXPORT YGJustify YGNodeStyleGetJustifyContent(YGNodeConstRef node);

YOGA_EXPORT void YGNodeStyleSetAlignContent(
    YGNodeRef node,
    YGAlign alignContent);
YOGA_EXPORT YGAlign YGNodeStyleGetAlignContent(YGNodeConstRef node);

YOGA_EXPORT void YGNodeStyleSetAlignItems(YGNodeRef node, YGAlign alignItems);
YOGA_EXPORT YGAlign YGNodeStyleGetAlignItems(YGNodeConstRef node);

YOGA_EXPORT void YGNodeStyleSetAlignSelf(YGNodeRef node, YGAlign alignSelf);
YOGA_EXPORT YGAlign YGNodeStyleGetAlignSelf(YGNodeConstRef node);

YOGA_EXPORT void YGNodeStyleSetPositionType(
    YGNodeRef node,
    YGPositionType positionType);
YOGA_EXPORT YGPositionType YGNodeStyleGetPositionType(YGNodeConstRef node);

YOGA_EXPORT void YGNodeStyleSetFlexWrap(YGNodeRef node, YGWrap flexWrap);
YOGA_EXPORT YGWrap YGNodeStyleGetFlexWrap(YGNodeConstRef node);

YOGA_EXPORT void YGNodeStyleSetOverflow(YGNodeRef node, YGOverflow overflow);
YOGA_EXPORT YGOverflow YGNodeStyleGetOverflow(YGNodeConstRef node);

YOGA_EXPORT void YGNodeStyleSetDisplay(YGNodeRef node, YGDisplay display);
YOGA_EXPORT YGDisplay YGNodeStyleGetDisplay(YGNodeConstRef node);

YOGA_EXPORT void YGNodeStyleSetFlex(YGNodeRef node, float flex);
YOGA_EXPORT float YGNodeStyleGetFlex(YGNodeConstRef node);

YOGA_EXPORT void YGNodeStyleSetFlexGrow(YGNodeRef node, float flexGrow);
YOGA_EXPORT float YGNodeStyleGetFlexGrow(YGNodeConstRef node);

YOGA_EXPORT void YGNodeStyleSetFlexShrink(YGNodeRef node, float flexShrink);
YOGA_EXPORT float YGNodeStyleGetFlexShrink(YGNodeConstRef node);

YOGA_EXPORT void YGNodeStyleSetFlexBasis(YGNodeRef node, float flexBasis);
YOGA_EXPORT void YGNodeStyleSetFlexBasisPercent(
    YGNodeRef node,
    float flexBasis);
YOGA_EXPORT void YGNodeStyleSetFlexBasisAuto(YGNodeRef node);
YOGA_EXPORT YGValue YGNodeStyleGetFlexBasis(YGNodeConstRef node);

YOGA_EXPORT void YGNodeStyleSetPosition(
    YGNodeRef node,
    YGEdge edge,
    float position);
YOGA_EXPORT void YGNodeStyleSetPositionPercent(
    YGNodeRef node,
    YGEdge edge,
    float position);
YOGA_EXPORT YGValue YGNodeStyleGetPosition(YGNodeConstRef node, YGEdge edge);

YOGA_EXPORT void YGNodeStyleSetMargin(
    YGNodeRef node,
    YGEdge edge,
    float margin);
YOGA_EXPORT void YGNodeStyleSetMarginPercent(
    YGNodeRef node,
    YGEdge edge,
    float margin);
YOGA_EXPORT void YGNodeStyleSetMarginAuto(YGNodeRef node, YGEdge edge);
YOGA_EXPORT YGValue YGNodeStyleGetMargin(YGNodeConstRef node, YGEdge edge);

YOGA_EXPORT void YGNodeStyleSetPadding(
    YGNodeRef node,
    YGEdge edge,
    float padding);
YOGA_EXPORT void YGNodeStyleSetPaddingPercent(
    YGNodeRef node,
    YGEdge edge,
    float padding);
YOGA_EXPORT YGValue YGNodeStyleGetPadding(YGNodeConstRef node, YGEdge edge);

YOGA_EXPORT void YGNodeStyleSetBorder(
    YGNodeRef node,
    YGEdge edge,
    float border);
YOGA_EXPORT float YGNodeStyleGetBorder(YGNodeConstRef node, YGEdge edge);

YOGA_EXPORT void YGNodeStyleSetGap(
    YGNodeRef node,
    YGGutter gutter,
    float gapLength);
YOGA_EXPORT float YGNodeStyleGetGap(YGNodeConstRef node, YGGutter gutter);

YOGA_EXPORT void YGNodeStyleSetWidth(YGNodeRef node, float width);
YOGA_EXPORT void YGNodeStyleSetWidthPercent(YGNodeRef node, float width);
YOGA_EXPORT void YGNodeStyleSetWidthAuto(YGNodeRef node);
YOGA_EXPORT YGValue YGNodeStyleGetWidth(YGNodeConstRef node);

YOGA_EXPORT void YGNodeStyleSetHeight(YGNodeRef node, float height);
YOGA_EXPORT void YGNodeStyleSetHeightPercent(YGNodeRef node, float height);
YOGA_EXPORT void YGNodeStyleSetHeightAuto(YGNodeRef node);
YOGA_EXPORT YGValue YGNodeStyleGetHeight(YGNodeConstRef node);

YOGA_EXPORT void YGNodeStyleSetMinWidth(YGNodeRef node, float minWidth);
YOGA_EXPORT void YGNodeStyleSetMinWidthPercent(YGNodeRef node, float minWidth);
YOGA_EXPORT YGValue YGNodeStyleGetMinWidth(YGNodeConstRef node);

YOGA_EXPORT void YGNodeStyleSetMinHeight(YGNodeRef node, float minHeight);
YOGA_EXPORT void YGNodeStyleSetMinHeightPercent(
    YGNodeRef node,
    float minHeight);
YOGA_EXPORT YGValue YGNodeStyleGetMinHeight(YGNodeConstRef node);

YOGA_EXPORT void YGNodeStyleSetMaxWidth(YGNodeRef node, float maxWidth);
YOGA_EXPORT void YGNodeStyleSetMaxWidthPercent(YGNodeRef node, float maxWidth);
YOGA_EXPORT YGValue YGNodeStyleGetMaxWidth(YGNodeConstRef node);

YOGA_EXPORT void YGNodeStyleSetMaxHeight(YGNodeRef node, float maxHeight);
YOGA_EXPORT void YGNodeStyleSetMaxHeightPercent(
    YGNodeRef node,
    float maxHeight);
YOGA_EXPORT YGValue YGNodeStyleGetMaxHeight(YGNodeConstRef node);

// Yoga specific properties, not compatible with flexbox specification Aspect
// ratio control the size of the undefined dimension of a node. Aspect ratio is
// encoded as a floating point value width/height. e.g. A value of 2 leads to a
// node with a width twice the size of its height while a value of 0.5 gives the
// opposite effect.
//
// - On a node with a set width/height aspect ratio control the size of the
//   unset dimension
// - On a node with a set flex basis aspect ratio controls the size of the node
//   in the cross axis if unset
// - On a node with a measure function aspect ratio works as though the measure
//   function measures the flex basis
// - On a node with flex grow/shrink aspect ratio controls the size of the node
//   in the cross axis if unset
// - Aspect ratio takes min/max dimensions into account
YOGA_EXPORT void YGNodeStyleSetAspectRatio(YGNodeRef node, float aspectRatio);
YOGA_EXPORT float YGNodeStyleGetAspectRatio(YGNodeConstRef node);

YOGA_EXPORT float YGNodeLayoutGetLeft(YGNodeRef node);
YOGA_EXPORT float YGNodeLayoutGetTop(YGNodeRef node);
YOGA_EXPORT float YGNodeLayoutGetRight(YGNodeRef node);
YOGA_EXPORT float YGNodeLayoutGetBottom(YGNodeRef node);
YOGA_EXPORT float YGNodeLayoutGetWidth(YGNodeRef node);
YOGA_EXPORT float YGNodeLayoutGetHeight(YGNodeRef node);
YOGA_EXPORT YGDirection YGNodeLayoutGetDirection(YGNodeRef node);
YOGA_EXPORT bool YGNodeLayoutGetHadOverflow(YGNodeRef node);

// Get the computed values for these nodes after performing layout. If they were
// set using point values then the returned value will be the same as
// YGNodeStyleGetXXX. However if they were set using a percentage value then the
// returned value is the computed value used during layout.
YOGA_EXPORT float YGNodeLayoutGetMargin(YGNodeRef node, YGEdge edge);
YOGA_EXPORT float YGNodeLayoutGetBorder(YGNodeRef node, YGEdge edge);
YOGA_EXPORT float YGNodeLayoutGetPadding(YGNodeRef node, YGEdge edge);

YOGA_EXPORT void YGConfigSetLogger(YGConfigRef config, YGLogger logger);
YOGA_EXPORT void YGAssert(bool condition, const char* message);
YOGA_EXPORT void YGAssertWithNode(
    YGNodeRef node,
    bool condition,
    const char* message);
YOGA_EXPORT void YGAssertWithConfig(
    YGConfigRef config,
    bool condition,
    const char* message);
// Set this to number of pixels in 1 point to round calculation results If you
// want to avoid rounding - set PointScaleFactor to 0
YOGA_EXPORT void YGConfigSetPointScaleFactor(
    YGConfigRef config,
    float pixelsInPoint);
YOGA_EXPORT float YGConfigGetPointScaleFactor(YGConfigRef config);

// Yoga previously had an error where containers would take the maximum space
// possible instead of the minimum like they are supposed to. In practice this
// resulted in implicit behaviour similar to align-self: stretch; Because this
// was such a long-standing bug we must allow legacy users to switch back to
// this behaviour.
YOGA_EXPORT YG_DEPRECATED(
    "Please use "
    "\"YGConfigGetErrata()\"") bool YGConfigGetUseLegacyStretchBehaviour(YGConfigRef
                                                                             config);
YOGA_EXPORT
YG_DEPRECATED(
    "\"YGConfigSetUseLegacyStretchBehaviour\" will be removed in the next "
    "release. Usage should be replaced with \"YGConfigSetErrata(YGErrataAll)\" "
    "to opt out of all future breaking conformance fixes, or "
    "\"YGConfigSetErrata(YGErrataStretchFlexBasis)\" to opt out of the "
    "specific conformance fix previously disabled by "
    "\"UseLegacyStretchBehaviour\".")
void YGConfigSetUseLegacyStretchBehaviour(
    YGConfigRef config,
    bool useLegacyStretchBehaviour);

// YGConfig
YOGA_EXPORT YGConfigRef YGConfigNew(void);
YOGA_EXPORT void YGConfigFree(YGConfigRef config);
YOGA_EXPORT void YGConfigCopy(YGConfigRef dest, YGConfigRef src);
YOGA_EXPORT int32_t YGConfigGetInstanceCount(void);

YOGA_EXPORT void YGConfigSetExperimentalFeatureEnabled(
    YGConfigRef config,
    YGExperimentalFeature feature,
    bool enabled);
YOGA_EXPORT bool YGConfigIsExperimentalFeatureEnabled(
    YGConfigRef config,
    YGExperimentalFeature feature);

// Using the web defaults is the preferred configuration for new projects. Usage
// of non web defaults should be considered as legacy.
YOGA_EXPORT void YGConfigSetUseWebDefaults(YGConfigRef config, bool enabled);
YOGA_EXPORT bool YGConfigGetUseWebDefaults(YGConfigRef config);

YOGA_EXPORT void YGConfigSetCloneNodeFunc(
    YGConfigRef config,
    YGCloneNodeFunc callback);

// Export only for C#
YOGA_EXPORT YGConfigRef YGConfigGetDefault(void);

YOGA_EXPORT void YGConfigSetContext(YGConfigRef config, void* context);
YOGA_EXPORT void* YGConfigGetContext(YGConfigRef config);

YOGA_EXPORT void YGConfigSetErrata(YGConfigRef config, YGErrata errata);
YOGA_EXPORT YGErrata YGConfigGetErrata(YGConfigRef config);

YOGA_EXPORT float YGRoundValueToPixelGrid(
    double value,
    double pointScaleFactor,
    bool forceCeil,
    bool forceFloor);

YG_EXTERN_C_END
