#include <grass/gis.h>
#include <grass/vector.h>
#include <grass/dbmi.h>
#include <grass/glocale.h>

#include "local_proto.h"

void copy_tabs(const struct Map_info *In, int field, int new_cat,
	       struct Map_info *Out)
{
    int nlines, line, i;
    int ttype, ntabs;
    int **ocats, *nocats, nfields, *fields;
    
    struct field_info *IFi, *OFi;
    struct line_cats *Cats;
    dbDriver *driver;
    
    ntabs = 0;
    
    /* Collect list of output cats */
    Cats = Vect_new_cats_struct();
    nfields = Vect_cidx_get_num_fields(Out);
    ocats = (int **)G_malloc(nfields * sizeof(int *));
    nocats = (int *)G_malloc(nfields * sizeof(int));
    fields = (int *)G_malloc(nfields * sizeof(int));
    for (i = 0; i < nfields; i++) {
	nocats[i] = 0;
	ocats[i] =
	    (int *)G_malloc(Vect_cidx_get_num_cats_by_index(Out, i) *
			    sizeof(int));
	fields[i] = Vect_cidx_get_field_number(Out, i);
    }
    
    nlines = Vect_get_num_lines(Out);
    for (line = 1; line <= nlines; line++) {
	Vect_read_line(Out, NULL, Cats, line);
	
	for (i = 0; i < Cats->n_cats; i++) {
	    int f, j;
	    
	    f = -1;
	    for (j = 0; j < nfields; j++) {	/* find field */
		if (fields[j] == Cats->field[i]) {
		    f = j;
		    break;
		}
	    }
	    if (f >= 0) {
		ocats[f][nocats[f]] = Cats->cat[i];
		nocats[f]++;
	    }
	}
    }
    
    /* Copy tables */
    G_message(_("Writing attributes..."));
    
    /* Number of output tabs */
    for (i = 0; i < Vect_get_num_dblinks(In); i++) {
	int j, f = -1;
	
	IFi = Vect_get_dblink(In, i);
	
	for (j = 0; j < nfields; j++) {	/* find field */
	    if (fields[j] == IFi->number) {
		f = j;
		break;
	    }
	}
	if (f >= 0 && nocats[f] > 0)
	    ntabs++;
    }
    
    if (ntabs > 1)
	ttype = GV_MTABLE;
    else
	ttype = GV_1TABLE;
    
    for (i = 0; i < nfields; i++) {
	int ret;
	
	if (fields[i] == 0)
	    continue;
	if (nocats[i] == 0)
	    continue;
	if (fields[i] == field && new_cat != -1)
		continue;
	
	G_verbose_message(_("Writing attributes for layer %d"), fields[i]);
	
	/* Make a list of categories */
	IFi = Vect_get_field(In, fields[i]);
	if (!IFi) {		/* no table */
	    G_message(_("No attribute table for layer %d"), fields[i]);
	    continue;
	}
	
	OFi = Vect_default_field_info(Out, IFi->number, NULL, ttype);
	
	ret = db_copy_table_by_ints(IFi->driver, IFi->database, IFi->table,
				    OFi->driver,
				    Vect_subst_var(OFi->database, Out),
				    OFi->table, IFi->key, ocats[i],
				    nocats[i]);
	
	if (ret == DB_FAILED) {
	    G_warning(_("Unable to copy table <%s>"), IFi->table);
	}
	else {

	    driver = db_start_driver_open_database(OFi->driver,
						   Vect_subst_var(OFi->database,
								    Out));

	    if (!driver) {
		G_warning(_("Unable to open database <%s> with driver <%s>"),
			      OFi->database, OFi->driver);
	    }
	    else {

		/* do not allow duplicate keys */
		if (db_create_index2(driver, OFi->table, IFi->key) != DB_OK) {
		    G_warning(_("Unable to create index"));
		}

		if (db_grant_on_table(driver, OFi->table, DB_PRIV_SELECT,
		     DB_GROUP | DB_PUBLIC) != DB_OK) {
		    G_warning(_("Unable to grant privileges on table <%s>"),
				  OFi->table);
		}

		db_close_database_shutdown_driver(driver);
	    }

	    Vect_map_add_dblink(Out, OFi->number, OFi->name, OFi->table,
				IFi->key, OFi->database, OFi->driver);
	}
    }
}
