/* savebsp.m */

#include "idbsp.h"

/* id           secdefstore_i; */
STORAGE            *secdefstore_i;

/*
   #define         MAXVERTEX               8192
   #define         MAXTOUCHSECS    16
   #define         MAXSECTORS              2048
   #define         MAXSUBSECTORS   2048
 */

int                 vertexsubcount[MAXVERTEX];
short               vertexsublist[MAXVERTEX][MAXTOUCHSECS];

/* short **vertexsublist; */

int                 subsectordef[MAXSUBSECTORS];
int                 subsectornum[MAXSUBSECTORS];

int                 buildsector;


/*
   ==========================
   =
   = RecursiveGroupSubsector
   =
   ==========================
 */

void                RecursiveGroupSubsector(int ssnum)
{
	int                 i,
	                    l,
	                    count;
	int                 vertex;
	int                 checkss;
	short              *vertsub;

/*      short vertsub[MAXTOUCHSECS]; */

	int                 vt;
	mapseg_t           *seg;
	mapsubsector_t     *ss;
	maplinedef_t       *ld;
	mapsidedef_t       *sd;

/*      ss = [subsecstore_i elementAt:ssnum]; */
	ss = (mapsubsector_t *) subsecstore_i -> data + ssnum;
	subsectornum[ssnum] = buildsector;

	for (l = 0; l < ss -> numsegs; l++)
		{
/*
   seg = [maplinestore_i elementAt: ss->firstseg+l];
   ld = [ldefstore_i elementAt: seg->linedef];
 */
		seg = (mapseg_t *) maplinestore_i -> data + ss -> firstseg + l;
		ld = (maplinedef_t *) ldefstore_i -> data + seg -> linedef;
		DrawLineDef(ld);
/*              sd = [sdefstore_i elementAt: ld->sidenum[seg->side]]; */
		sd = (mapsidedef_t *) sdefstore_i -> data + ld -> sidenum[seg -> side];
		sd -> sector = buildsector;

		for (vt = 0; vt < 2; vt++)
			{
			if (vt)
				vertex = seg -> v1;
			else
				vertex = seg -> v2;

			vertsub = vertexsublist[vertex];
/*
   fseek(vertexsublist, vertex * MAXTOUCHSECS, SEEK_SET);
   fread(vertsub,sizeof(short),MAXTOUCHSECS,vertexsublist);
 */
			count = vertexsubcount[vertex];
			for (i = 0; i < count; i++)
				{
				checkss = vertsub[i];
				if (subsectordef[checkss] == subsectordef[ssnum])
					{
					if (subsectornum[checkss] == -1)
						{
						RecursiveGroupSubsector(checkss);
						continue;
						}
					if (subsectornum[checkss] != buildsector)
						/*      Error ("RecusiveGroup: regrouped a sector"); */
						Error("RecursiveGroupSubsector: regrouped (%d (subsectornum[%d]) != %d",
							subsectornum[checkss], checkss, buildsector);

					}
				}
			}
		}
}

/*
   =================
   =
   = UniqueSector
   =
   = Returns the sector number, adding a new sector if needed
   =================
 */

int                 UniqueSector(sectordef_t * def)
{
	int                 i,
	                    count;
	mapsector_t         ms,
	                   *msp;

	ms.floorheight = def -> floorheight;
	ms.ceilingheight = def -> ceilingheight;
	memcpy(ms.floorpic, def -> floorflat, 8);
	memcpy(ms.ceilingpic, def -> ceilingflat, 8);
	ms.lightlevel = def -> lightlevel;
	ms.special = def -> special;
	ms.tag = def -> tag;

/*
   see if an identical sector already exists
   count = [secdefstore_i count];
   msp = [secdefstore_i elementAt:0];
 */
	count = secdefstore_i -> count;
	msp = (mapsector_t *) secdefstore_i -> data;
	for (i = 0; i < count; i++, msp++)
/*
   if (!bcmp(msp, &ms, sizeof(ms)))
   return i;
 */
		if (!memcmp(msp, &ms, sizeof(ms)))
			return i;

/*      [secdefstore_i addElement: &ms]; */
	memcpy((mapsector_t *) secdefstore_i -> data + secdefstore_i -> count, &ms, sizeof(mapsector_t));
	secdefstore_i -> count += 1;
	secdefstore_i -> data = (mapsector_t *) realloc(secdefstore_i -> data,
		sizeof(mapsector_t) * (secdefstore_i -> count + 1));

	return count;
}




void                AddSubsectorToVertex(int subnum, int vertex)
{
	int                 j;

/*      short vsl[MAXTOUCHSECS]; */

	for (j = 0; j < vertexsubcount[vertex]; j++)
		if (vertexsublist[vertex][j] == subnum)
			return;
	vertexsublist[vertex][j] = subnum;
	vertexsubcount[vertex]++;
/*
   fseek(vertexsublist, vertex * MAXTOUCHSECS, SEEK_SET);
   fread(vsl,sizeof(short),MAXTOUCHSECS, vertexsublist);

   for (j=0;j<vertexsubcount[vertex];j++)
   if (vsl[j] == subnum)
   return

   vsl[j] = subnum;
   vertexsubcount[vertex]++;

   fseek(vertexsublist, -MAXTOUCHSECS, SEEK_CUR);
   fwrite(vsl,sizeof(short),MAXTOUCHSECS, vertexsublist);
 */
}


/*
   ================
   =
   = BuildSectordefs
   =
   = Call before ProcessNodes
   ================
 */

void                BuildSectordefs(void)
{
	int                 i;
	worldline_t        *wl;
	int                 count;
	mapseg_t           *seg;

/*
   build sectordef list
 */
/*
   secdefstore_i = [[Storage alloc]
   initCount:              0
   elementSize:    sizeof(mapsector_t)
   description:    NULL];
 */

	secdefstore_i = (STORAGE *) SafeMalloc(sizeof(STORAGE));
	secdefstore_i -> data = (mapsector_t *) SafeMalloc(sizeof(mapsector_t));
	secdefstore_i -> count = 0;
	secdefstore_i -> size = sizeof(mapsector_t);

/*
   count = [linestore_i count];
   wl= [linestore_i elementAt:0];
 */

	count = linestore_i -> count;
	wl = linestore_i -> data;
	for (i = 0; i < count; i++, wl++)
		{
/*
   seg = [maplinestore_i elementAt: i];
 */
/*                seg = (mapseg_t *)maplinestore_i->data + i; */
		wl -> side[0].sector = UniqueSector(&wl -> side[0].sectordef);
		if (wl -> flags & ML_TWOSIDED)
			{
			wl -> side[1].sector = UniqueSector(&wl -> side[1].sectordef);
			}
		}
}


/*
   ================
   =
   = ProcessSectors
   =
   = Must be called after ProcessNodes, because it references the subsector list
   ================
 */

void                ProcessSectors(void)
{
	int                 i,
	                    l;
	int                 numss;
	mapsubsector_t     *ss;
	mapsector_t         sec;
	mapseg_t           *seg;
	maplinedef_t       *ml;
	mapsidedef_t       *ms;

/*
   build a connection matrix that lists all the subsectors that touch
   each vertex
 */
	memset(vertexsubcount, 0, sizeof(vertexsubcount));
	memset(vertexsublist, 0, sizeof(vertexsublist));
/*      memset(vertexsublist, 0, MAXVERTEX * MAXTOUCHSECS); */
/*      numss = [subsecstore_i count]; */
	numss = subsecstore_i -> count;

	printf("\n");
	for (i = 0; i < numss; i++)
		{
/*              ss = [subsecstore_i elementAt: i]; */
		printf("Processing subsector #%d of %d\r", i, numss);
		ss = (mapsubsector_t *) subsecstore_i -> data + i;
		for (l = 0; l < ss -> numsegs; l++)
			{
/*                      seg = [maplinestore_i elementAt: ss->firstseg+l]; */
			seg = (mapseg_t *) maplinestore_i -> data + ss -> firstseg + l;
			AddSubsectorToVertex(i, seg -> v1);
			AddSubsectorToVertex(i, seg -> v2);
			}
		subsectornum[i] = -1;		   /* ungrouped */
/*
   ml = [ldefstore_i elementAt: seg->linedef];
   ms = [sdefstore_i elementAt: ml->sidenum[seg->side]];
 */
		ml = (maplinedef_t *) ldefstore_i -> data + seg -> linedef;
		ms = (mapsidedef_t *) sdefstore_i -> data + ml -> sidenum[seg -> side];
		subsectordef[i] = ms -> sector;
		}

/*
   recursively build final sectors
 */
/*
   secstore_i = [[Storage alloc]
   initCount:              0
   elementSize:    sizeof(mapsector_t)
   description:    NULL];
 */
	secstore_i = (STORAGE *) SafeMalloc(sizeof(STORAGE));
	secstore_i -> data = (mapsector_t *) SafeMalloc(sizeof(mapsector_t));
	secstore_i -> count = 0;
	secstore_i -> size = sizeof(mapsector_t);

	buildsector = 0;
/*
   if (draw)
   PSsetgray (0);
 */
	for (i = 0; i < numss; i++)
		{
		if (subsectornum[i] == -1)
			{
			EraseWindow();
			RecursiveGroupSubsector(i);
			sec = *((mapsector_t *) secdefstore_i -> data + subsectordef[i]);
/*                      sec = *(mapsector_t *)[secdefstore_i elementAt: subsectordef[i]]; */
/*                      [secstore_i addElement: &sec]; */
			memcpy((mapsector_t *) secstore_i -> data + secstore_i -> count, &sec, sizeof(mapsector_t));
			secstore_i -> count += 1;
			secstore_i -> data = (mapsector_t *) realloc(secstore_i -> data,
				sizeof(mapsector_t) * (secstore_i -> count + 1));

			buildsector++;
			}
		}

}
