/*!
   \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];
        /* color */
        /* check for color map */
        if (i < ncolor_map && strcmp(params->color_map->answers[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]);
            }
            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;
}
