/*!
 * \file point2d.c
 *
 * \author
 * Lubos Mitas (original program and various modifications)
 *
 * \author
 * H. Mitasova,
 * I. Kosinovsky,
 * D. Gerdes,
 * D. McCauley
 * (GRASS4.1 version of the program and GRASS4.2 modifications)
 *
 * \author modified by McCauley in August 1995
 * \author modified by Mitasova in August 1995, Nov. 1996
 *
 * \copyright
 * (C) 1993-2006 by Helena Mitasova and the GRASS Development Team
 *
 * \copyright
 * This program is free software under the
 * GNU General Public License (>=v2).
 * Read the file COPYING that comes with GRASS for details.
 */

#include <stdio.h>
#include <math.h>
#include <unistd.h>
#include <grass/gis.h>
#include <grass/vector.h>
#include <grass/dbmi.h>

#define POINT2D_C
#include <grass/interpf.h>

/* needed for AIX */
#ifdef hz
#undef hz
#endif

/*!
 * Checks if interpolating function interp() evaluates correct z-values at
 * given points. If smoothing is used calculate the maximum error caused
 * by smoothing.
 *
 * *ertot* is a RMS deviation of the interpolated surface.
 *
 * \todo
 * Alternative description:
 * ...calculate the maximum and RMS deviation caused by smoothing.
 */
int IL_check_at_points_2d(struct interp_params *params,
                          struct quaddata *data, /*!< current region */
                          double *b,     /*!< solution of linear equations */
                          double *ertot, /*!< total error */
                          double zmin,   /*!< min z-value */
                          double dnorm, struct triple skip_point)
{
    int n_points = data->n_points;        /* number of points */
    struct triple *points = data->points; /* points for interpolation */
    double east = data->xmax;
    double west = data->x_orig;
    double north = data->ymax;
    double south = data->y_orig;
    double /* rfsta2, errmax, */ h, xx, yy, r2, hz, zz, err, xmm, ymm, r;
    double skip_err;
    int /* n1, */ mm, m, cat;

    /* double fstar2; */
    int inside;

    /*  Site *site; */
    char buf[1024];

    /*  if ((site = G_site_new_struct (-1, 2, 0, 1)) == NULL)
       G_fatal_error ("Memory error for site struct"); */

    /* fstar2 = params->fi * params->fi / 4.; */
    /* errmax = .0; */
    /* n1 = n_points + 1; */
    for (mm = 1; mm <= n_points; mm++) {
        h = b[0];
        for (m = 1; m <= n_points; m++) {
            xx = points[mm - 1].x - points[m - 1].x;
            yy = points[mm - 1].y - points[m - 1].y;
            r2 = yy * yy + xx * xx;
            if (r2 != 0.) {
                /* rfsta2 = fstar2 * r2; */
                r = r2;
                h = h + b[m] * params->interp(r, params->fi);
            }
        }
        /* modified by helena january 1997 - normalization of z was
           removed from segm2d.c and interp2d.c
           hz = (h * dnorm) + zmin;
           zz = (points[mm - 1].z * dnorm) + zmin;
         */
        hz = h + zmin;
        zz = points[mm - 1].z + zmin;
        err = hz - zz;
        xmm = points[mm - 1].x * dnorm + params->x_orig + west;
        ymm = points[mm - 1].y * dnorm + params->y_orig + south;
        if ((xmm >= west + params->x_orig) && (xmm <= east + params->x_orig) &&
            (ymm >= south + params->y_orig) && (ymm <= north + params->y_orig))
            inside = 1;
        else
            inside = 0;

        if (params->create_devi) {

            if (inside) { /* if the point is inside the region */
                Vect_reset_line(Pnts);
                Vect_reset_cats(Cats2);

                Vect_append_point(Pnts, xmm, ymm, zz);
                cat = count;
                Vect_cat_set(Cats2, 1, cat);
                Vect_write_line(&Map2, GV_POINT, Pnts, Cats2);

                db_zero_string(&sql2);
                sprintf(buf, "insert into %s values ( %d ", ff->table, cat);
                db_append_string(&sql2, buf);

                sprintf(buf, ", %f", err);
                db_append_string(&sql2, buf);
                db_append_string(&sql2, ")");
                G_debug(3, "IL_check_at_points_2d: %s", db_get_string(&sql2));

                if (db_execute_immediate(driver2, &sql2) != DB_OK) {
                    db_close_database(driver2);
                    db_shutdown_driver(driver2);
                    G_fatal_error("Cannot insert new row: %s",
                                  db_get_string(&sql2));
                }
                count++;
            }
        }
        (*ertot) += err * err;
    }

    /* cv stuff */
    if (params->cv) {
        h = b[0];
        for (m = 1; m <= n_points - 1; m++) {
            xx = points[m - 1].x - skip_point.x;
            yy = points[m - 1].y - skip_point.y;
            r2 = yy * yy + xx * xx;
            if (r2 != 0.) {
                /* rfsta2 = fstar2 * r2; */
                r = r2;
                h = h + b[m] * params->interp(r, params->fi);
            }
        }
        hz = h + zmin;
        zz = skip_point.z + zmin;
        skip_err = hz - zz;
        xmm = skip_point.x * dnorm + params->x_orig + west;
        ymm = skip_point.y * dnorm + params->y_orig + south;

        if ((xmm >= west + params->x_orig) && (xmm <= east + params->x_orig) &&
            (ymm >= south + params->y_orig) && (ymm <= north + params->y_orig))
            inside = 1;
        else
            inside = 0;

        if (inside) { /* if the point is inside the region */
            Vect_reset_line(Pnts);
            Vect_reset_cats(Cats2);

            Vect_append_point(Pnts, xmm, ymm, zz);
            cat = count;
            Vect_cat_set(Cats2, 1, cat);
            Vect_write_line(&Map2, GV_POINT, Pnts, Cats2);

            db_zero_string(&sql2);
            sprintf(buf, "insert into %s values ( %d ", ff->table, cat);
            db_append_string(&sql2, buf);

            sprintf(buf, ", %f", skip_err);
            db_append_string(&sql2, buf);
            db_append_string(&sql2, ")");
            G_debug(3, "IL_check_at_points_2d: %s", db_get_string(&sql2));

            if (db_execute_immediate(driver2, &sql2) != DB_OK) {
                db_close_database(driver2);
                db_shutdown_driver(driver2);
                G_fatal_error("Cannot insert new row: %s",
                              db_get_string(&sql2));
            }
            count++;
        }
    } /* cv */

    return 1;
}
