
/***************************************************************
 *
 * MODULE:       v.build
 * 
 * AUTHOR(S):    Radim Blazek
 *               
 * PURPOSE:      Build topology
 *               
 * COPYRIGHT:    (C) 2001, 2012 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.
 *
 **************************************************************/

#include <stdlib.h>
#include <string.h>
#include <grass/gis.h>
#include <grass/vector.h>
#include <grass/glocale.h>

int main(int argc, char *argv[])
{
    struct GModule *module;
    struct Option *map_opt, *opt, *err_opt;
    struct Flag *chk;
    struct Map_info Map;
    int i, build, dump, sdump, cdump, fdump;
    char xname[GNAME_MAX], xmapset[GMAPSET_MAX];
    char *opt_desc;
    G_gisinit(argv[0]);

    module = G_define_module();
    G_add_keyword(_("vector"));
    G_add_keyword(_("topology"));
    G_add_keyword(_("geometry"));
    module->label = _("Creates topology for vector map.");
    module->description = _("Optionally also checks for topological errors.");

    map_opt = G_define_standard_option(G_OPT_V_MAP);
    map_opt->label = NULL;
    map_opt->description = _("Name of vector map");
    
    err_opt = G_define_standard_option(G_OPT_V_OUTPUT);
    err_opt->key = "error";
    err_opt->description =
	_("Name for output vector map where erroneous vector features are written to");
    err_opt->required = NO;
    err_opt->guisection = _("Errors");

    opt = G_define_option();
    opt->key = "option";
    opt->type = TYPE_STRING;
    opt->options = "build,dump,sdump,cdump,fdump";
    opt->required = NO;
    opt->multiple = YES;
    opt->answer = "build";
    opt->description =
	_("Build topology or dump topology or indices to standard output");
    opt_desc = NULL;
    G_asprintf(&opt_desc,
	       "build;%s;dump;%s;sdump;%s;cdump;%s;fdump;%s",
	       _("build topology"),
	       _("write topology to stdout"),
	       _("write spatial index to stdout"),
	       _("write category index to stdout"),
	       _("write feature index to stdout (OGR simple-feature-based formats only)"));
    opt->descriptions = opt_desc;
    opt->required = YES;
    
    chk = G_define_flag();
    chk->key = 'e';
    chk->label = _("Extensive checks for topological errors");
    chk->description = _("Perform in-depth checks for topological errors when building topology");
    chk->guisection = _("Errors");
    
    if (G_parser(argc, argv))
	exit(EXIT_FAILURE);

    build = dump = sdump = cdump = fdump = FALSE;
    i = 0;
    while (opt->answers[i]) {
	if (*opt->answers[i] == 'b')
	    build = TRUE;
	else if (*opt->answers[i] == 'd')
	    dump = TRUE;
	else if (*opt->answers[i] == 's')
	    sdump = TRUE;
	else if (*opt->answers[i] == 'c')
	    cdump = TRUE;
	else if (*opt->answers[i] == 'f')
	    fdump = TRUE;
	i++;
    }
    if (err_opt->answer) {
	Vect_check_input_output_name(map_opt->answer, err_opt->answer,
				     G_FATAL_EXIT);
    }

    /* build topology */
    if (build) {
	if (G_name_is_fully_qualified(map_opt->answer, xname, xmapset)) {
	    if (0 == G_strcasecmp(xmapset, "OGR")) {
		G_fatal_error(_("Direct read access to OGR layers is not supported by this module. "
				"Run %s to create a link as GRASS vector map in the current mapset."),
			      "'v.external'");
	    }
	    if (0 != strcmp(xmapset, G_mapset())) {
		G_fatal_error(_("Vector map <%s> is not in current mapset"),
			      map_opt->answer);
	    }
	}
	Vect_set_open_level(1);

	if (Vect_open_old(&Map, map_opt->answer, G_mapset()) < 0)
	    G_fatal_error(_("Unable to open vector map <%s>"), map_opt->answer);
        
	Vect_build(&Map);
    }
    /* dump topology */
    if (dump || sdump || cdump || fdump) {
	if (!build) {
	    Vect_set_open_level(2);

	    if (Vect_open_old(&Map, map_opt->answer, "") < 0)
		G_fatal_error(_("Unable to open vector map <%s>"),
				map_opt->answer);
	}
	if (dump)
	    Vect_topo_dump(&Map, stdout);

	if (sdump)
	    Vect_sidx_dump(&Map, stdout);

	if (cdump)
	    Vect_cidx_dump(&Map, stdout);
	
	if (fdump)
	    Vect_fidx_dump(&Map, stdout);
    }

    if (err_opt->answer) {
	int nlines, line, type, area, left, right, err, narea;
	struct Map_info Err;
	struct line_pnts *Points;
	struct line_cats *Cats;

	Points = Vect_new_line_struct();
	Cats = Vect_new_cats_struct();

	if (Vect_open_new(&Err, err_opt->answer, Vect_is_3d(&Map)) < 0)
	    G_fatal_error(_("Unable to create vector map <%s>"),
			    err_opt->answer);

	nlines = Vect_get_num_lines(&Map);

	for (line = 1; line <= nlines; line++) {
	    err = 0;

	    if (!Vect_line_alive(&Map, line))
		continue;

	    type = Vect_read_line(&Map, Points, Cats, line);

	    if (type == GV_BOUNDARY) {
		Vect_get_line_areas(&Map, line, &left, &right);
		if (left == 0 || right == 0)
		    err = 1;
	    }
	    else if (type == GV_CENTROID) {
		area = Vect_get_centroid_area(&Map, line);
		if (area <= 0)
		    err = 1;
	    }

	    if (err)
		Vect_write_line(&Err, type, Points, Cats);

	}

	narea = Vect_get_num_areas(&Map);

	for (area = 1; area <= narea; area++) {
	    if (!Vect_area_alive(&Map, area))
		continue;

	    if (Vect_get_area_centroid(&Map, area) == 0) {
		Vect_get_area_points(&Map, area, Points);
		Vect_reset_cats(Cats);
		Vect_write_line(&Err, GV_BOUNDARY, Points, Cats);
	    }
	}

	if (chk->answer)
	    Vect_topo_check(&Map, &Err);

	Vect_build(&Err);
	Vect_close(&Err);
    }
    else if (chk->answer)
	Vect_topo_check(&Map, NULL);

    if (build || dump || sdump || cdump) {
	Vect_close(&Map);
    }

    exit(EXIT_SUCCESS);
}
