
/****************************************************************************
 *
 * MODULE:       r.cross
 *
 * AUTHOR(S):    Michael Shapiro - CERL
 *
 * PURPOSE:      Creates a cross product of the category values from
 *               multiple raster map layers.
 *
 * COPYRIGHT:    (C) 2006 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 <grass/glocale.h>
#include <grass/raster.h>
#include <grass/btree.h>
#include "glob.h"
#include "local_proto.h"

static int compare(const void *aa, const void *bb)
{
    const CELL *a = aa;
    const CELL *b = bb;
    int i;

    for (i = 0; i < nfiles; i++) {
	if (a[i] > b[i])
	    return 1;
	if (a[i] < b[i])
	    return -1;
    }

    return 0;
}

CELL cross(int fd[], int non_zero, int primary, int outfd)
{
    BTREE btree;
    CELL *cell[NFILES];
    CELL *result_cell;
    CELL cat[NFILES];
    int row, col, i;
    int zero;
    CELL result;
    int keysize = nfiles * sizeof(CELL);
    void *ptr;

    /* allocate i/o buffers for each raster map */

    for (i = 0; i < nfiles; i++)
	cell[i] = Rast_allocate_c_buf();
    result_cell = cell[0];

    /* initialize the reclass table */
    result = 0;

    /* here we go */
    btree_create(&btree, compare, 1);
    G_message(_("%s: STEP 1 ... "), G_program_name());
    for (row = 0; row < nrows; row++) {
	G_percent(row, nrows, 5);

	/* read the primary file first, even if not first in the list */
	Rast_get_c_row(fd[primary], cell[0], row);

	/* read the others */
	col = 1;
	for (i = 0; i < nfiles; i++)
	    if (i != primary)
		Rast_get_c_row(fd[i], cell[col++], row);
	for (col = 0; col < ncols; col++) {
	    zero = 1;
	    for (i = 0; i < nfiles; i++) {
		cat[i] = cell[i][col];
		if (!Rast_is_c_null_value(&cat[i]))
		    zero = 0;
		else if (non_zero) {
		    zero = 1;
		    break;
		}
	    }
	    if (zero) {
		Rast_set_c_null_value(&result_cell[col], 1);
		continue;
	    }

	    /* search for this value in the tree */
	    if (btree_find(&btree, cat, &ptr))
		result_cell[col] = *(CELL*)ptr;
	    else {
		btree_update(&btree, cat, keysize, &result, sizeof(CELL));
		store_reclass(result, primary, cat);
		result_cell[col] = result;
		result++;
	    }
	}
	Rast_put_row(outfd, result_cell, CELL_TYPE);
    }
    G_percent(nrows, nrows, 5);

    /* free some memory */
    btree_free(&btree);
    for (i = 0; i < nfiles; i++)
	G_free(cell[i]);
    return result;
}
