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

#include "local_proto.h"

void copy_tabs(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);
        }
    }
}
