content: package org.allaymc.server.datastruct.aabb;
  
  import lombok.Getter;
  import lombok.Setter;
  import org.allaymc.api.world.physics.HasAABB;
  import org.joml.primitives.AABBd;
  
  /**
   * @author daoge_cmd
   */
  @Getter
  @Setter
  public final class AABBTreeNode<E extends HasAABB> {
      public static final int INVALID_NODE_INDEX = -1;
  
      public static final int LEFT_CHILD = 0;
      public static final int RIGHT_CHILD = 1;
  
      private static final int MAX_NUM_OF_CHILDREN_PER_NODE = 2;
  
      private final int[] children = new int[MAX_NUM_OF_CHILDREN_PER_NODE];
      private final AABBd aabb = new AABBd();
  
      private int parent = INVALID_NODE_INDEX;
      private int index = INVALID_NODE_INDEX;
      private int height;
      private E data;
  
      public AABBTreeNode() {
          assignChildren(INVALID_NODE_INDEX, INVALID_NODE_INDEX);
      }
  
      public boolean isLeaf() {
          return getLeftChild() == INVALID_NODE_INDEX;
      }
  
      void replaceChild(int childIndexToReplace, int replacement) {
          if (getLeftChild() == childIndexToReplace) {
              assignChild(LEFT_CHILD, replacement);
          } else if (getRightChild() == childIndexToReplace) {
              assignChild(RIGHT_CHILD, replacement);
          }
      }
  
      void assignChild(int whichChild, int childIndex) {
          children[whichChild] = childIndex;
      }
  
      public void assignChildren(int childA, int childB) {
          assignChild(LEFT_CHILD, childA);
          assignChild(RIGHT_CHILD, childB);
      }
  
      void computeAABBWithMargin(float margin) {
          if (data == null) return;
          var offsetAABB = data.getOffsetAABB();
          aabb.setMin(offsetAABB.minX() - margin, offsetAABB.minY() - margin, offsetAABB.minZ() - margin);
          aabb.setMax(offsetAABB.maxX() + margin, offsetAABB.maxY() + margin, offsetAABB.maxZ() + margin);
      }
  
      public void resetForReuse() {
          assignChildren(INVALID_NODE_INDEX, INVALID_NODE_INDEX);
  
          aabb.setMin(Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY);
          aabb.setMax(Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY);
  
          this.parent = INVALID_NODE_INDEX;
          this.height = 0;
          this.data = null;
      }
  
      public int getLeftChild() {
          return children[LEFT_CHILD];
      }
  
      public int getRightChild() {
          return children[RIGHT_CHILD];
      }
  }
  