#define	LIBQBUILD_CORE
#include "../include/libqbuild.h"

int outleafs = 0;						/* 4 */

struct portal *prevleaknode;					/* 4 */
FILE *leakfile;							/* 4 */

int hit_occupied = 0;						/* 4 */
int backdraw = 0;						/* 4 */

/* PROGRESS-ONLY! */
int outsidenum;
int outsidecur;

/*
 * ===========
 * PointInLeaf
 * ===========
 */
struct node *PointInLeaf(__memBase, struct node *node, vec3_t point)
{
  vec_t d;

  if (node->contents)
    return node;

#ifdef EXHAUSIVE_CHECK
  if (node->planenum >= bspMem->numbrushplanes || node->planennum < 0)
    Error("looking for nonexisting plane %d\n", node->planenum);
#endif
  d = DotProduct(bspMem->brushplanes[node->planenum].normal, point) - bspMem->brushplanes[node->planenum].dist;

  if (d > 0)
    return PointInLeaf(bspMem, node->children[0], point);

  return PointInLeaf(bspMem, node->children[1], point);
}

/*
 * ===========
 * PlaceOccupant
 * ===========
 */
bool PlaceOccupant(__memBase, register int num, register vec3_t point, register struct node * headnode)
{
  struct node *n;

  n = PointInLeaf(bspMem, headnode, point);
  if (n->contents == CONTENTS_SOLID)
    return FALSE;
  n->occupied = num;
  return TRUE;
}

/*
 * ==============
 * MarkLeakTrail
 * ==============
 */
void MarkLeakTrail(register struct portal *n2)
{
  int i;
  short int j;
  vec3_t p1, p2, dir;
  float len;
  struct portal *n1;

  if (hullnum)
    return;

  n1 = prevleaknode;
  prevleaknode = n2;

  if (!n1)
    return;

  VectorCopy(n2->winding->points[0], p1);
  for (i = 1; i < n2->winding->numpoints; i++) {
    for (j = 0; j < 3; j++)
      p1[j] = (p1[j] + n2->winding->points[i][j]) / 2;
  }

  VectorCopy(n1->winding->points[0], p2);
  for (i = 1; i < n1->winding->numpoints; i++) {
    for (j = 0; j < 3; j++)
      p2[j] = (p2[j] + n1->winding->points[i][j]) / 2;
  }

  VectorSubtract(p2, p1, dir);
  len = VectorLength(dir);
  VectorNormalize(dir);

  while (len > 2) {
    fprintf(leakfile, "%g %g %g\n", p1[0], p1[1], p1[2]);
    for (i = 0; i < 3; i++)
      p1[i] += dir[i] * 2;
    len -= 2;
  }
}

/*
 * ==================
 * RecursiveFillOutside
 * 
 * If fill is FALSE, just check, don't fill
 * Returns TRUE if an occupied leaf is reached
 * ==================
 */
bool RecursiveFillOutside(register struct node *l, register bool fill)
{
  struct portal *p;
  int s;

  /* PROGRESS-ONLY! */
  if (!fill)
    outsidenum++;
  else
    mprogress(outsidenum, ++outsidecur);

  if (l->contents == CONTENTS_SOLID || l->contents == CONTENTS_SKY)
    return FALSE;

  if (l->valid == valid)
    return FALSE;

  if (l->occupied)
    return TRUE;

  l->valid = valid;

  /* fill it and it's neighbors */
  if (fill)
    l->contents = CONTENTS_SOLID;
  outleafs++;

  for (p = l->portals; p;) {
    s = (p->nodes[0] == l);

    if (RecursiveFillOutside(p->nodes[s], fill)) {		/* leaked, so stop filling */

      if (backdraw-- > 0) {
	MarkLeakTrail(p);
	DrawLeaf(l, 2);
      }
      return TRUE;
    }
    p = p->next[!s];
  }

  return FALSE;
}

/*
 * ==================
 * ClearOutFaces
 * 
 * ==================
 */
void ClearOutFaces(register struct node *node)
{
  struct visfacet **fp;

  if (node->planenum != -1) {
    ClearOutFaces(node->children[0]);
    ClearOutFaces(node->children[1]);
    return;
  }
  if (node->contents != CONTENTS_SOLID)
    return;

  for (fp = node->markfaces; *fp; fp++) {
    /* mark all the original faces that are removed */
    (*fp)->numpoints = 0;
  }
  node->faces = NULL;
}

/*============================================================================= */

/*
 * ===========
 * FillOutside
 * 
 * ===========
 */
bool FillOutside(__memBase, struct node *node, char *pointfilename)
{
  int s;
  vec_t *v;
  int i;
  bool inside;

  mprintf("----- FillOutside -------\n");
  /* PROGRESS-ONLY! */
  outsidenum = 0;
  outsidecur = 0;

  if (bspMem->bspOptions & QBSP_NOFILL) {
    mprintf("    - skipped\n");
    return FALSE;
  }

  inside = FALSE;
  for (i = 1; i < bspMem->nummapentities; i++) {
    if (!VectorZero(bspMem->mapentities[i].origin)) {
      if (PlaceOccupant(bspMem, i, bspMem->mapentities[i].origin, node))
	inside = TRUE;
    }
  }

  if (!inside) {
    mprintf("Hullnum %i: No bspMem->mapentities in empty space -- no filling performed\n", hullnum);
    return FALSE;
  }

  s = !(outside_node.portals->nodes[1] == &outside_node);

  /* first check to see if an occupied leaf is hit */
  outleafs = 0;
  valid++;

  prevleaknode = NULL;

  if (!hullnum) {
    leakfile = __fopen(pointfilename, "w");
    if (!leakfile)
      Error(failed_fileopen, pointfilename);
  }

  if (RecursiveFillOutside(outside_node.portals->nodes[s], FALSE)) {
    v = bspMem->mapentities[hit_occupied].origin;
    eprintf("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n");
    eprintf("reached occupant at: ( %g %g %g )\n"
	    ,v[0], v[1], v[2]);
    eprintf("no filling performed\n");
    if (!hullnum)
      __fclose(leakfile);
    eprintf("leak file written to %s\n", pointfilename);
    eprintf("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n");
    return FALSE;
  }
  if (!hullnum)
    __fclose(leakfile);

  /* now go back and fill things in */
  valid++;
  RecursiveFillOutside(outside_node.portals->nodes[s], TRUE);

  /* remove faces from filled in leafs     */
  ClearOutFaces(node);

  mprintf("%5i outleafs\n", outleafs);
  return TRUE;
}
