#include "cm_world_sector_private.h"

void SV_TraceEntities_r(cmClipMoveWork_t *traceWork,
                  worldSector_t *sector,
                  float startFraction,
                  float endFraction,
                  const vec3_t start,
                  const vec3_t end)
{
    /*
     * The original jae exits only for ordered >=. Unordered values continue
     * through each negated gate (0x0805e8eb..0x0805e9df).
     */
    if (!(startFraction >= traceWork->bestTrace.fraction) &&
        (traceWork->contentsMask & sector->entityContentsMask) != 0) {
        const int32_t axis = sector->axis;
        const float startDistance = start[axis] - sector->dist;
        const float endDistance = end[axis] - sector->dist;
        const float radius = traceWork->expandedHalfSize[axis];

        if (!(startDistance >= radius) || !(endDistance >= radius)) {
            if (!(-radius >= startDistance) ||
                !(-radius >= endDistance)) {
                float enterFraction;
                float leaveFraction;
                int32_t side;

                if (startDistance < endDistance) {
                    const float invDistanceDelta =
                        1.0f / (startDistance - endDistance);

                    side = 1;
                    enterFraction =
                        (startDistance + radius) * invDistanceDelta;
                    leaveFraction =
                        (startDistance - radius) * invDistanceDelta;
                } else if (endDistance < startDistance) {
                    const float invDistanceDelta =
                        1.0f / (startDistance - endDistance);

                    side = 0;
                    enterFraction =
                        (startDistance - radius) * invDistanceDelta;
                    leaveFraction =
                        (startDistance + radius) * invDistanceDelta;
                } else {
                    side = 0;
                    leaveFraction = 1.0f;
                    enterFraction = 0.0f;
                }

                if (leaveFraction > 1.0f) {
                    leaveFraction = 1.0f;
                }

                {
                    vec3_t middle;
                    const float middleFraction =
                        startFraction +
                        (endFraction - startFraction) * leaveFraction;

                    middle[0] = start[0] + (end[0] - start[0]) * leaveFraction;
                    middle[1] = start[1] + (end[1] - start[1]) * leaveFraction;
                    middle[2] = start[2] + (end[2] - start[2]) * leaveFraction;

                    SV_TraceEntities_r(traceWork,
                                 CM_LoadWorldSector(sector->children[side]),
                                 startFraction,
                                 middleFraction,
                                 start,
                                 middle);
                }

                if (enterFraction < 0.0f) {
                    enterFraction = 0.0f;
                }

                {
                    vec3_t middle;
                    const float middleFraction =
                        startFraction +
                        (endFraction - startFraction) * enterFraction;

                    middle[0] = start[0] + (end[0] - start[0]) * enterFraction;
                    middle[1] = start[1] + (end[1] - start[1]) * enterFraction;
                    middle[2] = start[2] + (end[2] - start[2]) * enterFraction;

                    SV_TraceEntities_r(traceWork,
                                 CM_LoadWorldSector(
                                     sector->children[1 - side]),
                                 middleFraction,
                                 endFraction,
                                 middle,
                                 end);
                }
            } else {
                SV_TraceEntities_r(traceWork,
                             CM_LoadWorldSector(sector->children[1]),
                             startFraction,
                             endFraction,
                             start,
                             end);
            }
        } else {
            SV_TraceEntities_r(traceWork,
                         CM_LoadWorldSector(sector->children[0]),
                         startFraction,
                         endFraction,
                         start,
                         end);
        }

        for (svEntity_t *svEntity =
                 CM_LoadEntityLink(sector->entityLinkHead);
             svEntity != NULL;
             svEntity = CM_LoadEntityLink(svEntity->nextInWorldSector)) {
            SV_ClipMoveToEntity(traceWork, svEntity);
        }
    }
}
