#include <grass/vector.h>
#include <grass/raster.h>
#include <grass/glocale.h>

#include "local_proto.h"

void scan_z(struct Map_info *Map, int field,
            const char *style, const char *rules,
            const struct FPRange *range, struct Colors *colors, int invert)
{
    int ltype, line, cat, i, found;
    int items_alloc;
    double zmin = 0, zmax = 0;
    struct line_pnts *Points;
    struct line_cats *Cats;

    struct Colors vcolors;

    dbCatValArray cvarr;

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

    items_alloc = 0;
    db_CatValArray_init(&cvarr);
    cvarr.ctype = DB_C_TYPE_DOUBLE;

    Vect_set_constraint_field(Map, field);

    /* points, centroids or kernels only) */
    Vect_set_constraint_type(Map, GV_POINTS);

    G_message(_("Reading features..."));
    line = i = found = 0;
    while(TRUE) {
	ltype = Vect_read_next_line(Map, Points, Cats);
	if (ltype == -1)
	    G_fatal_error(_("Unable to read vector map"));
	if (ltype == -2)
	    break; /* EOF */

	G_progress(++line, 1e4);

        if (Vect_cat_get(Cats, field, &cat) == -1)
            continue; /* skip features without category */

        /* add item into cat-value array */
        if (i >= items_alloc) {
            items_alloc += 1000;
            db_CatValArray_realloc(&cvarr, items_alloc);
        }
        cvarr.n_values++;
        cvarr.value[i].cat = cat;
        cvarr.value[i++].val.d = Points->z[0];

	if (!found || Points->z[0] < zmin)
	    zmin = Points->z[0];
	if (!found || Points->z[0] > zmax)
	    zmax = Points->z[0];
	found = 1;
    }
    G_progress(1, 1);

    /* sort array by z-coordinate */
    db_CatValArray_sort_by_value(&cvarr);

    if (range) {
	if (!found || (range->min >= zmin && range->min <= zmax))
	    zmin = range->min;
	else
	    G_warning(_("Min value (%f) is out of range %f,%f"),
		      range->min, zmin, zmax);

	if (!found || (range->max <= zmax && range->max >= zmin))
	    zmax = range->max;
	else
	    G_warning(_("Max value (%f) is out of range %f,%f"),
		      range->max, zmin, zmax);
    }

    if (style)
	make_colors(&vcolors, style, (DCELL) zmin, (DCELL) zmax, TRUE);
    else if (rules)
	load_colors(&vcolors, rules, (DCELL) zmin, (DCELL) zmax, TRUE);

    /* color table for categories */
    color_rules_to_cats(&cvarr, TRUE, &vcolors, colors, invert, zmin, zmax);

    Vect_destroy_line_struct(Points);
    Vect_destroy_cats_struct(Cats);
    db_CatValArray_free(&cvarr);
}
