/* This file is part of the Neper software package. */
/* Copyright (C) 2003-2014, Romain Quey. */
/* See the COPYING file in the top-level directory. */

#include"net_filter_.h"

// The filter is applied on a per cell basis.
void
net_tesr_filter_cell_find (struct TESR Tesr, int dim, int *prptqty,
			  int ***prptpos)
{
  int i, j, k, p, part;
  struct TESR Seg;
  int *rptqty = NULL;

  (*prptqty) = 0;

  for (p = 1; p <= Tesr.CellQty; p++)
  {
    neut_tesr_set_zero (&Seg);

    // for cell, looking for the different parts
    net_tesr_cell_segment (Tesr, p, dim, &Seg);

    // if more than one part, marking points for filtering
    if (Seg.CellQty > 1)
    {
      // looking for the bigger part (will keep this one)
      neut_tesr_cells_rptqty (Seg, &rptqty);
      part = 1 + ut_array_1d_max_int_index (rptqty + 1, Seg.CellQty);

      for (k = 1; k <= Tesr.size[2]; k++)
	for (j = 1; j <= Tesr.size[1]; j++)
	  for (i = 1; i <= Tesr.size[0]; i++)
	    if (Seg.VoxCell[i][j][k] != 0 && Seg.VoxCell[i][j][k] != part)
	    {
	      (*prptpos)
		= ut_realloc_2d_int_addline ((*prptpos), ++(*prptqty), 3);
	      ut_array_1d_int_set_3 ((*prptpos)[(*prptqty) - 1], i, j, k);
	    }

      ut_free_1d_int (rptqty);
      rptqty = NULL;
    }

    neut_tesr_free (&Seg);
  }

  return;
}

void
net_tesr_filter_cell_remove (struct TESR *pTesr, int dim, int rptqty,
			    int **rptpos)
{
  int i, j, neighqty, id;
  int **neighpos = NULL;
  int *pos = NULL;
  int **cellinfo = NULL;
  int cellqty;

  for (i = 0; i < rptqty; i++)
  {
    neut_tesr_cells_pos_neighpos (*pTesr, NULL, -1, rptpos[i], dim,
				 &neighpos, &neighqty);

    int *neighcell = ut_alloc_1d_int (neighqty);
    for (j = 0; j < neighqty; j++)
    {
      pos = neighpos[j];
      neighcell[j] = (*pTesr).VoxCell[pos[0]][pos[1]][pos[2]];
    }

    ut_array_1d_int_valqty (neighcell, neighqty, &cellinfo, &cellqty);
    id = ut_array_1d_int_max_index (cellinfo[1], cellqty);
    int newcell = cellinfo[0][id];

    (*pTesr).VoxCell[rptpos[i][0]][rptpos[i][1]][rptpos[i][2]] = newcell;

    ut_free_1d_int (neighcell);
  }

  ut_free_2d_int (neighpos, neighqty);

  return;
}

int
net_tesr_filter_noise (struct TESR* pTesr, int poly, int qty, int itermax)
{
  int i, j, k, ii, jj, kk, iter, dataqty, status, filqty, new;
  int *data = NULL;
  int **val = NULL;
  int valqty;
  struct TESR TesrCpy;
  int rptqty;

  neut_tesr_set_zero (&TesrCpy);
  neut_tesr_memcpy (*pTesr, &TesrCpy);

  data = ut_alloc_1d_int (pow (3, (*pTesr).Dim) - 1);

  filqty = 0;
  iter = 1;
  do
  {
    rptqty = 0;
    status = 0;
    for (k = 1; k <= (*pTesr).size[2]; k++)
      for (j = 1; j <= (*pTesr).size[1]; j++)
	for (i = 1; i <= (*pTesr).size[0]; i++)
	  if ((*pTesr).VoxCell[i][j][k] == poly)
	  {
	    rptqty++;
	    dataqty = 0;
	    for (kk = k; kk <= k; kk++)
	      for (jj = j - 1; jj <= j + 1; jj++)
		for (ii = i - 1; ii <= i + 1; ii++)
		  if (!(ii == i && jj == j && kk == k)
		   && ii >= 1 && ii <= (*pTesr).size[0]
		   && jj >= 1 && jj <= (*pTesr).size[1]
		   && kk >= 1 && kk <= (*pTesr).size[2])
		    data[dataqty++] = TesrCpy.VoxCell[ii][jj][kk];

	    if (dataqty >= qty)
	    {
	      ut_array_1d_int_valqty (data, dataqty, &val, &valqty);
	      new = val[0][ut_array_1d_int_max_index (val[1], valqty)];
	      if (new != poly)
	      {
		status++;
		(*pTesr).VoxCell[i][j][k] = new;
	      }
	      ut_free_2d_int (val, 2);
	      val = NULL;
	    }
	  }
    filqty += status;
  }
  while (status > 0 && ++iter <= itermax);

  ut_free_1d_int (data);
  neut_tesr_free (&TesrCpy);

  return (rptqty > 0) ? filqty : -1;
}
