#include "cm_world_sector_private.h"

void SV_LinkEntityToWorldSector(svEntity_t *svEntity,
                                const vec3_t mins, const vec3_t maxs)
{
    int32_t contentsMask;
    worldSector_t *sector;
    int32_t axis;
    float dist;
    float sectorMins[2];
    float sectorMaxs[2];
    int stoppedAtNullChild;

    contentsMask = SV_GEntityForSvEntity(svEntity)->contents;

    do {
        sectorMins[0] = cm_worldMins[0];
        sectorMins[1] = cm_worldMins[1];
        sectorMaxs[0] = cm_worldMaxs[0];
        sectorMaxs[1] = cm_worldMaxs[1];
        sector = &cm_worldSectorRoot;
        stoppedAtNullChild = 0;

        while (1) {
            sector->entityContentsMask |= contentsMask;
            axis = sector->axis;
            dist = sector->dist;

            if (mins[axis] > dist) {
                sectorMins[axis] = dist;
                if (CM_LoadWorldSector(sector->children[0]) ==
                    &cm_nullWorldSector) {
                    stoppedAtNullChild = 1;
                    break;
                }
                sector = CM_LoadWorldSector(sector->children[0]);
                continue;
            }

            if (!(dist > maxs[axis])) {
                break;
            }

            sectorMaxs[axis] = dist;
            if (CM_LoadWorldSector(sector->children[1]) ==
                &cm_nullWorldSector) {
                stoppedAtNullChild = 1;
                break;
            }
            sector = CM_LoadWorldSector(sector->children[1]);
        }

        if (!stoppedAtNullChild &&
            sector == CM_LoadWorldSector(svEntity->worldSector) &&
            ((~contentsMask & svEntity->contentsMask) == 0)) {
            svEntity->contentsMask = contentsMask;
            svEntity->linkMins[0] = mins[0];
            svEntity->linkMins[1] = mins[1];
            svEntity->linkMaxs[0] = maxs[0];
            svEntity->linkMaxs[1] = maxs[1];
            return;
        }

        if (svEntity->worldSector != 0) {
            if (sector == CM_LoadWorldSector(svEntity->worldSector) &&
                ((~contentsMask & svEntity->contentsMask) == 0)) {
                svEntity->contentsMask = contentsMask;
                svEntity->linkMins[0] = mins[0];
                svEntity->linkMins[1] = mins[1];
                svEntity->linkMaxs[0] = maxs[0];
                svEntity->linkMaxs[1] = maxs[1];
                CM_RebucketWorldSectorLinks(sector, sectorMins, sectorMaxs);
                return;
            }

            SV_UnlinkEntityFromWorldSector(svEntity);
            continue;
        }

        svEntity->worldSector = CM_StoreWorldSector(sector);
        svEntity->nextInWorldSector = sector->entityLinkHead;
        sector->entityLinkHead = CM_StoreEntityLink(svEntity);

        svEntity->contentsMask = contentsMask;
        svEntity->linkMins[0] = mins[0];
        svEntity->linkMins[1] = mins[1];
        svEntity->linkMaxs[0] = maxs[0];
        svEntity->linkMaxs[1] = maxs[1];
        CM_RebucketWorldSectorLinks(sector, sectorMins, sectorMaxs);
        return;
    } while (1);
}
