/* initiallinking.c */

#include "initiallinking.h"
#include "formfactor.h"
#include "shaftculling.h"
#include "geom.h"
#include "bounds.h"
#include "debug.h"
#include "error.h"
#include "globals.h"
#include "scene.h"

/* #define DEBUG */
#include "monitor.h"

extern void CheckForEvents(void); 	/* in main.c */

/* needed for shaftculling */
static GEOMLIST *candList = (GEOMLIST *)NULL;

/* the "interactioncreated" flag in the PATCH structure helps to prevent us to
 * try to create the initial links for a patch more than once. This way, we don't
 * have to check if there is already a link with some other patch ... */
INTERACTION *ToplevelLink(PATCH *P, PATCH *Q)
{
	static Float K[BASISMAXSIZE][BASISMAXSIZE];
	INTERACTION *PQ;
	Float deltaK;
	clock_t t;
	int vis;

	SHAFT shaft;
	GEOMLIST *candidateList = candList;
	BOUNDINGBOX Pbounds, Qbounds;
#ifdef DEBUG
if (monitored) 
fprintf(stderr, "ToplevelLink(%d, %d): ", P->id, Q->id);
#endif /*DEBUG*/

/* for better feedback */
	CheckForEvents();

	if (!Facing(P, Q)) {
#ifdef DEBUG
if (monitored)
fprintf(stderr, " not facing\n");
#endif
		return (INTERACTION *)NULL;
	}

	if (shaftcullmode == SHAFTCULL_ALWAYS) {
		t = clock();
		ConstructShaft(PatchBounds(P, Pbounds), PatchBounds(Q, Qbounds), &shaft);
		candidateList = DoShaftCulling(candList, &shaft, GeomListCreate());
		usecs_shaftculling += clock()-t;
	} 

	t = clock();
	deltaK = AreaToAreaFormFactor(P, Q, candidateList, K, &vis);
	usecs_ff_computation += clock()-t;

	if (shaftcullmode == SHAFTCULL_ALWAYS) {
		t = clock();
		FreeCandidateList(candidateList);
		usecs_shaftculling += clock()-t;
	}

	if (vis) {
		PQ = InteractionCreate(P, Q, K, deltaK);
		P->interactions = InteractionListAdd(P->interactions, PQ);
#ifdef DEBUG
if (monitored) {
fprintf(stderr, " new:\n");
InteractionPrint(stderr, PQ);
}
#endif
		return PQ;
	}
#ifdef DEBUG
if (monitored) 
fprintf(stderr, "can't see each other.\n");
#endif

	return (INTERACTION *)NULL;
}

/* yes ... we exploit the hierarchical structure of the scene during initial linking */
static void GeomLink(PATCH *patch, GEOM *geom)
{
	SHAFT shaft;
	BOUNDINGBOX Pbounds;
	GEOMLIST *oldCandList = candList;
	clock_t t;

	if (!patch->twosided && GEOMBOUNDED(geom) && BoundsBehindPlane(GeomBounds(geom), &patch->norm, patch->d)) 
		return;

	if (GEOMBOUNDED(geom) /* && shaftcullmode == SHAFTCULL_ALWAYS */) {
		t = clock();
		ConstructShaft(PatchBounds(patch, Pbounds), GeomBounds(geom), &shaft);
		candList = DoShaftCulling(oldCandList, &shaft, GeomListCreate());
		usecs_shaftculling += clock()-t;
	}

	if (GeomIsAggregate(geom)) {
		GEOMLIST *geoml = GeomPrimList(geom);
		GeomListIterate1B(geoml, GeomLink, patch);
	} else {
		PATCHLIST *patchl = GeomPatchList(geom);
		PatchListIterate1B(patchl, ToplevelLink, patch);
	}

	if (GEOMBOUNDED(geom) /* && shaftcullmode == SHAFTCULL_ALWAYS */) {
		t = clock();
		FreeCandidateList(candList);
		usecs_shaftculling += clock()-t;
	}

	candList = oldCandList;
}

/* initial linking step for the patch */
void CreateToplevelInteractions(PATCH *patch)
{
	candList = World;

#ifdef DEBUG
if (monitored)
fprintf(stderr, "CreateTopLevelInteractions(%d):\n", patch->id);
#endif
	if (!patch->interactionscreated) {
		GeomListIterate1B(World, GeomLink, patch);
		patch->interactionscreated = TRUE;
	}
}

