/*!
   \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;
    const 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);
        if (params->draw_volume_box->answer) {
            GVL_set_draw_wire(id, 1);
        }
    }

    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 UNUSED)
{
    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);

        if (params->isosurf_toggle_norm_dir->answer) {
            GVL_isosurf_set_flags(id, nisosurfs - 1, 1);
        }

        /* 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 UNUSED)
{
    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;
}
