#include "../core_runtime/core_runtime_private.h"
#include "coduo_engine_structs.h"

#include "cm_collision_globals_private.h"

void FloodArea_r(int32_t areaNum, int32_t floodNum)
{
    coduo_collision_area_t *area = &cm_areas[areaNum];
    int32_t *areaPortals;

    if (area->floodvalid == cm_floodValid) {
        if (area->floodnum == floodNum) {
            return;
        }

        Com_Error(1, "\x15" "FloodArea_r: reflooded");
    }

    area->floodnum = floodNum;
    area->floodvalid = cm_floodValid;

    areaPortals = &cm_areaPortals[areaNum * cm_numAreas];
    for (int32_t otherAreaNum = 0; otherAreaNum < cm_numAreas;
         otherAreaNum++) {
        if (areaPortals[otherAreaNum] > 0) {
            FloodArea_r(otherAreaNum, floodNum);
        }
    }
}

void FloodAreaConnections(void)
{
    int32_t floodNum = 0;
    coduo_collision_area_t *area = cm_areas;

    cm_floodValid++;

    for (int32_t areaNum = 0; areaNum < cm_numAreas;
         areaNum++) {
        if (area->floodvalid != cm_floodValid) {
            floodNum++;
            FloodArea_r(areaNum, floodNum);
        }

        area++;
    }
}

void CM_AdjustAreaPortalState(int32_t area1,
                              int32_t area2,
                              qboolean open)
{
    if (area1 < 0 || area2 < 0) {
        return;
    }

    if (area1 >= cm_numAreas || area2 >= cm_numAreas) {
        Com_Error(1, "\x15" "CM_ChangeAreaPortalState: bad area number");
    }

    if (open) {
        cm_areaPortals[area1 * cm_numAreas + area2]++;
        cm_areaPortals[area2 * cm_numAreas + area1]++;
    } else if (cm_areaPortals[area2 * cm_numAreas + area1] != 0) {
        cm_areaPortals[area1 * cm_numAreas + area2]--;
        cm_areaPortals[area2 * cm_numAreas + area1]--;

        if (cm_areaPortals[area2 * cm_numAreas + area1] < 0) {
            Com_Error(1,
                      "\x15" "CM_AdjustAreaPortalState: negative reference count");
        }
    }

    FloodAreaConnections();
}

qboolean CM_AreasConnected(int32_t area1,
                                 int32_t area2)
{
    if (area1 < 0 || area2 < 0) {
        return 0;
    }

    return cm_areas[area1].floodnum == cm_areas[area2].floodnum;
}
