# Path: pygeoid/sharm/legendre.py
# def lplm(lmax, x):
#     """Associated Legendre functions of the first kind.
# 
#     Parameters
#     ----------
#     lmax : int
#         Maximum degree and order of the Plm(x).
#     x : float
#         Input value.
# 
#     Returns
#     -------
#     Plm(x) : (lmax + 1, lmax + 1) array
#         Values of Plm(x) for all orders and degrees.
#     """
#     return PlmBar(lmax, x)[_lplm_index(lmax)]
# 
# def lplm_d1(lmax, x):
#     """Associated Legendre functions of the first kind and their derivatives.
# 
#     Parameters
#     ----------
#     lmax : int
#         Maximum degree and order.
#     x : float
#         Input value.
# 
#     Returns
#     -------
#     Plm(x) : (lmax + 1, lmax + 1) array
#         Values of Plm(x) for all orders and degrees.
#     Plm_d(x) : {(lmax + 1, lmax + 1), None} array
#         Values of Plm_d(x) for all orders and degrees.
#         Will return None if `x` is very close or equal
#         to -1 or 1.
#     """
#     if not (np.allclose(-1, x) or np.allclose(1, x)):
#         index = _lplm_index(lmax)
#         p, p_d1 = PlmBar_d1(lmax, x)
#         return p[index], p_d1[index]
#     else:
#         p = lplm(lmax, x)
#         return p, None


import warnings
import numpy as np
from joblib import Parallel, delayed
from .legendre import lplm, lplm_d1


def common_precompute(lat, lon, r, r0, lmax):

    lat = np.atleast_2d(lat)
    lon = np.atleast_2d(lon)
    r = np.atleast_2d(r)

    degrees = np.arange(lmax + 1)
    m = np.atleast_2d(lon[0]).T * degrees

    cosin = np.array([np.cos(m), np.sin(m)])

    if np.allclose(r[:, 0, None], r):
        ri = 1 / r[:, 0]
        x = np.sin(lat[:, 0])
    else:
        ri = 1 / r
        x = np.sin(lat)

    q = np.asarray(r0 * ri)

    if np.any(q > 1.01):
        warnings.filterwarnings('once')
        warnings.warn("Possible singularity in downward continuation, r << r0")

    return lat, lon, degrees, cosin, x, q


def in_coeff_potential(x, q, lmax, degrees):

# Path: pygeoid/sharm/legendre.py
# def lplm(lmax, x):
#     """Associated Legendre functions of the first kind.
# 
#     Parameters
#     ----------
#     lmax : int
#         Maximum degree and order of the Plm(x).
#     x : float
#         Input value.
# 
#     Returns
#     -------
#     Plm(x) : (lmax + 1, lmax + 1) array
#         Values of Plm(x) for all orders and degrees.
#     """
#     return PlmBar(lmax, x)[_lplm_index(lmax)]
# 
# def lplm_d1(lmax, x):
#     """Associated Legendre functions of the first kind and their derivatives.
# 
#     Parameters
#     ----------
#     lmax : int
#         Maximum degree and order.
#     x : float
#         Input value.
# 
#     Returns
#     -------
#     Plm(x) : (lmax + 1, lmax + 1) array
#         Values of Plm(x) for all orders and degrees.
#     Plm_d(x) : {(lmax + 1, lmax + 1), None} array
#         Values of Plm_d(x) for all orders and degrees.
#         Will return None if `x` is very close or equal
#         to -1 or 1.
#     """
#     if not (np.allclose(-1, x) or np.allclose(1, x)):
#         index = _lplm_index(lmax)
#         p, p_d1 = PlmBar_d1(lmax, x)
#         return p[index], p_d1[index]
#     else:
#         p = lplm(lmax, x)
#         return p, None


# Path: pygeoid/sharm/expand.py
import warnings
import numpy as np
from joblib import Parallel, delayed
from .legendre import lplm, lplm_d1



def common_precompute(lat, lon, r, r0, lmax):

    lat = np.atleast_2d(lat)
    lon = np.atleast_2d(lon)
    r = np.atleast_2d(r)

    degrees = np.arange(lmax + 1)
    m = np.atleast_2d(lon[0]).T * degrees

    cosin = np.array([np.cos(m), np.sin(m)])

    if np.allclose(r[:, 0, None], r):
        ri = 1 / r[:, 0]
        x = np.sin(lat[:, 0])
    else:
        ri = 1 / r
        x = np.sin(lat)

    q = np.asarray(r0 * ri)

    if np.any(q > 1.01):
        warnings.filterwarnings('once')
        warnings.warn("Possible singularity in downward continuation, r << r0")

    return lat, lon, degrees, cosin, x, q


def in_coeff_potential(x, q, lmax, degrees):

    p = lplm(lmax, x)