#include <grass/config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <grass/lidar.h>

/*------------------------------------------------------------------------------------------------*/
void
P_Sparse_Points(struct Map_info *Out, struct Cell_head *Elaboration,
		struct bound_box General, struct bound_box Overlap, double **obs,
		double *param, int *line_num, double pe, double pn,
		double overlap, int nsplx, int nsply, int num_points,
		int bilin, struct line_cats *categories, dbDriver * driver,
		double mean, char *tab_name)
{
    int i;
    char buf[1024];
    dbString sql;

    double interpolation, csi, eta, weight;
    struct line_pnts *point;

    point = Vect_new_line_struct();

    db_begin_transaction(driver);
    
    for (i = 0; i < num_points; i++) {

	if (Vect_point_in_box(obs[i][0], obs[i][1], mean, &General)) {	/*Here mean is just for asking if obs point is in box */

	    if (bilin)
		interpolation =
		    dataInterpolateBilin(obs[i][0], obs[i][1], pe, pn, nsplx,
					 nsply, Elaboration->west,
					 Elaboration->south, param);
	    else
		interpolation =
		    dataInterpolateBicubic(obs[i][0], obs[i][1], pe, pn,
					   nsplx, nsply, Elaboration->west,
					   Elaboration->south, param);

	    interpolation += mean;
	    Vect_copy_xyz_to_pnts(point, &obs[i][0], &obs[i][1],
				  &interpolation, 1);

	    if (Vect_point_in_box(obs[i][0], obs[i][1], interpolation, &Overlap)) {	/*(5) */
		Vect_write_line(Out, GV_POINT, point, categories);
	    }
	    else {
		db_init_string(&sql);

		sprintf(buf, "INSERT INTO %s (ID, X, Y, Interp)", tab_name);
		db_append_string(&sql, buf);

		sprintf(buf, " VALUES (");
		db_append_string(&sql, buf);
		sprintf(buf, "%d, %f, %f, ", line_num[i], obs[i][0],
			obs[i][1]);
		db_append_string(&sql, buf);

		if ((*point->x > Overlap.E) && (*point->x < General.E)) {
		    if ((*point->y > Overlap.N) && (*point->y < General.N)) {	/*(3) */
			csi = (General.E - *point->x) / overlap;
			eta = (General.N - *point->y) / overlap;
			weight = csi * eta;
			*point->z = weight * interpolation;

			sprintf(buf, "%lf", *point->z);
			db_append_string(&sql, buf);
			sprintf(buf, ")");
			db_append_string(&sql, buf);

			if (db_execute_immediate(driver, &sql) != DB_OK)
			    G_fatal_error(_("Unable to access table <%s>"),
					  tab_name);
		    }
		    else if ((*point->y < Overlap.S) && (*point->y > General.S)) {	/*(1) */
			csi = (General.E - *point->x) / overlap;
			eta = (*point->y - General.S) / overlap;
			weight = csi * eta;
			*point->z = weight * interpolation;

			sprintf(buf, "%lf", *point->z);
			db_append_string(&sql, buf);
			sprintf(buf, ")");
			db_append_string(&sql, buf);

			if (db_execute_immediate(driver, &sql) != DB_OK)
			    G_fatal_error(_("Unable to access table <%s>"),
					  tab_name);
		    }
		    else if ((*point->y <= Overlap.N) && (*point->y >= Overlap.S)) {	/*(1) */
			weight = (General.E - *point->x) / overlap;
			*point->z = weight * interpolation;

			sprintf(buf, "%lf", *point->z);
			db_append_string(&sql, buf);
			sprintf(buf, ")");
			db_append_string(&sql, buf);

			if (db_execute_immediate(driver, &sql) != DB_OK)
			    G_fatal_error(_("Unable to access table <%s>"),
					  tab_name);
		    }
		}
		else if ((*point->x < Overlap.W) && (*point->x > General.W)) {
		    if ((*point->y > Overlap.N) && (*point->y < General.N)) {	/*(4) */
			csi = (*point->x - General.W) / overlap;
			eta = (General.N - *point->y) / overlap;
			weight = eta * csi;
			*point->z = weight * interpolation;

			sprintf(buf, "%lf", *point->z);
			db_append_string(&sql, buf);
			sprintf(buf, ")");
			db_append_string(&sql, buf);

			if (db_execute_immediate(driver, &sql) != DB_OK)
			    G_fatal_error(_("Unable to access table <%s>"),
					  tab_name);
		    }
		    else if ((*point->y < Overlap.S) && (*point->y > General.S)) {	/*(2) */
			csi = (*point->x - General.W) / overlap;
			eta = (*point->y - General.S) / overlap;
			weight = csi * eta;
			*point->z = weight * interpolation;

			sprintf(buf, "%lf", *point->z);
			db_append_string(&sql, buf);
			sprintf(buf, ")");
			db_append_string(&sql, buf);

			if (db_execute_immediate(driver, &sql) != DB_OK)
			    G_fatal_error(_("Unable to access table <%s>"),
					  tab_name);
		    }
		    else if ((*point->y >= Overlap.S) && (*point->y <= Overlap.N)) {	/*(2) */
			weight = (*point->x - General.W) / overlap;
			*point->z = weight * interpolation;

			sprintf(buf, "%lf", *point->z);
			db_append_string(&sql, buf);
			sprintf(buf, ")");
			db_append_string(&sql, buf);

			if (db_execute_immediate(driver, &sql) != DB_OK)
			    G_fatal_error(_("Unable to access table <%s>"),
					  tab_name);
		    }
		}
		else if ((*point->x >= Overlap.W) && (*point->x <= Overlap.E)){
		    if ((*point->y > Overlap.N) && (*point->y < General.N)) {	/*(3) */
			weight = (General.N - *point->y) / overlap;
			*point->z = weight * interpolation;

			sprintf(buf, "%lf", *point->z);
			db_append_string(&sql, buf);
			sprintf(buf, ")");
			db_append_string(&sql, buf);

			if (db_execute_immediate(driver, &sql) != DB_OK)
			    G_fatal_error(_("Unable to access table <%s>"),
					  tab_name);
		    }
		    else if ((*point->y < Overlap.S) && (*point->y > General.S)) {	/*(1) */
			weight = (*point->y - General.S) / overlap;
			*point->z = (1 - weight) * interpolation;

			sprintf(buf, "%lf", *point->z);
			db_append_string(&sql, buf);
			sprintf(buf, ")");
			db_append_string(&sql, buf);

			if (db_execute_immediate(driver, &sql) != DB_OK)
			    G_fatal_error(_("Unable to access table <%s>"),
					  tab_name);
		    }
		}
	    }
	}  /*IF*/
    }  /*FOR*/

    db_commit_transaction(driver);

    return;
}


/*------------------------------------------------------------------------------------------------*/
int P_Regular_Points(struct Cell_head *Elaboration, struct Cell_head *Original,
                          struct bound_box General, struct bound_box Overlap,
			  SEGMENT *out_seg, double *param,
			  double passoN, double passoE, double overlap,
			  double mean, int nsplx, int nsply,
			  int nrows, int ncols, int bilin)
{

    int col, row, startcol, endcol, startrow, endrow;
    double X, Y, interpolation, weight, csi, eta, dval;

    /* G_get_window(&Original); */
    if (Original->north > General.N)
	startrow = (Original->north - General.N) / Original->ns_res - 1;
    else
	startrow = 0;
    if (Original->north > General.S) {
	endrow = (Original->north - General.S) / Original->ns_res + 1;
	if (endrow > nrows)
	    endrow = nrows;
    }
    else
	endrow = nrows;
    if (General.W > Original->west)
	startcol = (General.W - Original->west) / Original->ew_res - 1;
    else
	startcol = 0;
    if (General.E > Original->west) {
	endcol = (General.E - Original->west) / Original->ew_res + 1;
	if (endcol > ncols)
	    endcol = ncols;
    }
    else
	endcol = ncols;

    for (row = startrow; row < endrow; row++) {
	for (col = startcol; col < endcol; col++) {

	    X = Rast_col_to_easting((double)(col) + 0.5, Original);
	    Y = Rast_row_to_northing((double)(row) + 0.5, Original);

	    if (Vect_point_in_box(X, Y, mean, &General)) {	/* Here, mean is just for asking if obs point is in box */

		if (bilin)
		    interpolation =
			dataInterpolateBilin(X, Y, passoE, passoN, nsplx,
					     nsply, Elaboration->west,
					     Elaboration->south, param);
		else
		    interpolation =
			dataInterpolateBicubic(X, Y, passoE, passoN, nsplx,
					       nsply, Elaboration->west,
					       Elaboration->south, param);

		interpolation += mean;

		if (Vect_point_in_box(X, Y, interpolation, &Overlap)) {	/* (5) */
		    dval = interpolation;
		}
		else {
		    segment_get(out_seg, &dval, row, col);
		    if ((X > Overlap.E) && (X < General.E)) {
			if ((Y > Overlap.N) && (Y < General.N)) {	/* (3) */
			    csi = (General.E - X) / overlap;
			    eta = (General.N - Y) / overlap;
			    weight = csi * eta;
			    interpolation *= weight;
			    dval += interpolation;
			}
			else if ((Y < Overlap.S) && (Y > General.S)) {	/* (1) */
			    csi = (General.E - X) / overlap;
			    eta = (Y - General.S) / overlap;
			    weight = csi * eta;
			    interpolation *= weight;
			    dval = interpolation;
			}
			else if ((Y >= Overlap.S) && (Y <= Overlap.N)) {	/* (1) */
			    weight = (General.E - X ) / overlap;
			    interpolation *= weight;
			    dval = interpolation;
			}
		    }
		    else if ((X < Overlap.W) && (X > General.W)) {
			if ((Y > Overlap.N) && (Y < General.N)) {	/* (4) */
			    csi = (X - General.W) / overlap;
			    eta = (General.N - Y) / overlap;
			    weight = eta * csi;
			    interpolation *= weight;
			    dval += interpolation;
			}
			else if ((Y < Overlap.S) && (Y > General.S)) {	/* (2) */
			    csi = (X - General.W) / overlap;
			    eta = (Y - General.S) / overlap;
			    weight = csi * eta;
			    interpolation *= weight;
			    dval += interpolation;
			}
			else if ((Y >= Overlap.S) && (Y <= Overlap.N)) {	/* (2) */
			    weight = (X - General.W) / overlap;
			    interpolation *= weight;
			    dval += interpolation;
			}
		    }
		    else if ((X >= Overlap.W) && (X <= Overlap.E)) {
			if ((Y > Overlap.N) && (Y < General.N)) {	/* (3) */
			    weight = (General.N - Y) / overlap;
			    interpolation *= weight;
			    dval += interpolation;
			}
			else if ((Y < Overlap.S) && (Y > General.S)) {	/* (1) */
			    weight = (Y - General.S) / overlap;
			    interpolation *= weight;
			    dval = interpolation;
			}
		    }
		}
		segment_put(out_seg, &dval, row, col);
	    }
	}			/* END COL */
    }				/* END ROW */
    return 1;
}
