/*!
   \file surface.c

   \brief Surface 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/glocale.h>

#include "local_proto.h"

/*!
   \brief Load raster maps/constants and set surface attributes

   \param params module parameters
   \param data nviz data
 */
int load_rasters(const struct GParams *params, nv_data * data)
{
    const char *mapset;
    int i;
    int nelevs, nelev_map, nelev_const, ncolor_map, ncolor_const, nmask_map;
    int ntransp_map, ntransp_const, nshine_map, nshine_const;
    int nemit_map, nemit_const;
    int *surf_list, nsurfs;
    int id;

    double x, y, z;

    nelev_map = opt_get_num_answers(params->elev_map);
    nelev_const = opt_get_num_answers(params->elev_const);

    nelevs = nelev_const + nelev_map;
    /* topography (required) */
    for (i = 0; i < nelevs; i++) {
	/* check maps */
	if (i < nelev_map && strcmp(params->elev_map->answers[i], "")) {
	    mapset = G_find_raster2(params->elev_map->answers[i], "");
	    if (mapset == NULL) {
		G_fatal_error(_("Raster map <%s> not found"),
			      params->elev_map->answers[i]);
	    }

	    id = Nviz_new_map_obj(MAP_OBJ_SURF,
				  G_fully_qualified_name(params->
							 elev_map->answers[i],
							 mapset), 0.0, data);
	}
	else {
	    if (i - nelev_map < nelev_const &&
		strcmp(params->elev_const->answers[i - nelev_map], "")) {
		id = Nviz_new_map_obj(MAP_OBJ_SURF, NULL,
				      atof(params->elev_const->
					   answers[i - nelev_map]), data);
	    }
	    else {
		G_fatal_error(_("Missing topography attribute for surface %d"),
			      i + 1);
	    }
	}

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

	GS_set_trans(id, x, y, z);
    }

    /* set surface attributes */
    surf_list = GS_get_surf_list(&nsurfs);

    ncolor_map = opt_get_num_answers(params->color_map);
    ncolor_const = opt_get_num_answers(params->color_const);
    nmask_map = opt_get_num_answers(params->mask_map);
    ntransp_map = opt_get_num_answers(params->transp_map);
    ntransp_const = opt_get_num_answers(params->transp_const);
    nshine_map = opt_get_num_answers(params->shine_map);
    nshine_const = opt_get_num_answers(params->shine_const);
    nemit_map = opt_get_num_answers(params->emit_map);
    nemit_const = opt_get_num_answers(params->emit_const);

    for (i = 0; i < nsurfs; i++) {
	id = surf_list[i];
	mapset = G_find_raster2(params->color_map->answers[i], "");
	if (mapset == NULL) {
	    G_fatal_error(_("Raster map <%s> not found"),
			  params->color_map->answers[i]);
	}
	/* color */
	/* check for color map */
	if (i < ncolor_map && strcmp(params->color_map->answers[i], "")) {
	    Nviz_set_attr(id, MAP_OBJ_SURF, ATT_COLOR, MAP_ATT,
			  G_fully_qualified_name(params->
						 color_map->answers[i],
						 mapset), -1.0, data);
	}
	/* check for color value */
	else if (i - ncolor_map < ncolor_const &&
		 strcmp(params->color_const->answers[i - ncolor_map], "")) {
	    Nviz_set_attr(id, MAP_OBJ_SURF, ATT_COLOR, CONST_ATT, NULL,
			  Nviz_color_from_str(params->
					      color_const->answers[i -
								   ncolor_map]),
			  data);
	}
	else {			/* use by default elevation map for coloring */
	    if (nelev_map > 0) {
		Nviz_set_attr(id, MAP_OBJ_SURF, ATT_COLOR, MAP_ATT,
			      G_fully_qualified_name(params->elev_map->
						     answers[i], mapset),
			      -1.0, data);
		G_verbose_message(_("Color attribute not defined, using default <%s>"),
				  G_fully_qualified_name(params->
							 elev_map->answers[i],
							 mapset));
	    }
	    else {
		G_fatal_error(_("Missing color attribute for surface %d"),
			      i + 1);
	    }
	}
	/* mask */
	if (i < nmask_map && strcmp(params->mask_map->answers[i], "")) {
	    Nviz_set_attr(id, MAP_OBJ_SURF, ATT_MASK, MAP_ATT,
			  G_fully_qualified_name(params->mask_map->answers[i],
						 mapset), -1.0, data);
	}

	/* transparency */
	if (i < ntransp_map && strcmp(params->transp_map->answers[i], "")) {
	    Nviz_set_attr(id, MAP_OBJ_SURF, ATT_TRANSP, MAP_ATT,
			  G_fully_qualified_name(params->
						 transp_map->answers[i],
						 mapset), -1.0, data);
	}
	else if (i - ntransp_map < ntransp_const &&
		 strcmp(params->transp_const->answers[i - ntransp_map], "")) {
	    Nviz_set_attr(id, MAP_OBJ_SURF, ATT_TRANSP, CONST_ATT, NULL,
			  atof(params->transp_const->
			       answers[i - ntransp_map]), data);
	}

	/* shininess */
	if (i < nshine_map && strcmp(params->shine_map->answers[i], "")) {
	    Nviz_set_attr(id, MAP_OBJ_SURF, ATT_SHINE, MAP_ATT,
			  G_fully_qualified_name(params->
						 shine_map->answers[i],
						 mapset), -1.0, data);
	}
	else if (i - nshine_map < nshine_const &&
		 strcmp(params->shine_const->answers[i - nshine_map], "")) {
	    Nviz_set_attr(id, MAP_OBJ_SURF, ATT_SHINE, CONST_ATT, NULL,
			  atof(params->shine_const->answers[i - nshine_map]),
			  data);
	}

	/* emission */
	if (i < nemit_map && strcmp(params->emit_map->answers[i], "")) {
	    Nviz_set_attr(id, MAP_OBJ_SURF, ATT_EMIT, MAP_ATT,
			  G_fully_qualified_name(params->emit_map->answers[i],
						 mapset), -1.0, data);
	}
	else if (i - nemit_map < nemit_const &&
		 strcmp(params->emit_const->answers[i - nemit_map], "")) {
	    Nviz_set_attr(id, MAP_OBJ_SURF, ATT_EMIT, CONST_ATT, NULL,
			  atof(params->emit_const->answers[i - nemit_map]),
			  data);
	}

	/*
	   if (i > 1)
	   set_default_wirecolors(data, i);
	 */
    }

    return nsurfs;
}

/*!
   \brief Set draw mode for loaded surfaces

   \param params module parameters
 */
void surface_set_draw_mode(const struct GParams *params)
{
    int *surf_list, nsurfs;
    int i, id, draw_mode;
    int resol_fine, resol_coarse;

    char *mode, *style, *shade, *res_fine, *res_coarse, *wire_color;

    surf_list = GS_get_surf_list(&nsurfs);

    for (i = 0; i < nsurfs; i++) {
	draw_mode = 0;
	id = surf_list[i];
	if (!GS_surf_exists(id))
	    G_fatal_error(_("Surface id %d doesn't exist"), id);

	if (params->mode_all->answer) {	/* use one mode for all surfaces */
	    mode = params->mode->answers[0];
	    style = params->style->answers[0];
	    shade = params->shade->answers[0];
	    res_fine = params->res_fine->answers[0];
	    res_coarse = params->res_coarse->answers[0];
	    wire_color = params->wire_color->answers[0];
	}
	else {
	    mode = params->mode->answers[i];
	    style = params->style->answers[i];
	    shade = params->shade->answers[i];
	    res_fine = params->res_fine->answers[i];
	    res_coarse = params->res_coarse->answers[i];
	    wire_color = params->wire_color->answers[i];
	}

	/* mode */
	if (strcmp(mode, "coarse") == 0) {
	    draw_mode |= DM_WIRE;
	}
	else if (strcmp(mode, "fine") == 0) {
	    draw_mode |= DM_POLY;
	}
	else {			/* both */
	    draw_mode |= DM_WIRE_POLY;
	}

	/* style */
	if (strcmp(style, "wire") == 0) {
	    draw_mode |= DM_GRID_WIRE;
	}
	else {			/* surface */
	    draw_mode |= DM_GRID_SURF;
	}

	/* shading */
	if (strcmp(shade, "flat") == 0) {
	    draw_mode |= DM_FLAT;
	}
	else {			/* gouraud */
	    draw_mode |= DM_GOURAUD;
	}

	if (GS_set_drawmode(id, draw_mode) < 0)
	    G_fatal_error(_("Unable to set draw mode for surface id %d"), id);

	/* resolution */
	resol_fine = atoi(res_fine);
	resol_coarse = atoi(res_coarse);
	if (GS_set_drawres(id, resol_fine, resol_fine,
			   resol_coarse, resol_coarse) < 0)
	    G_fatal_error(_("Unable to set draw mode for surface id %d"), id);

	/* wire color */
	GS_set_wire_color(id, Nviz_color_from_str(wire_color));
    }

    return;
}
