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

void
neut_tesr_cell (struct TESR Tesr, char** pcell)
{
  if (Tesr.Dim == 0)
    ut_string_string ("ver", pcell);
  else if (Tesr.Dim == 1)
    ut_string_string ("edge", pcell);
  else if (Tesr.Dim == 2)
    ut_string_string ("face", pcell);
  else if (Tesr.Dim == 3)
    ut_string_string ("poly", pcell);
  else
    ut_error_reportbug ();

  return;
}

void
neut_tesr_entity_qty (struct TESR Tesr, char* entity, int* pqty)
{
  if (!strcmp (entity, "cell"))
    (*pqty) = Tesr.CellQty;
  else if (!strcmp (entity, "seed"))
    (*pqty) = Tesr.CellQty;
  else
    (*pqty) = -1;

  return;
}

void
neut_tesr_tesrqty (struct TESR Tesr, int *pqty)
{
  (*pqty) = ut_array_1d_int_prod (Tesr.size, Tesr.Dim - 1);

  return;
}

int
neut_tesr_length (struct TESR Tesr, double *plength)
{
  if (Tesr.Dim == 1)
  {
    (*plength) = Tesr.vsize[0] * Tesr.size[0];
    return 0;
  }
  else
  {
    (*plength) = 0;
    return -1;
  }
}

int
neut_tesr_area (struct TESR Tesr, double *parea)
{
  if (Tesr.Dim == 2)
  {
    (*parea) = Tesr.vsize[0] * Tesr.size[0]
      * Tesr.vsize[1] * Tesr.size[1];
    return 0;
  }
  else
  {
    (*parea) = 0;
    return -1;
  }
}

int
neut_tesr_volume (struct TESR Tesr, double *pvol)
{
  if (Tesr.Dim == 3)
  {
    (*pvol) = Tesr.vsize[0] * Tesr.size[0]
      * Tesr.vsize[1] * Tesr.size[1] * Tesr.vsize[2] * Tesr.size[2];
    return 0;
  }
  else
  {
    (*pvol) = 0;
    return -1;
  }
}

int
neut_tesr_size (struct TESR Tesr, double *psize)
{
  if (Tesr.Dim == 1)
    neut_tesr_length (Tesr, psize);
  else if (Tesr.Dim == 2)
    neut_tesr_area (Tesr, psize);
  else if (Tesr.Dim == 3)
    neut_tesr_volume (Tesr, psize);

  return 0;
}

void
neut_tesr_var_list (char *entity, char ***pvar, int *pvarqty)
{
  if (!strcmp (entity, "cell"))
  {
    (*pvarqty) = 6;
    (*pvar) = ut_alloc_2d_char (*pvarqty, 10);
    strcpy ((*pvar)[0], "id");
    strcpy ((*pvar)[1], "x");
    strcpy ((*pvar)[2], "y");
    strcpy ((*pvar)[3], "z");
    strcpy ((*pvar)[4], "vol");
    strcpy ((*pvar)[5], "diameq");
  }
  else
    ut_error_reportbug ();

  return;
}

int
neut_tesr_var_val (struct TESR Tesr, char *entity,
		  int id, char *var, double *pval, char **ptype)
{
  int status, b;
  double vol;
  double *c = ut_alloc_1d (3);
  char *typetmp = ut_alloc_1d_char (10);

  // b = (Tess.CellQty > 0) ? Tess.CellBody[id] : 0;
  b = 0;

  if (!strcmp (var, "x") || !strcmp (var, "y") || !strcmp (var, "z"))
    neut_tesr_cell_centre (Tesr, id, c);

  status = -1;
  if (!strcmp (entity, "cell")
   || !strcmp (entity, "poly")
   || !strcmp (entity, "face")
   || !strcmp (entity, "edge"))
  {
    status = 0;
    if (!strcmp (var, "id"))
    {
      if (strcmp (entity, "cell") != 0)
	(*pval) = id;
      else
	(*pval) = Tesr.CellId ? Tesr.CellId[id] : id;
      strcpy (typetmp, "%d");
    }
    else if (!strcmp (var, "body"))
    {
      (*pval) = b;
      strcpy (typetmp, "%d");
    }
    else if (!strcmp (var, "x"))
    {
      (*pval) = c[0];
      strcpy (typetmp, "%f");
    }
    else if (!strcmp (var, "y"))
    {
      (*pval) = c[1];
      strcpy (typetmp, "%f");
    }
    else if (!strcmp (var, "z"))
    {
      (*pval) = c[2];
      strcpy (typetmp, "%f");
    }
    else if (!strcmp (var, "vol"))
    {
      neut_tesr_cell_volume (Tesr, id, pval);
      strcpy (typetmp, "%f");
    }
    else if (!strcmp (var, "diameq"))
    {
      neut_tesr_cell_diameq (Tesr, id, pval);
      strcpy (typetmp, "%f");
    }
  }
  else if (!strcmp (entity, "seed"))
  {
    status = 0;
    if (!strcmp (var, "id"))
    {
      (*pval) = id;
      strcpy (typetmp, "%d");
    }
    else if (!strcmp (var, "x"))
    {
      (*pval) = Tesr.SeedCoo[id][0];
      strcpy (typetmp, "%f");
    }
    else if (!strcmp (var, "y"))
    {
      (*pval) = Tesr.SeedCoo[id][1];
      strcpy (typetmp, "%f");
    }
    else if (!strcmp (var, "z"))
    {
      (*pval) = Tesr.SeedCoo[id][2];
      strcpy (typetmp, "%f");
    }
    else if (!strcmp (var, "w"))
    {
      (*pval) = Tesr.SeedWeight[id];
      strcpy (typetmp, "%f");
    }
    else if (!strcmp (var, "vol"))
    {
      neut_tesr_cell_volume (Tesr, id, &vol);
      (*pval) = vol;
      strcpy (typetmp, "%f");
    }
  }
  else
    ut_print_message (2, 0, "Failed to process expression `%s'.\n", 
		      entity);

  if (ptype)
  {
    ut_free_1d_char (*ptype);
    (*ptype) = ut_alloc_1d_char (strlen (typetmp) + 1);
    strcpy (*ptype, typetmp);
  }

  ut_free_1d (c);
  ut_free_1d_char (typetmp);

  return status;
}

void
neut_tesr_entity_expr_val (struct TESR Tesr, char* entity,
                          char* expr, double* val)
{
  int i, j, k, status;
  int qty, *qty2 = NULL;
  char ***list = NULL;
  char** vars = NULL;
  double* vals = NULL;
  FILE* file = NULL;
  int varqty;
  int entityqty;
  double tmp, tmp2;

  entityqty = Tesr.CellQty;
  ut_string_separate2 (expr, NEUT_SEP_NODEP, NEUT_SEP_DEP, &list, &qty2, &qty);
  
  // patching list
  for (i = 0; i < qty; i++)
    if (qty2[i] == 2)
      continue;
    else if (qty2[i] == 1)
    {
      list[i] = ut_realloc_1d_pchar (list[i], 2);
      list[i][1] = NULL;
      ut_string_string (list[i][0], &(list[i][1]));
      strcpy (list[i][0], "1");
      qty2[i] = 2;
    }
    else
      abort ();

  neut_tesr_var_list (entity, &vars, &varqty);

  vals = ut_alloc_1d (varqty);

  for (i = 0; i < qty; i++)
  {
    if (list[i][1][0] == '@')
    {
      file = ut_file_open (list[i][1] + 1, "R");
      ut_array_1d_fscanf (file, val + 1, entityqty);
      ut_file_close (file, list[i][1] + 1, "R");
    }
    else
    {
      ut_string_real (list[i][1], &tmp);

      if (!strcmp (list[i][0], "1"))
	ut_array_1d_set (val + 1, entityqty, tmp);
      else
	for (j = 1; j <= entityqty; j++)
	{
	  for (k = 0; k < varqty; k++)
	    neut_tesr_var_val (Tesr, entity, j, vars[k], &(vals[k]), NULL);

	  status =
	    ut_math_eval (list[i][0], varqty, vars, vals, &tmp2);

	  if (status == -1)
	    abort ();

	  if (ut_num_equal (tmp2, 1, 1e-6))
	    val[j] = tmp;
	}
    }
  }

  return;
}
