/* 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_seed_.h"

void
net_seed_seed (int level, int poly, char *width, struct SEEDSET *pGSet)
{
  double w;
  int N;

  if (width == NULL)
    N = (*pGSet).N;
  else
  {
    if (ut_string_real (width, &w) != 0)
      ut_error_reportbug ();

    N = ut_num_d2ri (1 / w);
  }

  (*pGSet).Random = neut_rand_nnid2rand (N, (*pGSet).Id, level, poly);

  if ((*pGSet).Random < 0)
    ut_error_reportbug ();

  return;
}

void
net_seed_prop (struct IN In, struct TESS Tess, int poly,
	       struct SEEDSET *pGSet)
{
  int varqty = 1;
  char **vars = NULL;
  double *vals = NULL;
  double res;

  (*pGSet).weight = ut_alloc_1d_char (strlen (In.weight[Tess.Level + 1]) + 1);
  strcpy ((*pGSet).weight, In.weight[Tess.Level + 1]);

  (*pGSet).morpho = ut_alloc_1d_char (strlen (In.morpho[Tess.Level + 1]) + 1);
  strcpy ((*pGSet).morpho, In.morpho[Tess.Level + 1]);

  (*pGSet).Dim = In.dim;

  if (strcmp ((*pGSet).morpho, "lamella") != 0)
  {
    varqty = 1;
    vars = ut_alloc_2d_char (1, 10);
    vals = ut_alloc_1d (1);

    strcpy (vars[0], "vol");
    neut_tess_poly_volume (Tess, poly, &(vals[0]));

    ut_math_eval (In.n[Tess.Level + 1], 1, vars, vals, &res);
    (*pGSet).N = ut_num_d2ri (ut_num_max (1, res));

    ut_free_2d_char (vars, varqty);
    ut_free_1d (vals);
  }
  else
  {
    (*pGSet).N = -1;
  }

  (*pGSet).N1d = (*pGSet).N;
  (*pGSet).NDensity = (*pGSet).N;

  (*pGSet).Id = In.id[Tess.Level + 1];

  return;
}

void
net_seed_randomize (struct IN In, struct SEEDSET *pGSet, struct TESS Domain)
{
  int i, j, dirsum;
  double eps;
  double *r = ol_r_alloc ();
  double **bbox = ut_alloc_2d (3, 2);
  int seed;
  double dist;
  char** tmp = NULL;
  int qty;
  int *dir = ut_alloc_1d_int (3);

  ut_string_separate (In.randomizestring, NEUT_SEP_DEP, &tmp, &qty);
  if (qty != 2)
    ut_print_message (2, 2, "Expression `%s' could not be processed.\n",
		      In.randomizestring);
  ut_string_real (tmp[0], &dist);
  ut_string_int (tmp[1], &seed);

  neut_tess_bbox (Domain, bbox);

  if (In.randomizestring)
  {
    if (!strcmp ((*pGSet).morpho, "columnar(x)"))
      ut_array_1d_int_set_3 (dir, 0, 1, 1);
    else if (!strcmp ((*pGSet).morpho, "columnar(y)"))
      ut_array_1d_int_set_3 (dir, 1, 0, 1);
    else if (!strcmp ((*pGSet).morpho, "columnar(z)"))
      ut_array_1d_int_set_3 (dir, 1, 1, 0);
    else if (!strcmp ((*pGSet).morpho, "bamboo(x)"))
      ut_array_1d_int_set_3 (dir, 1, 0, 0);
    else if (!strcmp ((*pGSet).morpho, "bamboo(y)"))
      ut_array_1d_int_set_3 (dir, 0, 1, 0);
    else if (!strcmp ((*pGSet).morpho, "bamboo(z)"))
      ut_array_1d_int_set_3 (dir, 0, 0, 1);
    else
      ut_array_1d_int_set_3 (dir, 1, 1, 1);

    // for non 3D tessellations
    for (i = In.dim; i < 3; i++)
      dir[i] = 0;

    gsl_rng *rr = gsl_rng_alloc (gsl_rng_ranlxd2);
    gsl_rng_set (rr, seed);

    dirsum = ut_array_1d_int_sum (dir, 3);

    double val;

    for (i = 1; i <= (*pGSet).N; i++)
    {
      if (dirsum == 3)
	ol_nb_r (gsl_rng_uniform (rr), gsl_rng_uniform (rr), r);
      else if (dirsum == 2)
      {
	ol_nb_r (0.5, gsl_rng_uniform (rr), r);

	if (dir[0] == 0)
	  ut_array_1d_rotate (r, 3, 2);
	else if (dir[1] == 0)
	  ut_array_1d_rotate (r, 3, 1);

	gsl_rng_uniform (rr);	// this is to trash one
      }
      else if (dirsum == 1)
      {
	ol_r_set_zero (r);
	for (j = 0; j < 3; j++)
	{
	  val = gsl_rng_uniform (rr);

	  if (dir[j] == 1)
	    r[j] = (val < 0.5) ? -1 : 1;
	}
      }
      else
	ol_r_set_zero (r);

      eps = dist * pow (gsl_rng_uniform (rr), 1. / dirsum);

      for (j = 0; j < 3; j++)
	if (dir[j] == 1)
	  (*pGSet).SeedCoo[i][j] +=
	    eps * r[j] * (bbox[j][1] - bbox[j][0]);
    }

    gsl_rng_free (rr);
  }

  ol_r_free (r);
  ut_free_2d (bbox, 3);
  ut_free_2d_char (tmp, qty);
  ut_free_1d_int (dir);

  return;
}
