""" Standard Utility Script for Gridding Data
    1. Contains all the common functions that 
        will be employed across various different interpolators

"""
import numpy as np
from scipy import spatial


def make_grid(self, x, y, res, offset=0.2):
    """ This function returns the grid to perform interpolation on.
       This function is used inside the fit() attribute of the idw class.
    
    Parameters
    ----------
    x: array-like, shape(n_samples,)
        The first coordinate values of all points where
        ground truth is available
    y: array-like, shape(n_samples,)
        The second coordinate values of all points where
        ground truth is available
    res: int
        The resolution value
    offset: float, optional
        A value between 0 and 0.5 that specifies the extra interpolation to be done
        Default is 0.2
    
    Returns
    -------
    xx : {array-like, 2D}, shape (n_samples, n_samples)
    yy : {array-like, 2D}, shape (n_samples, n_samples)
    """
    y_min = y.min() - offset
    y_max = y.max() + offset
    x_min = x.min() - offset
    x_max = x.max() + offset
    x_arr = np.linspace(x_min, x_max, res)
    y_arr = np.linspace(y_min, y_max, res)
    xx, yy = np.meshgrid(x_arr, y_arr)
    return xx, yy


def find_closest(grid, X, l=2):
    """Function used to find the indices of the grid points closest
    to the passed points in X.

    Parameters
    ----------
    grid: {list of 2 arrays}, (shape(res, res), shape(res, res))
        This is generated by meshgrid.

    X: {array-like, 2D matrix}, shape(n_samples, 2)
        The set of points to which we need to provide closest points
        on the grid.

    l: str, optional
        To decide the `l`th norm to use. `Default = 2`.

    Returns
    -------
    ix: array, shape(X.shape[0],)
        The index of the point closest to points in X.

    ref - https://stackoverflow.com/questions/10818546/finding-index-of-nearest-point-in-numpy-arrays-of-x-and-y-coordinates
    """
    points = np.asarray([grid[0].ravel(), grid[1].ravel()]).T  # ravel is inplace
    kdtree = spatial.KDTree(points)
    ixs = []  # for containing the indices of closest points found on grid

    for point_ix in range(X.shape[0]):
        point = X[point_ix, :]
        _, ix = kdtree.query(point)
        ixs.append(ix)

    return ixs
