/*!
  \file volume.c
  
  \brief Volume subroutines
  
  (C) 2008, 2010 by the GRASS Development Team

  This program is free software under the GNU General Public
  License (>=v2). Read the file COPYING that comes with GRASS
  for details.
  
  \author Martin Landa <landa.martin gmail.com> (Google SoC 2008/2010)
*/

#include <stdlib.h>
#include <string.h>

#include <grass/raster3d.h>
#include <grass/glocale.h>

#include "local_proto.h"

/*!
  \brief Load 3d raster map layers -> volume
  
  \param params module parameters
  \param data nviz data

  \return number of loaded volumes
*/
int load_rasters3d(const struct GParams *params, nv_data *data)
{
    int i, nvol, id;
    float x, y, z;
    char *mapset;
    
    nvol = opt_get_num_answers(params->volume);

    for (i = 0; i < nvol; i++) {
	mapset = G_find_raster3d(params->volume->answers[i], "");
	if (mapset == NULL) {
	    G_fatal_error(_("3d raster map <%s> not found"),
			  params->volume->answers[i]);
	}

	id = Nviz_new_map_obj(MAP_OBJ_VOL,
			      G_fully_qualified_name(params->volume->answers[i],
						     mapset),
			      0.0, data);

	/* set position */
	if (opt_get_num_answers(params->volume_pos) != 3 * nvol) {
	    x = atof(params->volume_pos->answers[0]);
	    y = atof(params->volume_pos->answers[1]);
	    z = atof(params->volume_pos->answers[2]);
	}
	else {
	    x = atof(params->volume_pos->answers[i*3+0]);
	    y = atof(params->volume_pos->answers[i*3+1]);
	    z = atof(params->volume_pos->answers[i*3+2]);
	}
    
	GVL_set_trans(id, x, y, z);
    }

    return 1;
}

/*!
  \brief Add isosurfaces and set their attributes
  
  \param params module parameters
  \param data nviz data
  
  \return number of defined isosurfaces
*/
int add_isosurfs(const struct GParams *params, nv_data *data)
{
    int i;
    float level;
    int num, nvols, *vol_list, id, nisosurfs;
    int ncolor_map, ncolor_const, ntransp_map, ntransp_const, nshine_map, nshine_const;
    int res, draw_mode;
    char **tokens;
    const char *mapset, *style;
    
    vol_list = GVL_get_vol_list(&nvols);

    for (i = 0; params->isosurf_level->answers[i]; i++) {
	tokens = G_tokenize(params->isosurf_level->answers[i], ":");
	if (G_number_of_tokens(tokens) != 2) 
	    G_fatal_error(_("Error tokenize '%s'"), 
			  params->isosurf_level->answers[i]);
	num = atoi(tokens[0]);
	level = atof(tokens[1]);
	G_free_tokens(tokens);

	if (num > nvols) {
	    G_fatal_error(_("Volume set number %d is not available"), 
			  num);
	}

	id = vol_list[num-1];
	if (GVL_isosurf_add(id) < 0) {
	    G_fatal_error(_("Unable to add isosurface (volume set %d)"),
			  id);
	}

	nisosurfs = GVL_isosurf_num_isosurfs(id);

	/* topography (level) */
	if (GVL_isosurf_set_att_const(id, nisosurfs-1, ATT_TOPO, level) < 0) {
	    G_fatal_error(_("Unable to set isosurface (%d) attribute (%d) of volume %d"),
			  nisosurfs-1, ATT_TOPO, id);
	}

	/* color */
	ncolor_map = opt_get_num_answers(params->isosurf_color_map);
	ncolor_const = opt_get_num_answers(params->isosurf_color_const);

	if (i < ncolor_map && strcmp(params->isosurf_color_map->answers[i], "")) {
	    mapset = G_find_raster3d(params->isosurf_color_map->answers[i], "");

	    if (mapset == NULL) {
		G_fatal_error(_("3d raster map <%s> not found"),
			      params->isosurf_color_map->answers[i]);
	    }

	    if (GVL_isosurf_set_att_map(id, nisosurfs-1, ATT_COLOR, 
					params->isosurf_color_map->answers[i]) < 0)
		G_fatal_error(_("Unable to set isosurface (%d) attribute (%d) of volume %d"),
				nisosurfs-1, ATT_COLOR, id);
	}
	else if (i-ncolor_map < ncolor_const &&
		 strcmp(params->isosurf_color_const->answers[i-ncolor_map], "")) {

	    if (GVL_isosurf_set_att_const(id, nisosurfs-1, ATT_COLOR,
			    Nviz_color_from_str(params->isosurf_color_const->answers[i-ncolor_map])) < 0)
		G_fatal_error(_("Unable to set isosurface (%d) attribute (%d) of volume %d"),
				nisosurfs-1, ATT_COLOR, id);
	}
	else {			/* use by default 3d raster map for coloring */
	    GVL_isosurf_set_att_map(id, nisosurfs-1, ATT_COLOR, params->volume->answers[num-1]);
	    G_verbose_message(_("Color attribute not defined, using default <%s>"),
				params->volume->answers[num-1]);
	}

	/* transparency */
	ntransp_map = opt_get_num_answers(params->isosurf_transp_map);
	ntransp_const = opt_get_num_answers(params->isosurf_transp_const);

	if (i < ntransp_map && strcmp(params->isosurf_transp_map->answers[i], "")) {
	    if (GVL_isosurf_set_att_map(id, nisosurfs-1, ATT_TRANSP, 
					params->isosurf_transp_map->answers[i]) < 0)
		G_fatal_error(_("Unable to set isosurface (%d) attribute (%d) of volume %d"),
				nisosurfs-1, ATT_TRANSP, id);
	}
	else if (i-ntransp_map < ntransp_const &&
		 strcmp(params->isosurf_transp_const->answers[i-ntransp_map], "")) {
	    if (GVL_isosurf_set_att_const(id, nisosurfs-1, ATT_TRANSP,
					  atof(params->isosurf_transp_const->answers[i-ntransp_map])) < 0)
		G_fatal_error(_("Unable to set isosurface (%d) attribute (%d) of volume %d"),
				nisosurfs-1, ATT_TRANSP, id);
	}

	/* shine */
	nshine_map = opt_get_num_answers(params->isosurf_shine_map);
	nshine_const = opt_get_num_answers(params->isosurf_shine_const);

	if (i < nshine_map && strcmp(params->isosurf_shine_map->answers[i], "")) {
	    if (GVL_isosurf_set_att_map(id, nisosurfs-1, ATT_SHINE, 
					params->isosurf_shine_map->answers[i]) < 0)
		G_fatal_error(_("Unable to set isosurface (%d) attribute (%d) of volume %d"),
				nisosurfs-1, ATT_SHINE, id);
	}
	else if (i-nshine_map < nshine_const &&
		 strcmp(params->isosurf_shine_const->answers[i-nshine_map], "")) {
	    if (GVL_isosurf_set_att_const(id, nisosurfs-1, ATT_SHINE,
					  atof(params->isosurf_shine_const->answers[i-nshine_map])) < 0)
		G_fatal_error(_("Unable to set isosurface (%d) attribute (%d) of volume %d"),
				nisosurfs-1, ATT_SHINE, id);
	}
    }

    /* set draw resolution and shading after isosurfaces are added*/
    for (i = 0; i < nvols; i++) {

	id = vol_list[i];
	/* set resolution */
	if (opt_get_num_answers(params->volume_res) != nvols)
	    res = atof(params->volume_res->answers[0]);
	else
	    res = atof(params->volume_res->answers[i]);

	GVL_isosurf_set_drawres(id, res, res, res);

	/* set shading */
	if (opt_get_num_answers(params->volume_shade) != nvols)
	    style = params->volume_shade->answers[0];
	else
	    style = params->volume_shade->answers[i];

	draw_mode = 0;

	if (strcmp(style, "flat") == 0) {
	    draw_mode |= DM_FLAT;
	}
	else {
	    draw_mode |= DM_GOURAUD;
	}
	
	GVL_isosurf_set_drawmode(id, draw_mode);
    }

    return 1;
}

int add_slices(const struct GParams *params, nv_data *data)
{
    int i;
    int num, nvols, *vol_list, id, nslices, axis;
    int res, draw_mode;
    char **tokens;
    const char* style;

    vol_list = GVL_get_vol_list(&nvols);

    for (i = 0; params->slice->answers[i]; i++) {
	tokens = G_tokenize(params->slice->answers[i], ":");
	if (G_number_of_tokens(tokens) != 2) 
	    G_fatal_error(_("Error tokenize '%s'"), 
			  params->slice->answers[i]);
	num = atoi(tokens[0]);

	if (!strcmp(tokens[1],"x") || !strcmp(tokens[1],"X"))
	    axis = 0;
	else if (!strcmp(tokens[1],"y") || !strcmp(tokens[1],"Y"))
	    axis = 1;
	else if (!strcmp(tokens[1],"z") || !strcmp(tokens[1],"Z"))
	    axis = 2;
	else
	    G_fatal_error(_("Wrong name for axis: %s"), 
			  tokens[1]);
	G_free_tokens(tokens);

	if (num > nvols) {
	    G_fatal_error(_("Volume set number %d is not available"), 
			  num);
	}

	id = vol_list[num-1];
	if (GVL_slice_add(id) < 0) {
	    G_fatal_error(_("Unable to add slice (volume set %d)"),
			  id);
	}

	nslices = GVL_slice_num_slices(id);

	if (GVL_slice_set_pos(id, nslices-1, atof(params->slice_pos->answers[i*6+0]),
					     atof(params->slice_pos->answers[i*6+1]),
					     atof(params->slice_pos->answers[i*6+2]),
					     atof(params->slice_pos->answers[i*6+3]),
					     atof(params->slice_pos->answers[i*6+4]),
					     atof(params->slice_pos->answers[i*6+5]),
					     axis) < 0) 
	    G_fatal_error(_("Unable to set slice (%d) position of volume %d"),
			  nslices-1, id);

	/* set transparency */
	if (GVL_slice_set_transp(id, nslices-1, atoi(params->slice_transp->answers[i])) < 0)
	    G_fatal_error(_("Unable to set slice (%d) transparency of volume %d"),
			  nslices-1, id);
    }

    /* set draw resolution and shading after slices are added*/
    for (i = 0; i < nvols; i++) {

	id = vol_list[i];
	/* set resolution */
	if (opt_get_num_answers(params->volume_res) != nvols)
	    res = atof(params->volume_res->answers[0]);
	else
	    res = atof(params->volume_res->answers[i]);

	GVL_slice_set_drawres(id, res, res, res);

	/* set shading */
	if (opt_get_num_answers(params->volume_shade) != nvols)
	    style = params->volume_shade->answers[0];
	else
	    style = params->volume_shade->answers[i];

	draw_mode = 0;

	if (strcmp(style, "flat") == 0) {
	    draw_mode |= DM_FLAT;
	}
	else {
	    draw_mode |= DM_GOURAUD;
	}

	GVL_slice_set_drawmode(id, draw_mode);
    }

    return 1;
}
