text:
export
    saelgv,
    scard,
    scard!,
    scdecd,
    sce2c,
    sce2s,
    sce2t,
    scencd,
    scfmt,
    scpart,
    scs2e,
    sct2e,
    sctiks,
    sdiff,
    set,
    sincpt,
    spd,
    sphcyl,
    sphlat,
    sphrec,
    spk14a,
    spk14b,
    spk14e,
    spkacs,
    spkapo,
    spkapp,
    spkaps,
    spkcls,
    spkcov!,
    spkcov,
    spkcpo,
    spkcpt,
    spkcvo,
    spkcvt,
    spkez,
    spkezp,
    spkezr,
    spkgeo,
    spkgps,
    spklef,
    spkltc,
    spkobj!,
    spkobj,
    spkopa,
    spkopn,
    spkpds,
    spkpos,
    spkpvn,
    spksfs,
    spkssb,
    spksub,
    spksub!,
    spkuds,
    spkuef,
    spkw02,
    spkw03,
    spkw05,
    spkw08,
    spkw09,
    spkw10,
    spkw12,
    spkw13,
    spkw15,
    spkw17,
    spkw18,
    spkw20,
    srfc2s,
    srfcss,
    srfnrm,
    srfrec,
    srfs2c,
    srfscc,
    srfxpt,
    ssize,
    ssize!,
    stelab,
    stpool,
    str2et,
    subpnt,
    subpt,
    subpt_pl02,
    subslr,
    subsol,
    subsol_pl02,
    sumad,
    sumai,
    surfnm,
    surfpt,
    surfpv,
    swpool,
    sxform,
    szpool

const SPICE_SRF_SFNMLN = 37

"""
    saelgv(vec1, vec2)

Find semi-axis vectors of an ellipse generated by two arbitrary three-dimensional vectors.

### Arguments ###

- `vec1`, `vec2`: Two vectors used to generate an ellipse

### Output ###

- `smajor`: Semi-major axis of ellipse
- `sminor`: Semi-minor axis of ellipse

### References ###

- [NAIF Documentation](https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/saelgv_c.html)
"""
function saelgv(vec1, vec2)
    @checkdims 3 vec1 vec2
    smajor = Array{SpiceDouble}(undef, 3)
    sminor = Array{SpiceDouble}(undef, 3)
    ccall((:saelgv_c, libcspice), Cvoid,
          (Ref{SpiceDouble}, Ref{SpiceDouble}, Ref{SpiceDouble}, Ref{SpiceDouble}),
          vec1, vec2, smajor, sminor)
    smajor, sminor
end

"""
    scard!(cell::SpiceCell{T}, card) where T

Set the cardinality of a cell.

### Arguments ###

- `cell`: The cell
- `card`: Cardinality of (number of elements in) the cell

### Output ###

Returns `cell` with its cardinality set to `card`.

### References ###

- [NAIF Documentation](https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/scard_c.html)
"""
function scard!(cell::SpiceCell{T}, card) where T
    data = cell.data
    GC.@preserve data begin
        ccall((:scard_c, libcspice), Cvoid, (SpiceInt, Ref{Cell{T}}), card, cell.cell)
    end
    cell
end

@deprecate scard scard!

"""
    scdecd(sc, sclkdp, lenout=128)

Convert double precision encoding of spacecraft clock time into a character representation.

### Arguments ###

- `sc`: NAIF spacecraft identification code
- `sclkdp`: Encoded representation of a spacecraft clock count
- `lenout`: Maximum allowed length of output SCLK string

### Output ###

Returns the character representation of a clock count.

### References ###

- [NAIF Documentation](https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/scdecd_c.html)
"""
function scdecd(sc, sclkdp, lenout=128)
    sclkch = Array{SpiceChar}(undef, lenout)
    ccall((:scdecd_c, libcspice), Cvoid,
          (SpiceInt, SpiceDouble, SpiceInt, Ref{SpiceChar}),
          sc, sclkdp, lenout, sclkch)
    handleerror()
    chararray_to_string(sclkch)
end

"""
    sce2c(sc, et)

Convert ephemeris seconds past J2000 (ET) to continuous encoded spacecraft clock ("ticks").
Non-integral tick values may be returned.

### Arguments ###

- `sc`: NAIF spacecraft ID code
- `et`: Ephemeris time, seconds past J2000

### Output ###

Returns SCLK, encoded as ticks since spacecraft clock start.

### References ###

- [NAIF Documentation](https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/sce2c_c.html)
"""
function sce2c(sc, et)
    sclkdp = Ref{SpiceDouble}()
    ccall((:sce2c_c, libcspice), Cvoid,
          (SpiceInt, SpiceDouble, Ref{SpiceDouble}),
          sc, et, sclkdp)
    handleerror()
    sclkdp[]
end

"""
    sce2s(sc, et, lenout=128)

Convert an epoch specified as ephemeris seconds past J2000 (ET) to a character string
representation of a spacecraft clock value (SCLK).

### Arguments ###

- `sc`: NAIF spacecraft identification code
- `et`: Ephemeris time, specified as seconds past J2000
- `lenout`: Maximum allowed length of output SCLK string

### Output ###

Returns an SCLK string.

### References ###

- [NAIF Documentation](https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/sce2s_c.html)
"""
function sce2s(sc, et, lenout=128)
    sclkch = Array{SpiceChar}(undef, lenout)
    ccall((:sce2s_c, libcspice), Cvoid,
          (SpiceInt, SpiceDouble, SpiceInt, Ref{SpiceChar}),
          sc, et, lenout, sclkch)
    handleerror()
    chararray_to_string(sclkch)
end

"""
    sce2t(sc, et)

Convert ephemeris seconds past J2000 (ET) to integral encoded spacecraft clock ("ticks").
For conversion to fractional ticks, (required for C-kernel production), see the routine
[`sce2c`](@ref).

### Arguments ###

- `sc`: NAIF spacecraft ID code
- `et`: Ephemeris time, seconds past J2000

### Output ###

Returns SCLK, encoded as ticks since spacecraft clock start.

### References ###

- [NAIF Documentation](https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/sce2c_t.html)
"""
function sce2t(sc, et)
    sclkdp = Ref{SpiceDouble}()
    ccall((:sce2t_c, libcspice), Cvoid,
          (SpiceInt, SpiceDouble, Ref{SpiceDouble}),
          sc, et, sclkdp)
    handleerror()
    sclkdp[]
end

"""
    scencd(sc, sclkch)

Encode character representation of spacecraft clock time into a double precision number.

### Arguments ###

- `sc`: NAIF spacecraft identification code
- `sclkch`: Character representation of a spacecraft clock

### Output ###

Returns the encoded representation of the clock count.

### References ###

- [NAIF Documentation](https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/scencd_c.html)
"""
function scencd(sc, sclkch)
    sclkdp = Ref{SpiceDouble}()
    ccall((:scencd_c, libcspice), Cvoid,
          (SpiceInt, Cstring, Ref{SpiceDouble}),
          sc, sclkch, sclkdp)
    handleerror()
    sclkdp[]
end

"""
    scfmt(sc, ticks, lenout=128)

Convert encoded spacecraft clock ticks to character clock format.

### Arguments ###

- `sc`: NAIF spacecraft identification code
- `ticks`: Encoded representation of a spacecraft clock count
- `lenout`: Maximum allowed length of output string

### Output ###

Returns a character representation of a clock count.

### References ###

- [NAIF Documentation](https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/scfmt_c.html)
"""
function scfmt(sc, ticks, lenout=128)
    clkstr = Array{SpiceChar}(undef, lenout)
    ccall((:scfmt_c, libcspice), Cvoid,
          (SpiceInt, SpiceDouble, SpiceInt, Ref{SpiceChar}),
          sc, ticks, lenout, clkstr)
    handleerror()
    chararray_to_string(clkstr)
end

"""
    scpart(sc)

Get spacecraft clock partition information from a spacecraft clock kernel file.

### Arguments ###

- `sc`: NAIF spacecraft identification code

### Output ###

- `pstart`: Array of partition start times
- `pstop`: Array of partition stop times

### References ###

- [NAIF Documentation](https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/scpart_c.html)
"""
function scpart(sc)
    nparts = Ref{SpiceInt}()
    pstart = Array{SpiceDouble}(undef, 9999)
    pstop = Array{SpiceDouble}(undef, 9999)
    ccall((:scpart_c, libcspice), Cvoid,
          (SpiceInt, Ref{SpiceInt}, Ref{SpiceDouble}, Ref{SpiceDouble}),
          sc, nparts, pstart, pstop)
    handleerror()
    pstart[1:nparts[]], pstop[1:nparts[]]
end

"""
    scs2e(sc, sclkch)

Convert a spacecraft clock string to ephemeris seconds past J2000 (ET).

### Arguments ###

- `sc`: NAIF integer code for a spacecraft
- `sclkch`: An SCLK string

### Output ###

Returns ephemeris time seconds past J2000.

### References ###

- [NAIF Documentation](https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/scs2e_c.html)
"""
function scs2e(sc, sclkch)
    et = Ref{SpiceDouble}()
    ccall((:scs2e_c, libcspice), Cvoid,
          (SpiceInt, Cstring, Ref{SpiceDouble}),
          sc, sclkch, et)
    handleerror()
    et[]
end

"""
    sct2e(sc, sclkdp)

Convert encoded spacecraft clock ("ticks") to ephemeris seconds past J2000 (ET).

### Arguments ###

- `sc`: NAIF integer code for a spacecraft
- `sclkdp`: SCLK, encoded as ticks since spacecraft clock start.

### Output ###

Returns ephemeris time seconds past J2000.

### References ###

- [NAIF Documentation](https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/sct2e_c.html)
"""
function sct2e(sc, sclkdp)
    et = Ref{SpiceDouble}()
    ccall((:sct2e_c, libcspice), Cvoid,
          (SpiceInt, SpiceDouble, Ref{SpiceDouble}),
          sc, sclkdp, et)
    handleerror()
    et[]
end

"""
    sctiks(sc, clkstr)

Convert a spacecraft clock format string to number of "ticks".

### Arguments ###

- `sc`: NAIF spacecraft identification code
- `clkstr`: Character representation of a spacecraft clock

### Output ###

Returns the number of ticks represented by the clock string.

### References ###

- [NAIF Documentation](https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/sctiks_c.html)
"""
function sctiks(sc, clkstr)
    ticks = Ref{SpiceDouble}()
    ccall((:sctiks_c, libcspice), Cvoid,
          (SpiceInt, Cstring, Ref{SpiceDouble}),
          sc, clkstr, ticks)
    handleerror()
    ticks[]
end

"""
    sdiff(a::T, b::T) where T <: SpiceCell

Compute the symmetric difference of two sets of any data type to form a third set.

### Arguments ###

- `a`: First input set
- `b`: Second input set

### Output ###

Returns a cell containing the symmetric difference of `a` and `b`.

### References ###

- [NAIF Documentation](https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/sdiff_c.html)
"""
function sdiff(a::SpiceCell{T}, b::SpiceCell{T}) where T
    size = max(a.cell.size, b.cell.size)
    if T <: SpiceChar
        length = max(a.cell.length, b.cell.length)
        out = SpiceCell{T}(size, length)
    else
        out = SpiceCell{T}(size)
    end
    a_data = a.data
    b_data = b.data
    out_data = out.data
    GC.@preserve a_data b_data out_data begin
        ccall((:sdiff_c, libcspice), Cvoid, (Ref{Cell{T}}, Ref{Cell{T}}, Ref{Cell{T}}),
              a.cell, b.cell, out.cell)
    end
    handleerror()
    out
end

"""
    set(a::T, b::T) where T <: SpiceCell

Given a relational operator, compare two sets of any data type.

### Arguments ###

- `a`: First set
- `op`: Comparison operator
- `b`: Second set

### Output ###

Returns the result of the comparison: `a (op) b`.

### References ###

- [NAIF Documentation](https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/set_c.html)
"""
function set(a::SpiceCell{T}, op, b::SpiceCell{T}) where T
    a_data = a.data
    b_data = b.data
    GC.@preserve a_data b_data begin
        res = ccall((:set_c, libcspice), SpiceBoolean, (Ref{Cell{T}}, Cstring, Ref{Cell{T}}),
                    a.cell, op, b.cell)
    end
    handleerror()
    Bool(res[])
end

function _shellc(array)
    array_, m, n = chararray(array)
    ccall((:shellc_c, libcspice), Cvoid,
          (SpiceInt, SpiceInt, Ref{SpiceChar}),
          m, n, array_)
    handleerror()
    array[:] .= chararray_to_string(array_, m)
end

"""
    shellc(array)

!!! warning "Deprecated"
    Use `sort!(array)` instead.
"""
shellc

@deprecate shellc(array) sort!(array)

function _shelld(array)
    n = length(array)
    ccall((:shelld_c, libcspice), Cvoid,
          (SpiceInt, Ref{SpiceDouble}),
          n, array)
    handleerror()
    array
end

"""
    shelld(array)

!!! warning "Deprecated"
    Use `sort!(array)` instead.
"""
shelld

@deprecate shelld(array) sort!(array)

function _shelli(array)
    n = length(array)
    array_ = SpiceInt.(array)
    ccall((:shelli_c, libcspice), Cvoid,
          (SpiceInt, Ref{SpiceInt}),
          n, array_)
    handleerror()
    Int.(array_)
end

"""
    shelli(array)

!!! warning "Deprecated"
    Use `sort!(array)` instead.
"""
shelli

@deprecate shelli(array) sort!(array)

"""
    sincpt(method, target, et, fixref, abcorr, obsrvr, dref, dvec)

Given an observer and a direction vector defining a ray, compute the surface intercept
of the ray on a target body at a specified epoch, optionally corrected for light time
and stellar aberration.

The surface of the target body may be represented by a triaxial ellipsoid or by
topographic data provided by DSK files.

### Arguments ###

- `method`: Computation method
- `target`: Name of target body
- `et`: Epoch in TDB seconds past J2000 TDB
- `fixref`: Body-fixed, body-centered target body frame
- `abcorr`: Aberration correction flag
- `obsrvr`: Name of observing body
- `dref`: Reference frame of ray's direction vector
- `dvec`: Ray's direction vector

### Output ###

Returns a tuple consisting of the following data or `nothing` if no intercept was found.

- `spoint`: Surface intercept point on the target body
- `trgepc`: Intercept epoch
- `srfvec`: Vector from observer to intercept point

### References ###

- [NAIF Documentation](https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/sincpt_c.html)
"""
function sincpt(method, target, et, fixref, abcorr, obsrvr, dref, dvec)
    @checkdims 3 dvec

    spoint = Array{SpiceDouble}(undef, 3)
    trgepc = Ref{SpiceDouble}()
    srfvec = Array{SpiceDouble}(undef, 3)
    found = Ref{SpiceBoolean}()

    ccall((:sincpt_c, libcspice), Cvoid,
          (Cstring, Cstring, SpiceDouble, Cstring, Cstring, Cstring, Cstring, Ref{SpiceDouble},
           Ref{SpiceDouble}, Ref{SpiceDouble}, Ref{SpiceDouble}, Ref{SpiceBoolean}),
          method, target, et, fixref, abcorr, obsrvr, dref, dvec, spoint, trgepc, srfvec, found)

    handleerror()
    Bool(found[]) || return nothing

    spoint, trgepc[], srfvec
end

"""
    spd()

Returns the number of seconds in a day.

### References ###

- [NAIF Documentation](https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/spd_c.html)
"""
function spd()
    ccall((:spd_c, libcspice), SpiceDouble, ())
end

"""
    sphcyl(radius, colat, slon)

Converts from spherical coordinates to cylindrical coordinates.

### Arguments ###

- `radius`: Distance of point from origin
- `colat`: Polar angle (co-latitude in radians) of point
- `slon`: Azimuthal angle (longitude) of point (radians)

### Output ###

- `r`: Distance of point from Z axis
- `lon`: Angle (radians) of point from XZ plane
- `z`: Height of point above XY plane

### References ###

- [NAIF Documentation](https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/sphcyl_c.html)
"""
function sphcyl(radius, colat, slon)
    r = Ref{SpiceDouble}()
    lon = Ref{SpiceDouble}()
    z = Ref{SpiceDouble}()
    ccall((:sphcyl_c, libcspice), Cvoid,
          (SpiceDouble, SpiceDouble, SpiceDouble,
           Ref{SpiceDouble}, Ref{SpiceDouble}, Ref{SpiceDouble}),
          radius, colat, slon, r, lon, z)
    r[], lon[], z[]
end

"""
    sphlat(r, colat, lons)

Convert from spherical coordinates to latitudinal coordinates.

### Arguments ###

- `r`: Distance of the point from the origin
- `colat`: Angle of the point from positive z axis (radians)
- `lons`: Angle of the point from the XZ plane (radians)

### Output ###

- `radius`: Distance of a point from the origin
- `lon`: Angle of the point from the XZ plane in radians
- `lat`: Angle of the point from the XY plane in radians

### References ###

- [NAIF Documentation](https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/sphlat_c.html)
"""
function sphlat(r, colat, lons)
    radius = Ref{SpiceDouble}()
    lon = Ref{SpiceDouble}()
    lat = Ref{SpiceDouble}()
    ccall((:sphcyl_c, libcspice), Cvoid,
          (SpiceDouble, SpiceDouble, SpiceDouble,
           Ref{SpiceDouble}, Ref{SpiceDouble}, Ref{SpiceDouble}),
          r, colat, lons, radius, lon, lat)
    radius[], lon[], lat[]
end

"""
    sphrec(r, colat, lon)

Convert from spherical coordinates to rectangular coordinates.

### Arguments ###

- `r`: Distance of a point from the origin
- `colat`: Angle of the point from the Z-axis in radians
- `lon`: Angle of the point from the XZ plane in radians

### Output ###

Returns the rectangular coordinates of the point.

### References ###

- [NAIF Documentation](https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/sphrec_c.html)
"""
function sphrec(r, colat, lon)
    rectan = Array{SpiceDouble}(undef, 3)
    ccall((:sphrec_c, libcspice), Cvoid,
          (SpiceDouble, SpiceDouble, SpiceDouble, Ref{SpiceDouble}),
          r, colat, lon, rectan)
    rectan
end

"""
    spk14a(handle, ncsets, coeffs, epochs)

Add data to a type 14 SPK segment associated with `handle`.
See also [`spk14b`](@ref) and [`spk14e`](@ref).

### Arguments ###

- `handle`: The handle of an SPK file open for writing
- `ncsets`: The number of coefficient sets and epochs
- `coeffs`: The collection of coefficient sets
- `epochs`: The epochs associated with the coefficient sets

### References ###

- [NAIF Documentation](https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/spk14a_c.html)
"""
function spk14a(handle, ncsets, coeffs, epochs)
    ccall((:spk14a_c, libcspice), Cvoid,
          (SpiceInt, SpiceInt, Ref{SpiceDouble}, Ref{SpiceDouble}),
          handle, ncsets, coeffs, epochs)
    handleerror()
end

"""
    spk14b(handle, segid, body, center, frame, first, last, chbdeg)

Begin a type 14 SPK segment in the SPK file associated with `handle`.
See also [`spk14a`](@ref) and [`spk14e`](@ref).

### Arguments ###

- `handle`: The handle of an SPK file open for writing
- `segid`: The string to use for segment identifier
- `body`: The NAIF ID code for the body of the segment
- `center`: The center of motion for body
- `frame`: The reference frame for this segment
- `first`: The first epoch for which the segment is valid
- `last`: The last epoch for which the segment is valid
- `chbdeg`: The degree of the Chebyshev Polynomial used

### References ###

- [NAIF Documentation](https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/spk14b_c.html)
"""
function spk14b(handle, segid, body, center, frame, first, last, chbdeg)
    ccall((:spk14b_c, libcspice), Cvoid,
          (SpiceInt, Cstring, SpiceInt, SpiceInt, Cstring, SpiceDouble, SpiceDouble, SpiceInt),
          handle, segid, body, center, frame, first, last, chbdeg)
    handleerror()
end

"""
    spk14e(handle)

End the type 14 SPK segment currently being written to the SPK file associated with `handle`.
See also [`spk14a`](@ref) and [`spk14b`](@ref).

### Arguments ###

- `handle`: The handle of an SPK file open for writing

### Output ###

Returns the handle of the SPK file.

### References ###

- [NAIF Documentation](https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/spk14e_c.html)
"""
function spk14e(handle)
    ccall((:spk14e_c, libcspice), Cvoid, (SpiceInt,), handle)
    handle
end

"""
    spkacs(targ, et, ref, abcorr, obs, starg, lt, dlt)

Return the state (position and velocity) of a target body relative to an observer, optionally
corrected for light time and stellar aberration, expressed relative to an inertial reference frame.

### Arguments ###

- `targ`: Target body
- `et`: Observer epoch
- `ref`: Inertial reference frame of output state
- `abcorr`: Aberration correction flag
- `obs`: Observer

### Output ###

- `starg`: State of target
- `lt`: One way light time between observer and target
- `dlt`: Derivative of light time with respect to time

### References ###

- [NAIF Documentation](https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/spkacs_c.html)
"""
function spkacs(targ, et, ref, abcorr, obs)
    starg = Array{SpiceDouble}(undef, 6)
    lt = Ref{SpiceDouble}()
    dlt = Ref{SpiceDouble}()
    ccall((:spkacs_c, libcspice), Cvoid,
          (SpiceInt, SpiceDouble, Cstring, Cstring, SpiceInt,
           Ref{SpiceDouble}, Ref{SpiceDouble}, Ref{SpiceDouble}),
          targ, et, ref, abcorr, obs, starg, lt, dlt)
    handleerror()
    starg, lt[], dlt[]
end

"""
    spkapo(targ, et, ref, sobs, abcorr)

Return the position of a target body relative to an observer, optionally corrected for light time
and stellar aberration.

### Arguments ###

- `targ`: Target body
- `et`: Observer epoch
- `ref`: Inertial reference frame of observer's state
- `sobs`: State of observer wrt. solar system barycenter
- `abcorr`: Aberration correction flag

### Output ###

- `ptarg`: Position of target
- `lt`: One way light time between observer and target

### References ###

- [NAIF Documentation](https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/spkapo_c.html)
"""
function spkapo(targ, et, ref, sobs, abcorr)
    @checkdims 6 sobs
    ptarg = Array{SpiceDouble}(undef, 3)
    lt = Ref{SpiceDouble}()
    ccall((:spkapo_c, libcspice), Cvoid,
          (SpiceInt, SpiceDouble, Cstring, Ref{SpiceDouble}, Cstring,
           Ref{SpiceDouble}, Ref{SpiceDouble}),
          targ, et, ref, sobs, abcorr, ptarg, lt)
    handleerror()
    ptarg, lt[]
end

"""
    spkaps(targ, et, ref, abcorr, stobs, accobs)

Given the state and acceleration of an observer relative to the solar system barycenter, return the
state (position and velocity) of a target body relative to the observer, optionally corrected for
light time and stellar aberration. All input and output vectors are expressed relative to an
inertial reference frame.

Users normally should call the high-level API routines [`spkezr`](@ref) or [`spkez`](@ref) rather
than this routine.

### Arguments ###

- `targ`: Target body.
- `et`: Observer epoch.
- `ref`: Inertial reference frame of output state.
- `abcorr`: Aberration correction flag.
- `stobs`: State of the observer relative to the SSB.
- `accobs`: Acceleration of the observer relative to the SSB.

### Output ###

- `starg`: State of target.
- `lt`: One way light time between observer and target.
- `dlt`: Derivative of light time with respect to time.

### References ###

- [NAIF Documentation](https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/spkaps_c.html)
"""
function spkaps(targ, et, ref, abcorr, stobs, accobs)
    @checkdims 6 stobs accobs
    starg = Array{SpiceDouble}(undef, 6)
    lt = Ref{SpiceDouble}()
    dlt = Ref{SpiceDouble}()
    ccall((:spkaps_c, libcspice), Cvoid,
          (SpiceInt, SpiceDouble, Cstring, Cstring, Ref{SpiceDouble}, Ref{SpiceDouble},
           Ref{SpiceDouble}, Ref{SpiceDouble}, Ref{SpiceDouble}),
          targ, et, ref, abcorr, stobs, accobs, starg, lt, dlt)
    handleerror()
    starg, lt[], dlt[]
end

@deprecate spkapp spkaps

"""
    spkcls(handle)

Close an open SPK file.

### Arguments ###

- `handle`: Handle of the SPK file to be closed

### Output ###

Returns the handle of the closed file.

### References ###

- [NAIF Documentation](https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/spkcls_c.html)
"""
function spkcls(handle)
    ccall((:spkcls_c, libcspice), Cvoid, (SpiceInt,), handle)
    handleerror()
    handle
end

"""
    spkcov!(cover, spk, idcode)

Find the coverage window for a specified ephemeris object in a specified SPK file.

### Arguments ###

- `cover`: Window giving coverage in `spk` for `idcode`
- `spk`: Name of the SPK file
- `idcode`: ID code of ephemeris object

### Output ###

Returns the extended coverage window.

### References ###

- [NAIF Documentation](https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/spkcov_c.html)
"""
function spkcov!(cover, spk, idcode)
    data = cover.data
    GC.@preserve data begin
        ccall((:spkcov_c, libcspice), Cvoid,
              (Cstring, SpiceInt, Ref{Cell{SpiceDouble}}),
              spk, idcode, cover.cell)
    end
    handleerror()
    cover
end

@deprecate spkcov spkcov!

"""
    spkcpo(target, et, outref, refloc, abcorr, obspos, obsctr, obsref)

Return the state of a specified target relative to an "observer,"
where the observer has constant position in a specified reference
frame. The observer's position is provided by the calling program
rather than by loaded SPK files.

### Arguments ###

- `target`: Name of target ephemeris object
- `et`: Observation epoch
- `outref`: Reference frame of output state
- `refloc`: Output reference frame evaluation locus
- `abcorr`: Aberration correction
- `obspos`: Observer position relative to center of motion
- `obsctr`: Center of motion of observer
- `obsref`: Frame of observer position

### Output ###

- `state`: State of target with respect to observer
- `lt`: One way light time between target and observer

### References ###

- [NAIF Documentation](https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/spkcpo_c.html)
"""
function spkcpo(target, et, outref, refloc, abcorr, obspos, obsctr, obsref)
    @checkdims 3 obspos
    state = Array{SpiceDouble}(undef, 6)
    lt = Ref{SpiceDouble}()
    ccall((:spkcpo_c, libcspice), Cvoid,
          (Cstring, SpiceDouble, Cstring, Cstring, Cstring, Ref{SpiceDouble}, Cstring, Cstring,
           Ref{SpiceDouble}, Ref{SpiceDouble}),
          target, et, outref, refloc, abcorr, obspos, obsctr, obsref, state, lt)
    handleerror()
    state, lt[]
end

"""
    spkcpt(trgpos, trgctr, trgref, et, outref, refloc, abcorr, obsrvr)

Return the state, relative to a specified observer, of a target having constant position in a
specified reference frame. The target's position is provided by the calling program rather than by
loaded SPK files.

### Arguments ###

- `trgpos`: Target position relative to center of motion
- `trgctr`: Center of motion of target
- `trgref`: Frame of target position
- `et`: Observation epoch
- `outref`: Reference frame of output state
- `refloc`: Output reference frame evaluation locus
- `abcorr`: Aberration correction
- `obsrvr`: Name of observing ephemeris object

### Output ###

- `state`: State of target with respect to observer
- `lt`: One way light time between target and observer

### References ###

- [NAIF Documentation](https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/spkcpt_c.html)
"""
function spkcpt(trgpos, trgctr, trgref, et, outref, refloc, abcorr, obsrvr)
    @checkdims 3 trgpos
    state = Array{SpiceDouble}(undef, 6)
    lt = Ref{SpiceDouble}()
    ccall((:spkcpt_c, libcspice), Cvoid,
          (Ref{SpiceDouble}, Cstring, Cstring, SpiceDouble, Cstring, Cstring, Cstring, Cstring,
           Ref{SpiceDouble}, Ref{SpiceDouble}),
          trgpos, trgctr, trgref, et, outref, refloc, abcorr, obsrvr, state, lt)
    handleerror()
    state, lt[]
end

"""
    spkcvo(target, et, outref, refloc, abcorr, obssta, obsepc, obsctr, obsref)

Return the state of a specified target relative to an "observer," where the observer has constant
velocity in a specified reference frame.  The observer's state is provided by the calling program
rather than by loaded SPK files.

### Arguments ###

- `target`: Name of target ephemeris object
- `et`: Observation epoch
- `outref`: Reference frame of output state
- `refloc`: Output reference frame evaluation locus
- `abcorr`: Aberration correction
- `obssta`: Observer state relative to center of motion
- `obsepc`: Epoch of observer state
- `obsctr`: Center of motion of observer
- `obsref`: Frame of observer state

### Output ###

- `state`: State of target with respect to observer
- `lt`: One way light time between target and observer

### References ###

- [NAIF Documentation](https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/spkcvo_c.html)
"""
function spkcvo(target, et, outref, refloc, abcorr, obssta, obsepc, obsctr, obsref)
    @checkdims 6 obssta
    state = Array{SpiceDouble}(undef, 6)
    lt = Ref{SpiceDouble}()
    ccall((:spkcvo_c, libcspice), Cvoid,
          (Cstring, SpiceDouble, Cstring, Cstring, Cstring, Ref{SpiceDouble}, SpiceDouble, Cstring,
           Cstring, Ref{SpiceDouble}, Ref{SpiceDouble}),
          target, et, outref, refloc, abcorr, obssta, obsepc, obsctr, obsref, state, lt)
    handleerror()
    state, lt[]
end

"""
    spkcvt(trgsta, trgepc, trgctr, trgref, et, outref, refloc, abcorr, obsrvr)

Return the state, relative to a specified observer, of a target having constant velocity in a
specified reference frame. The target's state is provided by the calling program rather than by
loaded SPK files.

### Arguments ###

- `trgsta`: Target state relative to center of motion
- `trgepc`: Epoch of target state
- `trgctr`: Center of motion of target
- `trgref`: Frame of target state
- `et`: Observation epoch
- `outref`: Reference frame of output state
- `refloc`: Output reference frame evaluation locus
- `abcorr`: Aberration correction
- `obsrvr`: Name of observing ephemeris object

### Output ###

- `state`: State of target with respect to observer
- `lt`: One way light time between target and observer

### References ###

- [NAIF Documentation](https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/spkcvt_c.html)
"""
function spkcvt(trgsta, trgepc, trgctr, trgref, et, outref, refloc, abcorr, obsrvr)
    @checkdims 6 trgsta
    state = Array{SpiceDouble}(undef, 6)
    lt = Ref{SpiceDouble}()
    ccall((:spkcvt_c, libcspice), Cvoid,
          (Ref{SpiceDouble}, SpiceDouble, Cstring, Cstring, SpiceDouble, Cstring, Cstring, Cstring,
           Cstring, Ref{SpiceDouble}, Ref{SpiceDouble}),
          trgsta, trgepc, trgctr, trgref, et, outref, refloc, abcorr, obsrvr, state, lt)
    handleerror()
    state, lt[]
end

"""
    spkez(targ, et, ref, abcorr, obs)

Return the state (position and velocity) of a target body relative to an observing body,
optionally corrected for light time (planetary aberration) and stellar aberration.

### Arguments ###

- `targ`: Target body
- `et`: Observer epoch
- `ref`: Reference frame of output state vector
- `abcorr`: Aberration correction flag
- `obs`: Observing body

### Output ###

- `starg`: State of target
- `lt`: One way light time between observer and target

### References ###

- [NAIF Documentation](https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/spkez_c.html)
"""
function spkez(targ, et, ref, abcorr, obs)
    starg = Array{SpiceDouble}(undef, 6)
    lt = Ref{SpiceDouble}()
    ccall((:spkez_c, libcspice), Cvoid,
          (SpiceInt, SpiceDouble, Cstring, Cstring, SpiceInt, Ref{SpiceDouble}, Ref{SpiceDouble}),
          targ, et, ref, abcorr, obs, starg, lt)
    handleerror()
    starg, lt[]
end

"""
    spkezp(targ, et, ref, abcorr, obs)

Return the position of a target body relative to an observing body,
optionally corrected for light time (planetary aberration) and stellar aberration.

### Arguments ###

- `targ`: Target body
- `et`: Observer epoch
- `ref`: Reference frame of output state vector
- `abcorr`: Aberration correction flag
- `obs`: Observing body

### Output ###

- `ptarg`: Position of target
- `lt`: One way light time between observer and target

### References ###

- [NAIF Documentation](https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/spkezp_c.html)
"""
function spkezp(targ, et, ref, abcorr, obs)
    ptarg = Array{SpiceDouble}(undef, 3)
    lt = Ref{SpiceDouble}()
    ccall((:spkezp_c, libcspice), Cvoid,
          (SpiceInt, SpiceDouble, Cstring, Cstring, SpiceInt, Ref{SpiceDouble}, Ref{SpiceDouble}),
          targ, et, ref, abcorr, obs, ptarg, lt)
    handleerror()
    ptarg, lt[]
end

"""
    spkezr(targ, et, ref, abcorr, obs)

Return the state (position and velocity) of a target body relative to an observing body, optionally
corrected for light time (planetary aberration) and stellar aberration.

### Arguments ###

- `targ`: Target body name
- `et`: Observer epoch
- `ref`: Reference frame of output state vector
- `abcorr`: Aberration correction flag
- `obs`: Observing body name

### Output ###

- `starg`: State of target
- `lt`: One way light time between observer and target

### References ###

- [NAIF Documentation](https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/spkezr_c.html)
"""
function spkezr(targ, et, ref, abcorr, obs)
    starg = Array{SpiceDouble}(undef, 6)
    lt = Ref{SpiceDouble}()
    ccall((:spkezr_c, libcspice), Cvoid,
          (Cstring, SpiceDouble, Cstring, Cstring, Cstring, Ref{SpiceDouble}, Ref{SpiceDouble}),
          targ, et, ref, abcorr, obs, starg, lt)
    handleerror()
    starg, lt[]
end

"""
    spkgeo(targ, et, ref, obs)

Compute the geometric state (position and velocity) of a target body relative to an observing body.

### Arguments ###

- `targ`: Target body.
- `et`: Target epoch.
- `ref`: Target reference frame.
- `obs`: Observing body.

### Output ###

- `state`: State of target.
- `lt`: Light time.

### References ###

- [NAIF Documentation](https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/spkgeo_c.html)
"""
function spkgeo(targ, et, ref, obs)
    state = Array{SpiceDouble}(undef, 6)
    lt = Ref{SpiceDouble}()
    ccall((:spkgeo_c, libcspice), Cvoid,
          (SpiceInt, SpiceDouble, Cstring, SpiceInt, Ref{SpiceDouble}, Ref{SpiceDouble}),
          targ, et, ref, obs, state, lt)
    handleerror()
    state, lt[]
end

"""
    spkgps(targ, et, ref, obs)

Compute the geometric position of a target body relative to an observing body.

### Arguments ###

- `targ`: Target body
- `et`: Target epoch
- `ref`: Target reference frame
- `obs`: Observing body

### Output ###

- `pos`: Position of target
- `lt`: Light time

### References ###

- [NAIF Documentation](https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/spkgps_c.html)
"""
function spkgps(targ, et, ref, obs)
    pos = Array{SpiceDouble}(undef, 3)
    lt = Ref{SpiceDouble}()
    ccall((:spkgps_c, libcspice), Cvoid,
          (SpiceInt, SpiceDouble, Cstring, SpiceInt, Ref{SpiceDouble}, Ref{SpiceDouble}),
          targ, et, ref, obs, pos, lt)
    handleerror()
    pos, lt[]
end

"""
    spklef(fname)

Load an ephemeris file for use by the readers. Return that file's handle, to be used by other
SPK routines to refer to the file.

### Arguments ###

- `fname`: Name of the file to be loaded

### Output ###

- `handle`: Loaded file's handle

### References ###

- [NAIF Documentation](https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/spklef_c.html)
"""
function spklef(fname)
    handle = Ref{SpiceInt}()
    ccall((:spklef_c, libcspice), Cvoid, (Cstring, Ref{SpiceInt}), fname, handle)
    handleerror()
    handle[]
end

"""
    spkltc(targ, et, ref, abcorr, stobs)

Return the state (position and velocity) of a target body relative to an observer, optionally
corrected for light time, expressed relative to an inertial reference frame.

### Arguments ###

- `targ`: Target body
- `et`: Observer epoch
- `ref`: Inertial reference frame of output state
- `abcorr`: Aberration correction flag
- `stobs`: State of the observer relative to the SSB

### Output ###

- `starg`: State of target
- `lt`: One way light time between observer and target
- `dlt`: Derivative of light time with respect to time

### References ###

- [NAIF Documentation](https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/spkltc_c.html)
"""
function spkltc(targ, et, ref, abcorr, stobs)
    @checkdims 6 stobs
    starg = Array{SpiceDouble}(undef, 6)
    lt = Ref{SpiceDouble}()
    dlt = Ref{SpiceDouble}()
    ccall((:spkltc_c, libcspice), Cvoid,
          (SpiceInt, SpiceDouble, Cstring, Cstring, Ref{SpiceDouble},
           Ref{SpiceDouble}, Ref{SpiceDouble}, Ref{SpiceDouble}),
          targ, et, ref, abcorr, stobs, starg, lt, dlt)
    handleerror()
    starg, lt[], dlt[]
end

"""
    spkobj!(ids, spk)

Find the set of ID codes of all objects in a specified SPK file.

### Arguments ###

- `ids`: A preallocated set of ID codes of objects in SPK file
- `spk`: Name of the SPK file

### Output ###

Returns the set of id codes.

### References ###

- [NAIF Documentation](https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/spkobj_c.html)
"""
function spkobj!(ids, spk)
    data = ids.data
    GC.@preserve data begin
        ccall((:spkobj_c, libcspice), Cvoid,
              (Cstring, Ref{Cell{SpiceInt}}),
              spk, ids.cell)
    end
    handleerror()
    ids
end

@deprecate spkobj spkobj!

"""
    spkopa(file)

Open an existing SPK file for subsequent write.

### Arguments ###

- `file`: The name of an existing SPK file

### Output ###

Returns a handle attached to the SPK file opened to append.

### References ###

- [NAIF Documentation](https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/spkopa_c.html)
"""
function spkopa(file)
    handle = Ref{SpiceInt}()
    ccall((:spkopa_c, libcspice), Cvoid, (Cstring, Ref{SpiceInt}), file, handle)
    handleerror()
    handle[]
end

"""
    spkopn(name, ifname="", ncomch=0)

Create a new SPK file, returning the handle of the opened file.

### Arguments ###

- `name`: The name of the new SPK file to be created
- `ifname`: The internal filename for the SPK file (default: "")
- `ncomch`: The number of characters to reserve for comments (default: 0)

### Output ###

Returns the handle of the opened SPK file.

### References ###

- [NAIF Documentation](https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/spkopn_c.html)
"""
function spkopn(name, ifname="", ncomch=0)
    handle = Ref{SpiceInt}()
    ccall((:spkopn_c, libcspice), Cvoid,
          (Cstring, Cstring, Cint, Ref{Cint}),
          name, ifname, ncomch, handle)
    handleerror()
    handle[]
end

"""
    spkpds(body, center, frame, typ, first, last)

Perform routine error checks and if all checks pass, pack the descriptor for an SPK segment.

### Arguments ###

- `body`: The NAIF ID code for the body of the segment
- `center`: The center of motion for body
- `frame`: The frame for this segment
- `type`: The type of SPK segment to create
- `first`: The first epoch for which the segment is valid
- `last`: The last  epoch for which the segment is valid

### Output ###

Returns an SPK segment descriptor.

### References ###

- [NAIF Documentation](https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/spkpds_c.html)
"""
function spkpds(body, center, frame, typ, first, last)
    descr = Array{SpiceDouble}(undef, 5)
    ccall((:spkpds_c, libcspice), Cvoid,
          (SpiceInt, SpiceInt, Cstring, SpiceInt, SpiceDouble, SpiceDouble, Ref{SpiceDouble}),
          body, center, frame, typ, first, last, descr)
    handleerror()
    descr
end

"""
    spkpos(targ, et, ref, abcorr, obs)

Return the position of a target body relative to an observing body, optionally corrected for
light time (planetary aberration) and stellar aberration.

### Arguments ###

- `targ`: Target body name
- `et`: Observer epoch
- `ref`: Reference frame of output position vector
- `abcorr`: Aberration correction flag
- `obs`: Observing body name

### Output ###

- `ptarg`: Position of target
- `lt`: One way light time between observer and target

### References ###

- [NAIF Documentation](https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/spkpos_c.html)
"""
function spkpos(targ, et, ref, abcorr, obs)
    starg = Array{SpiceDouble}(undef, 3)
    lt = Ref{SpiceDouble}()
    ccall((:spkpos_c, libcspice), Cvoid,
          (Cstring, SpiceDouble, Cstring, Cstring, Cstring, Ref{SpiceDouble}, Ref{SpiceDouble}),
          targ, et, ref, abcorr, obs, starg, lt)
    handleerror()
    starg, lt[]
end

"""
    spkpvn(handle, descr, et)

For a specified SPK segment and time, return the state (position and velocity) of the segment's
target body relative to its center of motion.

### Arguments ###

- `handle`: File handle
- `descr`: Segment descriptor
- `et`: Evaluation epoch

### Output ###

- `ref`: Segment reference frame ID code
- `state`: Output state vector
- `center`: Center of state

### References ###

- [NAIF Documentation](https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/spkpvn_c.html)
"""
function spkpvn(handle, descr, et)
    @checkdims 5 descr
    ref = Ref{SpiceInt}()
    state = Array{SpiceDouble}(undef, 6)
    center = Ref{SpiceInt}()
    ccall((:spkpvn_c, libcspice), Cvoid,
          (SpiceInt, Ref{SpiceDouble}, SpiceDouble,
           Ref{SpiceInt}, Ref{SpiceDouble}, Ref{SpiceInt}),
          handle, descr, et, ref, state, center)
    handleerror()
    ref[], state, center[]
end

"""
    spksfs(body, et)

Search through loaded SPK files to find the highest-priority segment applicable to the body and
time specified.

### Arguments ###

- `body`: Body ID
- `et`: Ephemeris time

### Output ###

Returns `nothing` if no segment was found or a tuple consisting of:

- `handle`: Handle of file containing the applicable segment
- `descr`: Descriptor of the applicable segment
- `ident`: Identifier of the applicable segment

### References ###

- [NAIF Documentation](https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/spksfs_c.html)
"""
function spksfs(body, et)
    idlen = 41
    handle = Ref{SpiceInt}()
    descr = Array{SpiceDouble}(undef, 5)
    ident = Array{SpiceChar}(undef, idlen)
    found = Ref{SpiceBoolean}()
    ccall((:spksfs_c, libcspice), Cvoid,
          (SpiceInt, SpiceDouble, SpiceInt,
           Ref{SpiceInt}, Ref{SpiceDouble}, Ref{SpiceChar}, Ref{SpiceBoolean}),
          body, et, idlen, handle, descr, ident, found)
    handleerror()
    Bool(found[]) || return nothing
    handle[], descr, chararray_to_string(ident)
end

"""
    spkssb(targ, et, ref)

Return the state (position and velocity) of a target body relative to the solar system barycenter.

### Arguments ###

- `targ`: Target body
- `et`: Target epoch
- `ref`: Target reference frame

### Output ###

Returns the state of target.

### References ###

- [NAIF Documentation](https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/spkssb_c.html)
"""
function spkssb(targ, et, ref)
    starg = Array{SpiceDouble}(undef, 6)
    ccall((:spkssb_c, libcspice), Cvoid,
          (SpiceInt, SpiceDouble, Cstring, Ref{SpiceDouble}),
          targ, et, ref, starg)
    handleerror()
    starg
end

"""
    spksub!(newh, handle, descr, ident, start, stop)

Extract a subset of the data in an SPK segment into a separate segment.

### Arguments ###

- `newh`: Handle of new segment
- `handle`: Handle of source segment
- `descr`: Descriptor of source segment
- `ident`: Identifier of source segment
- `start`: Beginning (initial epoch) of subset
- `stop`: End (final epoch) of subset

### References ###

- [NAIF Documentation](https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/spksub_c.html)
"""
function spksub!(newh, handle, descr, ident, start, stop)
    @checkdims 5 descr
    ccall((:spksub_c, libcspice), Cvoid,
          (SpiceInt, Ref{SpiceDouble}, Cstring, SpiceDouble, SpiceDouble, SpiceInt),
          handle, descr, ident, start, stop, newh)
    handleerror()
end

@deprecate spksub spksub!

"""
    spkuds(descr)

Unpack the contents of an SPK segment descriptor.

### Arguments ###

- `descr`: An SPK segment descriptor

### Output ###

- `body`: The NAIF ID code for the body of the segment
- `center`: The center of motion for body
- `frame`: The ID code for the frame of this segment
- `type`: The type of SPK segment
- `first`: The first epoch for which the segment is valid
- `last`: The last  epoch for which the segment is valid
- `start`: Beginning DAF address of the segment
- `stop`: Ending DAF address of the segment

### References ###

- [NAIF Documentation](https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/spkuds_c.html)
"""
function spkuds(descr)
    @checkdims 5 descr
    body = Ref{SpiceInt}()
    center = Ref{SpiceInt}()
    frame = Ref{SpiceInt}()
    typ = Ref{SpiceInt}()
    first = Ref{SpiceDouble}()
    last = Ref{SpiceDouble}()
    start = Ref{SpiceInt}()
    stop = Ref{SpiceInt}()
    ccall((:spkuds_c, libcspice), Cvoid,
          (Ref{SpiceDouble}, Ref{SpiceInt}, Ref{SpiceInt}, Ref{SpiceInt}, Ref{SpiceInt},
           Ref{SpiceDouble}, Ref{SpiceDouble}, Ref{SpiceInt}, Ref{SpiceInt}),
          descr, body, center, frame, typ, first, last, start, stop)
    handleerror()
    Int(body[]), Int(center[]), Int(frame[]), Int(typ[]),
    first[], last[], Int(start[]), Int(stop[])
end

"""
    spkuef(handle)

Unload an ephemeris file so that it will no longer be searched by the readers.

### Arguments ###

- `handle`: Handle of file to be unloaded

### References ###

- [NAIF Documentation](https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/spkuef_c.html)
"""
function spkuef(handle)
    ccall((:spkuef_c, libcspice), Cvoid, (SpiceInt,), handle)
end

"""
    spkw02(handle, body, center, frame, first, last, segid, intlen, cdata, btime)

Write a type 2 segment to an SPK file.

### Arguments ###

- `handle`: Handle of an SPK file open for writing
- `body`: Body code for ephemeris object
- `center`: Body code for the center of motion of the body
- `frame`: The reference frame of the states
- `first`: First valid time for which states can be computed
- `last`: Last valid time for which states can be computed
- `segid`: Segment identifier
- `intlen`: Length of time covered by logical record
- `cdata`: Array of Chebyshev coefficients
- `btime`: Begin time of first logical record

### References ###

- [NAIF Documentation](https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/spkw02_c.html)
"""
function spkw02(handle, body, center, frame, first, last, segid, intlen, cdata, btime)
    cdata_ = array_to_cmatrix(cdata)
    m, n = size(cdata_)
    polydg = m - 1
    ccall((:spkw02_c, libcspice), Cvoid,
          (SpiceInt, SpiceInt, SpiceInt, Cstring, SpiceDouble, SpiceDouble, Cstring, SpiceDouble,
           SpiceInt, SpiceInt, Ref{SpiceDouble}, SpiceDouble),
          handle, body, center, frame, first, last, segid, intlen,
          n, polydg, cdata_, btime)
    handleerror()
end

"""
    spkw03(handle, body, center, frame, first, last, segid, intlen, cdata, btime)

Write a type 3 segment to an SPK file.

### Arguments ###

- `handle`: Handle of an SPK file open for writing
- `body`: Body code for ephemeris object
- `center`: Body code for the center of motion of the body
- `frame`: The reference frame of the states
- `first`: First valid time for which states can be computed
- `last`: Last valid time for which states can be computed
- `segid`: Segment identifier
- `intlen`: Length of time covered by logical record
- `cdata`: Array of Chebyshev coefficients
- `btime`: Begin time of first logical record

### References ###

- [NAIF Documentation](https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/spkw03_c.html)
"""
function spkw03(handle, body, center, frame, first, last, segid, intlen, cdata, btime)
    cdata_ = array_to_cmatrix(cdata)
    m, n = size(cdata_)
    polydg = m ÷ 6 - 1
    ccall((:spkw03_c, libcspice), Cvoid,
          (SpiceInt, SpiceInt, SpiceInt, Cstring, SpiceDouble, SpiceDouble, Cstring, SpiceDouble,
           SpiceInt, SpiceInt, Ref{SpiceDouble}, SpiceDouble),
          handle, body, center, frame, first, last, segid, intlen,
          n, polydg, cdata_, btime)
    handleerror()
end

"""
    spkw05(handle, body, center, frame, first, last, segid, gm, states, epochs)

Write an SPK segment of type 5 given a time-ordered set of discrete states and epochs,
and the gravitational parameter of a central body.

### Arguments ###

- `handle`: Handle of an SPK file open for writing
- `body`: Body code for ephemeris object
- `center`: Body code for the center of motion of the body
- `frame`: The reference frame of the states
- `first`: First valid time for which states can be computed
- `last`: Last valid time for which states can be computed
- `segid`: Segment identifier
- `gm`: Gravitational parameter of central body
- `states`: States
- `epochs`: Epochs

### References ###

- [NAIF Documentation](https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/spkw05_c.html)
"""
function spkw05(handle, body, center, frame, first, last, segid, gm, states, epochs)
    n = length(states)
    @checkdims n epochs
    states_ = array_to_cmatrix(states, n=6)
    ccall((:spkw05_c, libcspice), Cvoid,
          (SpiceInt, SpiceInt, SpiceInt, Cstring, SpiceDouble, SpiceDouble, Cstring,
           SpiceDouble, SpiceInt, Ref{SpiceDouble}, Ref{SpiceDouble}),
          handle, body, center, frame, first, last, segid,
          gm, n, states_, epochs)
    handleerror()
end

"""
    spkw08(handle, body, center, frame, first, last, segid, degree, states, epoch1, step)

Write a type 8 segment to an SPK file.

### Arguments ###

- `handle`: Handle of an SPK file open for writing
- `body`: Body code for ephemeris object
- `center`: Body code for the center of motion of the body
- `frame`: The reference frame of the states
- `first`: First valid time for which states can be computed
- `last`: Last valid time for which states can be computed
- `segid`: Segment identifier
- `degree`: Degree of interpolating polynomials
- `states`: States
- `epoch1`: Epoch of first state in states array
- `step`: Time step separating epochs of states

### References ###

- [NAIF Documentation](https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/spkw08_c.html)
"""
function spkw08(handle, body, center, frame, first, last, segid, degree, states, epoch1, step)
    n = length(states)
    states_ = array_to_cmatrix(states, n=6)
    ccall((:spkw08_c, libcspice), Cvoid,
          (SpiceInt, SpiceInt, SpiceInt, Cstring, SpiceDouble, SpiceDouble, Cstring,
           SpiceInt, SpiceInt, Ref{SpiceDouble}, SpiceDouble, SpiceDouble),
          handle, body, center, frame, first, last, segid,
          degree, n, states_, epoch1, step)
    handleerror()
end

"""
    spkw09(handle, body, center, frame, first, last, segid, degree, states, epochs)

Write a type 9 segment to an SPK file.

### Arguments ###

- `handle`: Handle of an SPK file open for writing
- `body`: Body code for ephemeris object
- `center`: Body code for the center of motion of the body
- `frame`: The reference frame of the states
- `first`: First valid time for which states can be computed
- `last`: Last valid time for which states can be computed
- `segid`: Segment identifier
- `degree`: Degree of interpolating polynomials
- `states`: States
- `epochs`: Epochs

### References ###

- [NAIF Documentation](https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/spkw09_c.html)
"""
function spkw09(handle, body, center, frame, first, last, segid, degree, states, epochs)
    n = length(states)
    @checkdims n epochs
    states_ = array_to_cmatrix(states, n=6)
    ccall((:spkw09_c, libcspice), Cvoid,
          (SpiceInt, SpiceInt, SpiceInt, Cstring, SpiceDouble, SpiceDouble, Cstring,
           SpiceInt, SpiceInt, Ref{SpiceDouble}, Ref{SpiceDouble}),
          handle, body, center, frame, first, last, segid,
          degree, n, states_, epochs)
    handleerror()
end

"""
    spkw10(handle, body, center, frame, first, last, segid, consts, elems, epochs)

Write a type 10 segment to an SPK file.

### Arguments ###

- `handle`: The handle of a DAF file open for writing
- `body`: The NAIF ID code for the body of the segment
- `center`: The center of motion for body
- `frame`: The reference frame for this segment
- `first`: The first epoch for which the segment is valid
- `last`: The last  epoch for which the segment is valid
- `segid`: The string to use for segment identifier
- `consts`: The array of geophysical constants for the segmen
- `elems`: The collection of "two-line" element sets
- `epochs`: The epochs associated with the element sets

### References ###

- [NAIF Documentation](https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/spkw10_c.html)
"""
function spkw10(handle, body, center, frame, first, last, segid, consts, elems, epochs)
    n = length(elems)
    @checkdims n epochs
    elems_ = array_to_cmatrix(elems, n=10)
    ccall((:spkw10_c, libcspice), Cvoid,
          (SpiceInt, SpiceInt, SpiceInt, Cstring, SpiceDouble, SpiceDouble, Cstring,
           Ref{SpiceDouble}, SpiceInt, Ref{SpiceDouble}, Ref{SpiceDouble}),
          handle, body, center, frame, first, last, segid,
          consts, n, elems_, epochs)
    handleerror()
end

"""
    spkw12(handle, body, center, frame, first, last, segid, degree, states, epoch1, step)

Write a type 12 segment to an SPK file.

### Arguments ###

- `handle`: Handle of an SPK file open for writing
- `body`: Body code for ephemeris object
- `center`: Body code for the center of motion of the body
- `frame`: The reference frame of the states
- `first`: First valid time for which states can be computed
- `last`: Last valid time for which states can be computed
- `segid`: Segment identifier
- `degree`: Degree of interpolating polynomials
- `states`: States
- `epoch1`: Epoch of first state in states array
- `step`: Time step separating epochs of states

### References ###

- [NAIF Documentation](https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/spkw12_c.html)
"""
function spkw12(handle, body, center, frame, first, last, segid, degree, states, epoch1, step)
    n = length(states)
    states_ = array_to_cmatrix(states, n=6)
    ccall((:spkw12_c, libcspice), Cvoid,
          (SpiceInt, SpiceInt, SpiceInt, Cstring, SpiceDouble, SpiceDouble, Cstring,
           SpiceInt, SpiceInt, Ref{SpiceDouble}, SpiceDouble, SpiceDouble),
          handle, body, center, frame, first, last, segid,
          degree, n, states_, epoch1, step)
    handleerror()
end

"""
    spkw13(handle, body, center, frame, first, last, segid, degree, states, epochs)

Write a type 13 segment to an SPK file.

### Arguments ###

- `handle`: Handle of an SPK file open for writing
- `body`: Body code for ephemeris object
- `center`: Body code for the center of motion of the body
- `frame`: The reference frame of the states
- `first`: First valid time for which states can be computed
- `last`: Last valid time for which states can be computed
- `segid`: Segment identifier
- `degree`: Degree of interpolating polynomials
- `states`: States
- `epochs`: Epochs

### References ###

- [NAIF Documentation](https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/spkw13_c.html)
"""
function spkw13(handle, body, center, frame, first, last, segid, degree, states, epochs)
    n = length(states)
    @checkdims n epochs
    states_ = array_to_cmatrix(states, n=6)
    ccall((:spkw13_c, libcspice), Cvoid,
          (SpiceInt, SpiceInt, SpiceInt, Cstring, SpiceDouble, SpiceDouble, Cstring,
           SpiceInt, SpiceInt, Ref{SpiceDouble}, Ref{SpiceDouble}),
          handle, body, center, frame, first, last, segid,
          degree, n, states_, epochs)
    handleerror()
end

"""
    spkw15(handle, body, center, frame, first, last, segid,
           epoch, tp, pa, p, ecc, j2flg, pv, gm, j2, radius)

Write a type 15 segment to an SPK file.

### Arguments ###

- `handle`: Handle of an SPK file open for writing
- `body`: Body code for ephemeris object
- `center`: Body code for the center of motion of the body
- `frame`: The reference frame of the states
- `first`: First valid time for which states can be computed
- `last`: Last valid time for which states can be computed
- `segid`: Segment identifier
- `epoch`: Epoch of the periapse
- `tp`: Trajectory pole vector
- `pa`: Periapsis vector
- `p`: Semi-latus rectum
- `ecc`: Eccentricity
- `j2flg`: J2 processing flag
- `pv`: Central body pole vector
- `gm`: Central body GM
- `j2`: Central body J2
- `radius`: Equatorial radius of central body

### References ###

- [NAIF Documentation](https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/spkw15_c.html)
"""
function spkw15(handle, body, center, frame, first, last, segid, epoch, tp, pa, p, ecc, j2flg, pv,
                gm, j2, radius)
    @checkdims 3 tp pa pv
    ccall((:spkw15_c, libcspice), Cvoid,
          (SpiceInt, SpiceInt, SpiceInt, Cstring, SpiceDouble, SpiceDouble, Cstring,
           SpiceDouble, Ref{SpiceDouble}, Ref{SpiceDouble}, SpiceDouble, SpiceDouble,
           SpiceDouble, Ref{SpiceDouble}, SpiceDouble, SpiceDouble, SpiceDouble),
          handle, body, center, frame, first, last, segid,
          epoch, tp, pa, p, ecc, j2flg, pv, gm, j2, radius)
    handleerror()
end

"""
    spkw17(handle, body, center, frame, first, last, segid, epoch, eqel, rapol, decpol)

Write a type 17 segment to an SPK file.

### Arguments ###

- `handle`: Handle of an SPK file open for writing
- `body`: Body code for ephemeris object
- `center`: Body code for the center of motion of the body
- `frame`: The reference frame of the states
- `first`: First valid time for which states can be computed
- `last`: Last valid time for which states can be computed
- `segid`: Segment identifier
- `epoch`: Epoch of elements in seconds past J2000
- `eqel`: Array of equinoctial elements
- `rapol`: Right Ascension of the pole of the reference plane
- `decpol`: Declination of the pole of the reference plane

### References ###

- [NAIF Documentation](https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/spkw17_c.html)
"""
function spkw17(handle, body, center, frame, first, last, segid, epoch, eqel, rapol, decpol)
    @checkdims 9 eqel
    ccall((:spkw17_c, libcspice), Cvoid,
          (SpiceInt, SpiceInt, SpiceInt, Cstring, SpiceDouble, SpiceDouble, Cstring,
           SpiceDouble, Ref{SpiceDouble}, SpiceDouble, SpiceDouble),
          handle, body, center, frame, first, last, segid,
          epoch, eqel, rapol, decpol)
    handleerror()
end

"""
    spkw18(handle, subtyp, body, center, frame, first, last, segid, degree, packts, epochs)

Write a type 18 segment to an SPK file.

### Arguments ###

- `handle`: Handle of an SPK file open for writing
- `subtyp`: SPK type 18 subtype code, either `:S18TP0` or `:S18TP1`
- `body`: NAIF code for an ephemeris object
- `center`: NAIF code for center of motion of body
- `frame`: Reference frame name
- `first`: Start time of interval covered by segment
- `last`: End time of interval covered by segment
- `segid`: Segment identifier
- `degree`: Degree of interpolating polynomials
- `packts`: Time-ordered array of data packets representing geometric states of body
    - For `:S18TP0`: `[x,  y,  z,  dx/dt,  dy/dt,  dz/dt, vx, vy, vz, dvx/dt, dvy/dt, dvz/dt]`
    - For `:S18TP1`: `[x,  y,  z,  dx/dt,  dy/dt,  dz/dt]`
- `epochs`: Array of epochs corresponding to states.

### References ###

- [NAIF Documentation](https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/spkw18_c.html)
"""
function spkw18(handle, subtyp, body, center, frame, first, last, segid, degree, packts, epochs)
    subtyp = subtyp == :S18TP0 ? 0 : subtyp == :S18TP1 ? 1 : throw(ArgumentError("Unknown `subtype`."))
    n = length(packts)
    @checkdims n epochs
    m = subtyp == :S18TP0 ? 12 : subtyp == :S18TP1 ? 6 : 0
    packts_ = array_to_cmatrix(packts, n=m)
    ccall((:spkw18_c, libcspice), Cvoid,
          (SpiceInt, SpiceInt, SpiceInt, SpiceInt, Cstring, SpiceDouble, SpiceDouble, Cstring,
           SpiceInt, SpiceInt, Ref{SpiceDouble}, Ref{SpiceDouble}),
          handle, subtyp, body, center, frame, first, last, segid, degree, n, packts_, epochs)
    handleerror()
end

"""
    spkw20(handle, body, center, frame, first, last, segid, intlen, n, polydg, cdata, dscale,
           tscale, initjd, initfr)

Write a type 20 segment to an SPK file.

### Arguments ###

- `handle`: Handle of SPK file open for writing
- `body`: NAIF code for ephemeris object
- `center`: NAIF code for the center of motion of the body
- `frame`: Reference frame name
- `first`: Start time of interval covered by segment
- `last`: End time of interval covered by segment
- `segid`: Segment identifier
- `intlen`: Length of time covered by logical record (days)
- `cdata`: Array of Chebyshev coefficients and positions
- `dscale`: Distance scale of data
- `tscale`: Time scale of data
- `initjd`: Integer part of begin time (TDB Julian date) of first record
- `initfr`: Fractional part of begin time (TDB Julian date) of first record

### References ###

- [NAIF Documentation](https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/spkw20_c.html)
"""
function spkw20(handle, body, center, frame, first, last, segid, intlen, cdata, dscale,
                tscale, initjd, initfr)
    n = length(cdata)
    polydg = length(cdata[1]) ÷ 3 - 2
    cdata_ = array_to_cmatrix(cdata)
    ccall((:spkw20_c, libcspice), Cvoid,
          (SpiceInt, SpiceInt, SpiceInt, Cstring, SpiceDouble, SpiceDouble, Cstring,
           SpiceDouble, SpiceInt, SpiceInt, Ref{SpiceDouble},
           SpiceDouble, SpiceDouble, SpiceDouble, SpiceDouble),
          handle, body, center, frame, first, last, segid,
          intlen, n, polydg, cdata_,
          dscale, tscale, initjd, initfr)
    handleerror()
end

"""
    srfc2s(code, bodyid)

Translate a surface ID code, together with a body ID code, to the corresponding surface name.
If no such name exists, return a string representation of the surface ID code.

### Arguments ###

- `code`: Integer surface ID code to translate to a string
- `bodyid`: ID code of body associated with surface

### Output ###

- `srfstr`: String corresponding to surface ID code
- `isname`: Logical flag indicating output is a surface name

### References ###

- [NAIF Documentation](https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/srfc2s_c.html)
"""
function srfc2s(code, bodyid)
    srfstr = Array{SpiceChar}(undef, SPICE_SRF_SFNMLN)
    isname = Ref{SpiceBoolean}()
    ccall((:srfc2s_c, libcspice), Cvoid,
          (SpiceInt, SpiceInt, SpiceInt, Ref{SpiceChar}, Ref{SpiceBoolean}),
          code, bodyid, SPICE_SRF_SFNMLN, srfstr, isname)
    handleerror()
    chararray_to_string(srfstr), Bool(isname[])
end

"""
    srfcss(code, bodstr)

Translate a surface ID code, together with a body string, to the corresponding surface name.
If no such surface name exists, return a string representation of the surface ID code.

### Arguments ###

- `code`: Integer surface ID code to translate to a string
- `bodstr`: Name or ID of body associated with surface

### Output ###

- `srfstr`: String corresponding to surface ID code
- `isname`: Logical flag indicating output is a surface name

### References ###

- [NAIF Documentation](https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/srfcss_c.html)
"""
function srfcss(code, bodstr)
    srfstr = Array{SpiceChar}(undef, SPICE_SRF_SFNMLN)
    isname = Ref{SpiceBoolean}()
    ccall((:srfcss_c, libcspice), Cvoid,
          (SpiceInt, Cstring, SpiceInt, Ref{SpiceChar}, Ref{SpiceBoolean}),
          code, bodstr, SPICE_SRF_SFNMLN, srfstr, isname)
    handleerror()
    chararray_to_string(srfstr), Bool(isname[])
end

"""
    srfnrm(method, target, et, fixref, npts, srfpts)

Map array of surface points on a specified target body to the corresponding unit length outward
surface normal vectors.

The surface of the target body may be represented by a triaxial ellipsoid or by topographic data
provided by DSK files.

### Arguments ###

- `method`: Computation method
- `target`: Name of target body
- `et`: Epoch in TDB seconds past J2000 TDB
- `fixref`: Body-fixed, body-centered target body frame
- `srfpts`: Array of surface points

### Output ###

Returns an array of outward, unit length normal vectors.

### References ###

- [NAIF Documentation](https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/srfnrm_c.html)
"""
function srfnrm(method, target, et, fixref, srfpts)
    npts = length(srfpts)
    srfpts_ = array_to_cmatrix(srfpts, n=3)
    normls = similar(srfpts_)
    ccall((:srfnrm_c, libcspice), Cvoid,
          (Cstring, Cstring, SpiceDouble, Cstring, SpiceInt, Ref{SpiceDouble}, Ref{SpiceDouble}),
          method, target, et, fixref, npts, srfpts_, normls)
    handleerror()
    cmatrix_to_array(normls)
end

"""
    srfrec(body, longitude, latitude)

Convert planetocentric latitude and longitude of a surface point on a specified body to rectangular
coordinates.

### Arguments ###

- `body`: NAIF integer code of an extended body.
- `longitude`: Longitude of point in radians.
- `latitude`: Latitude of point in radians.

### Output ###

Returns the rectangular coordinates of the point.

### References ###

- [NAIF Documentation](https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/srfrec_c.html)
"""
function srfrec(body, longitude, latitude)
    rectan = Array{SpiceDouble}(undef, 3)
    ccall((:srfrec_c, libcspice), Cvoid,
          (SpiceInt, SpiceDouble, SpiceDouble, Ref{SpiceDouble}),
          body, longitude, latitude, rectan)
    handleerror()
    rectan
end

"""
    srfs2c(srfstr, bodstr)

Translate a surface string, together with a body string, to the corresponding surface ID code.
The input strings may contain names or integer ID codes.

### Arguments ###

- `srfstr`: Surface name or ID string
- `bodstr`: Body name or ID string

### Output ###

Returns the surface ID code if it was found or `nothing` otherwise.

### References ###

- [NAIF Documentation](https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/srfs2c_c.html)
"""
function srfs2c(srfstr, bodstr)
    code = Ref{SpiceInt}()
    found = Ref{SpiceBoolean}()
    ccall((:srfs2c_c, libcspice), Cvoid,
          (Cstring, Cstring, Ref{SpiceInt}, Ref{SpiceBoolean}),
          srfstr, bodstr, code, found)
    handleerror()
    Bool(found[]) || return nothing
    Int(code[])
end

"""
    srfscc(srfstr, bodyid)

Translate a surface string, together with a body ID code, to the corresponding surface ID code.
The input surface string may contain a name or an integer ID code.

### Arguments ###

- `srfstr`: Surface name or ID string
- `bodyid`: Body ID code.

### Output ###

Returns the surface ID code if it was found or `nothing` otherwise.

### References ###

- [NAIF Documentation](https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/srfscc_c.html)
"""
function srfscc(srfstr, bodyid)
    code = Ref{SpiceInt}()
    found = Ref{SpiceBoolean}()
    ccall((:srfscc_c, libcspice), Cvoid,
          (Cstring, SpiceInt, Ref{SpiceInt}, Ref{SpiceBoolean}),
          srfstr, bodyid, code, found)
    handleerror()
    Bool(found[]) || return nothing
    Int(code[])
end

@deprecate srfxpt sincpt

"""
    srfxpt

!!! warning "Deprecated"
    Use `sincpt` instead.
"""
srfxpt

"""
    ssize!(cell, size)

Set the size (maximum cardinality) of a cell of any data type.

### Arguments ###

- `cell`: The cell
- `size`: Size (maximum cardinality) of the cell

### Output ###

Returns the updated cell.

### References ###

- [NAIF Documentation](https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/ssize_c.html)
"""
function ssize!(cell::SpiceCell{T}, size) where T
    data = cell.data
    GC.@preserve data begin
        ccall((:ssize_c, libcspice), Cvoid, (SpiceInt, Ref{Cell{T}}), size, cell.cell)
    end
    handleerror()
    cell
end

@deprecate ssize ssize!

"""
    stelab(pobj, vobs)

Correct the apparent position of an object for stellar aberration.

### Arguments ###

- `pobj`: Position of an object with respect to the observer
- `vobs`: Velocity of the observer with respect to the Solar System barycenter

### Output ###

Returns the apparent position of the object with respect to the observer, corrected for stellar aberration.

### References ###

- [NAIF Documentation](https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/stelab_c.html)
"""
function stelab(pobj, vobs)
    @checkdims 3 pobj vobs
    appobj = Array{SpiceDouble}(undef, 3)
    ccall((:stelab_c, libcspice), Cvoid,
          (Ref{SpiceDouble}, Ref{SpiceDouble}, Ref{SpiceDouble}),
          pobj, vobs, appobj)
    handleerror()
    appobj
end

"""
    stpool(item, nth, contin, lenout=1024)

Retrieve the nth string from the kernel pool variable, where the string may be continued across
several components of the kernel pool variable.

### Arguments ###

- `item`: Name of the kernel pool variable
- `nth`: Index of the full string to retrieve
- `contin`: Character sequence used to indicate continuation
- `lenout`: Available space in output string (default: 1024)

### Output ###

Returns the full string concatenated across continuations if the kernel variable was found or
`nothing` otherwise.

### References ###

- [NAIF Documentation](https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/stpool_c.html)
"""
function stpool(item, nth, contin, lenout=1024)
    string = Array{SpiceChar}(undef, lenout)
    size = Ref{SpiceInt}()
    found = Ref{SpiceBoolean}()
    ccall((:stpool_c, libcspice), Cvoid,
          (Cstring, SpiceInt, Cstring, SpiceInt, Ref{SpiceChar}, Ref{SpiceInt}, Ref{SpiceBoolean}),
          item, nth - 1, contin, lenout, string, size, found)
    handleerror()
    chararray_to_string(string)
end

"""
    str2et(str)

Convert a string representing an epoch to a double precision value representing the number of TDB
seconds past the J2000 epoch corresponding to the input epoch.

### Arguments ###

- `str`: A string representing an epoch

### Output ###

Returns the equivalent value in seconds past J2000, TDB.

### References ###

- [NAIF Documentation](https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/str2et_c.html)
"""
function str2et(str)
    et = Ref{SpiceDouble}()
    ccall((:str2et_c, libcspice), Cvoid, (Cstring, Ref{SpiceDouble}), str, et)
    handleerror()
    et[]
end

"""
    subpnt(method, target, et, fixref, obsrvr, abcorr)

Compute the rectangular coordinates of the sub-observer point on
a target body at a specified epoch, optionally corrected for
light time and stellar aberration.

### Arguments ###

- `method`: Computation method
- `target`: Name of target body
- `et`: Epoch in ephemeris seconds past J2000 TDB
- `fixref`: Body-fixed, body-centered target body frame
- `abcorr`: Aberration correction
- `obsrvr`: Name of observing body

### Output ###

- `spoint`: Sub-solar point on the target body
- `trgepc`: Sub-solar point epoch
- `srfvec`: Vector from observer to sub-solar point

### References ###

- [NAIF Documentation](https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/subpnt_c.html)
"""
function subpnt(method, target, et, fixref, abcorr, obsrvr)
    spoint = Array{SpiceDouble}(undef, 3)
    trgepc = Ref{SpiceDouble}()
    srfvec = Array{SpiceDouble}(undef, 3)
    ccall((:subpnt_c, libcspice), Cvoid,
          (Cstring, Cstring, SpiceDouble, Cstring, Cstring, Cstring,
           Ref{SpiceDouble}, Ref{SpiceDouble}, Ref{SpiceDouble}),
          method, target, et, fixref, abcorr, obsrvr, spoint, trgepc, srfvec)
    handleerror()
    spoint, trgepc[], srfvec
end

@deprecate subpt subpnt

"""
    subpt

!!! warning "Deprecated"
    Use `subpnt` instead.
"""
subpt

@deprecate subpt_pl02 subpnt

"""
    subpt_pl02

!!! warning "Deprecated"
    Use `subpnt` instead.
"""
subpt_pl02

"""
    subslr(method, target, et, fixref, abcorr, obsrvr)

Compute the rectangular coordinates of the sub-solar point on
a target body at a specified epoch, optionally corrected for
light time and stellar aberration.

### Arguments ###

- `method`: Computation method
- `target`: Name of target body
- `et`: Epoch in ephemeris seconds past J2000 TDB
- `fixref`: Body-fixed, body-centered target body frame
- `abcorr`: Aberration correction
- `obsrvr`: Name of observing body

### Output ###

- `spoint`: Sub-solar point on the target body
- `trgepc`: Sub-solar point epoch
- `srfvec`: Vector from observer to sub-solar point

### References ###

- [NAIF Documentation](https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/subslr_c.html)
"""
function subslr(method, target, et, fixref, abcorr, obsrvr)
    spoint = Array{SpiceDouble}(undef, 3)
    trgepc = Ref{SpiceDouble}()
    srfvec = Array{SpiceDouble}(undef, 3)
    ccall((:subslr_c, libcspice), Cvoid,
          (Cstring, Cstring, SpiceDouble, Cstring, Cstring, Cstring,
           Ref{SpiceDouble}, Ref{SpiceDouble}, Ref{SpiceDouble}),
          method, target, et, fixref, abcorr, obsrvr, spoint, trgepc, srfvec)
    handleerror()
    spoint, trgepc[], srfvec
end

@deprecate subsol subslr

"""
    subsol

!!! warning "Deprecated"
    Use `subslr` instead.
"""
subsol

@deprecate subsol_pl02 subslr

"""
    subsol_pl02

!!! warning "Deprecated"
    Use `subslr` instead.
"""
subsol_pl02

function _sumad(array)
    n = length(array)
    ccall((:sumad_c, libcspice), SpiceDouble, (Ref{SpiceDouble}, SpiceInt), array, n)
end

@deprecate sumad sum

"""
    sumad(array)

!!! warning "Deprecated"
    Use `sum(array)` instead.
"""
sumad

function _sumai(array)
    n = length(array)
    array_ = SpiceInt.(array)
    ccall((:sumai_c, libcspice), SpiceInt, (Ref{SpiceInt}, SpiceInt), array_, n)
end

@deprecate sumai sum

"""
    sumai(array)

!!! warning "Deprecated"
    Use `sum(array)` instead.
"""
sumai

"""
    surfnm(a, b, c, point)

Computes the outward-pointing, unit normal vector from a point on the surface of an ellipsoid.

### Arguments ###

- `a`: Length of the ellisoid semi-axis along the x-axis
- `b`: Length of the ellisoid semi-axis along the y-axis
- `c`: Length of the ellisoid semi-axis along the z-axis
- `point`: Body-fixed coordinates of a point on the ellipsoid

### Output ###

Return the outward pointing unit normal to ellipsoid at point

### References ###

- [NAIF Documentation](https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/surfnm_c.html)
"""
function surfnm(a, b, c, point)
    @checkdims 3 point
    normal = Array{SpiceDouble}(undef, 3)
    ccall((:surfnm_c, libcspice), Cvoid,
          (SpiceDouble, SpiceDouble, SpiceDouble, Ref{SpiceDouble}, Ref{SpiceDouble}),
          a, b, c, point, normal)
    handleerror()
    normal
end

"""
    surfpt(positn, u, a, b, c)

Determine the intersection of a line-of-sight vector with the surface of an ellipsoid.

### Arguments ###

- `positn`: Position of the observer in body-fixed frame
- `u`: Vector from the observer in some direction
- `a`: Length of the ellipsoid semi-axis along the x-axis
- `b`: Length of the ellipsoid semi-axis along the y-axis
- `c`: Length of the ellipsoid semi-axis along the z-axis

### Output ###

Returns the point on the ellipsoid pointed to by u or `nothing` if none was found.

### References ###

- [NAIF Documentation](https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/surfpt_c.html)
"""
function surfpt(positn, u, a, b, c)
    @checkdims 3 positn u
    point = Array{SpiceDouble}(undef, 3)
    found = Ref{SpiceBoolean}()
    ccall((:surfpt_c, libcspice), Cvoid,
          (Ref{SpiceDouble}, Ref{SpiceDouble}, SpiceDouble, SpiceDouble, SpiceDouble,
           Ref{SpiceDouble}, Ref{SpiceBoolean}),
          positn, u, a, b, c, point, found)
    handleerror()
    Bool(found[]) || return nothing
    point
end

"""
    surfpv(stvrtx, stdir, a, b, c)

Find the state (position and velocity) of the surface intercept defined by a specified ray,
ray velocity, and ellipsoid.

### Arguments ###

- `stvrtx`: State of ray's vertex
- `stdir`: State of ray's direction vector
- `a`: Length of ellipsoid semi-axis along the x-axis
- `b`: Length of ellipsoid semi-axis along the y-axis
- `c`: Length of ellipsoid semi-axis along the z-axis

### Output ###

Return the state of surface intercept or `nothing` if none was found.

### References ###

- [NAIF Documentation](https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/surfpv_c.html)
"""
function surfpv(stvrtx, stdir, a, b, c)
    @checkdims 6 stvrtx stdir
    stx = Array{SpiceDouble}(undef, 6)
    found = Ref{SpiceBoolean}()
    ccall((:surfpv_c, libcspice), Cvoid,
          (Ref{SpiceDouble}, Ref{SpiceDouble}, SpiceDouble, SpiceDouble, SpiceDouble,
           Ref{SpiceDouble}, Ref{SpiceBoolean}),
          stvrtx, stdir, a, b, c, stx, found)
    handleerror()
    Bool(found[]) || return nothing
    stx
end

"""
    swpool(agent, names)

Add a name to the list of agents to notify whenever a member of a list of kernel variables is updated.

### Arguments ###

- `agent`: The name of an agent to be notified after updates
- `names`: Variable names whose update causes the notice

### References ###

- [NAIF Documentation](https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/swpool_c.html)
"""
function swpool(agent, names)
    names_, m, n = chararray(names)
    ccall((:swpool_c, libcspice), Cvoid, (Cstring, SpiceInt, SpiceInt, Ref{SpiceChar}),
          agent, m, n, names_)
    handleerror()
end

"""
    sxform(from, to, et)

Return the state transformation matrix from one frame to another at a specified epoch.

### Arguments ###

- `from`: Name of the frame to transform from
- `to`: Name of the frame to transform to
- `et`: Epoch of the state transformation matrix

### Output ###

Returns the state transformation matrix.

### References ###

- [NAIF Documentation](https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/sxform_c.html)
"""
function sxform(from, to, et)
    rot = Array{SpiceDouble}(undef, 6, 6)
    ccall((:sxform_c, libcspice), Cvoid,
          (Cstring, Cstring, SpiceDouble, Ref{SpiceDouble}),
          from, to, et, rot)
    handleerror()
    permutedims(rot)
end

"""
    szpool(name)

Return the kernel pool size limitations.

### Arguments ###

- `name`: Name of the parameter to be returned

### Output ###

Returns the value of the parameter specified by `name` or `nothing` if none was found.

### References ###

- [NAIF Documentation](https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/szpool_c.html)
"""
function szpool(name)
    n = Ref{SpiceInt}()
    found = Ref{SpiceBoolean}()
    ccall((:szpool_c, libcspice), Cvoid,
          (Cstring, Ref{SpiceInt}, Ref{SpiceBoolean}),
          name, n, found)
    Bool(found[]) || return nothing
    Int(n[])
end


text:
module  TestHeterozygosity

using PopGen
using Test

cats = @nancycats;
testarray = cats.genodata.genotype[1:10]

@testset "Hardy Weinberg" begin
    @test PopGen._chisqlocus(testarray) == (16.691358024691358, 12, 0.1615808310222504)
    tmp = hwetest(cats)
    @test tmp isa DataFrames.DataFrame
    @test size(tmp) == (9,4)
    tmp = hwetest(cats, correction = "bh")
    @test size(tmp) == (9,5)
    tmp = hwetest(cats, by = "population", correction = "bh")
    @test size(tmp) == (153,6)
end

end #module

ext: jl


text:
# This file is part of Maxima.jl. It is licensed under the MIT license

using Maxima
using Test

# Basic server and setup test

# Conversion and evaluation test
@test m"expand((1+x)^2)" == m"1 + 2*x + x^2"
@test mcall(:(exp(im*pi))) == -1
@test integrate(:(sin(x)), :x) == :(-cos(x))
@test MExpr(:(100x)) == m"100 * x"
@test MExpr(:(-im)) == m"-%i"

# Julia special constant replacement
@test mcall(:(ℯ^(im * π))) == -1
@test mcall(:(e^(im * π))) != -1  # We no longer support 'e' as euler number in Julia >= 1.0

# Calculus tests
@test integrate(:(sin(x)), :x) == :(-cos(x))
@test integrate("exp(-x^2)", "x", "minf", "inf") == "sqrt(%pi)"
@test risch(:(1/x), :x) == :(log(x))
@test diff(:(log(x)), "x") == :(1/x)
@test diff(:(log(x)), :x, 2) == :(-1 / x ^ 2)
@test limit(m"sin(x)/x", :x, 0) == m"1"
@test limit(:(1/x), :x, :a) == :(1 / a)
@test limit(:(1/x), :x, :a, :plus) == :(1/a)

try
    limit(:(1/x), :x, :a, "lalala")
catch err
    @test typeof(err) == ErrorException
end

@test sum(:(1 / k^2), :k, 1, Inf) == :(π ^ 2 / 6)
@test sum(m"1 / k ^ 2", :k, 1, "inf") == m"%pi^2/6"
@test taylor(m"sin(x)", :x, 0, 3) == m"x - x^3/6"
@test taylor(:(sin(x)), :x, 0, 3) == :(x - x^3/6)

# Simplification tests
@test ratsimp(m"a + b/c") == m"(a * c + b) / c"
@test ratsimp(:(exp(log(x)))) == :x
@test radcan(m"sqrt(x/y)") == m"sqrt(x)/sqrt(y)"
@test factor(:(x^2 + 2x + 1)) == :((x + 1)^2)
@test gfactor(:(x^2 + 2*im*x - 1)) == :((x + im)^2)
@test expand(MExpr(:((a + b)^2))) == m"a^2 + 2*a*b + b^2"
@test logcontract(m"log(x) - log(y)") == m"log(x/y)"
@test logexpand(m"log(x/y)") == m"log(x) - log(y)"
@test trigsimp(m"sin(x)^2 + cos(x)^2") |> parse == 1
@test trigrat(MExpr(:(exp(im*x) + exp(-im*x)))) == MExpr(:(2 * cos(x)))
@test rectform(:(R*ℯ^(im*theta))) == :(im * R * sin(theta) + R * cos(theta))
@test polarform(m"a + %i*b") == m"sqrt(a^2 + b^2)*exp(%i * atan2(b, a))"
@test realpart(m"a + %i*b") |> parse == :a
@test imagpart(m"a + %i*b") |> parse == :b
@test demoivre(m"exp(a + %i * b)") == m"exp(a) * (cos(b) + %i * sin(b))"
@test exponentialize(m"sin(x)") == m"-%i*(exp(%i * x) - exp(-%i * x))/2"
@test float(m"1/3*x") == m"0.3333333333333333*x"
@test subst(:b, :a, :(a^2 + b^2)) == :(2 * b ^ 2)
@test trigexpand(:(sin(2x) + cos(3y))) == :(-3 * cos(y) * sin(y) ^ 2 + cos(y) ^ 3 + 2 * cos(x) * sin(x))
@test trigreduce(m"-sin(x)^2+3*cos(x)^2+x") == m"cos(2*x)/2+3*(cos(2*x)/2+1/2)+x-1/2"
@test expand(:((a + b)^2)) == :(b ^ 2 + 2 * a * b + a ^ 2)
@test expand("(a + b)^3") == "b^3+3*a*b^2+3*a^2*b+a^3"
@test makefact(m"gamma(x)") == m"(x-1)!"
@test makegamma(m"n! * m!") == m"gamma(m+1)*gamma(n+1)"

# Error handling

try
    mcall(m"1/0")
catch err
    @test typeof(err) == Maxima.MaximaError
end

try
    mcall(m"1 + ")
catch err
    @test typeof(err) == Maxima.MaximaSyntaxError
end


text:
##===----------------------------------------------------------------------===##
##                                      VML.JL                                ##
##                                                                            ##
##===----------------------------------------------------------------------===##
##                                                                            ##
##  This file provides access to VML and handles checking for the existence   ##
##  of the VML library during import and checks for the available             ##
##  vector instruction sets.                                                  ##
##                                                                            ##
##===----------------------------------------------------------------------===##
module VML
import Vectorize: functions, addfunction

# Cross-version compatibility
if VERSION < v"0.5.0-dev" # Julia v0.4
    readstring(cmd) = readall(cmd)
    OS = OS_NAME
else
    OS = Sys.KERNEL
end

# Library dependency for VML
const global librt = Libdl.find_library(["libmkl_rt"], ["/opt/intel/mkl/lib"])

if librt == ""
    error("Unable to load librt")
end
Libdl.dlopen(librt)

# ======= VML FUNCTION ACCURACY CONTROL ======= #
const VML_LA               =  0x00000001     # Low Accuracy
const VML_HA               =  0x00000002     # High Accuracy
const VML_EP               =  0x00000003     # Enhanced Performance

# ======= VML ERROR HANDLING CONTROL ======= #
const VML_ERRMODE_IGNORE   =  0x00000100     # ignore errors
const VML_ERRMODE_ERRNO    =  0x00000200     # errno variable is set on error
const VML_ERRMODE_STDERR   =  0x00000400     # error description text is written to stderr
const VML_ERRMODE_EXCEPT   =  0x00000800     # exception is raised on error
const VML_ERRMODE_CALLBACK =  0x00001000     # user's error handler is called
# errno variable is set, exceptions are raised, and user's error handler is called on error
const VML_ERRMODE_DEFAULT  = VML_ERRMODE_ERRNO | VML_ERRMODE_CALLBACK | VML_ERRMODE_EXCEPT

# ======= FTZ & DAZ MODE CONTROL ======= #
const VML_FTZDAZ_ON        =  0x00280000     # faster denormal value processing
const VML_FTZDAZ_OFF       =  0x00140000     # accurate denormal value processing

"""
This function sets the default values for the VME library on import,
allowing for the precompilation of the rest of the package.
"""
function __init__()

    # Open librt
    Libdl.dlopen(librt)

    # Set default mode
    VML.setmode(VML.VML_HA | VML.VML_ERRMODE_DEFAULT | VML.VML_FTZDAZ_ON)
end

"""
Sets accuracy, error, and FTZDAZ modes for all VML functions. This is automatically
called in init() but can also be called to change the modes during runtime.
"""
function setmode(mode)
    oldmode = ccall(("vmlSetMode", librt),  Cuint,
                    (Cuint,),
                    mode)
    return oldmode
end

"""
Returns the accuracy, error, and FTZDAZ modes for all VML functions". This is automatically
called in init() but can also be called to change the modes during runtime".
"""
function getmode()
    status = ccall(("vmlGetMode", librt),  Cuint,
                   (), )
    return status
end

# Basic operations on two args
for (T, prefix) in [(Float32,  "s"), (Float64, "d"),  (Complex{Float32}, "c"),  (Complex{Float64}, "z")]
    for (f, fvml, name) in [(:add, :Add, "addition"), (:mul, :Mul, "multiplcation"),
                      (:sub, :Sub, "subtraction"), (:div, :Div, "division"), (:pow, :Pow, "power")]
        f! = Symbol("$(f)!")
        addfunction(functions, (f, (T,T)), "Vectorize.VML.$f")
        addfunction(functions, (f!, (T,T,T)), "Vectorize.VML.$(f!)")
        @eval begin
            @doc """
            `$($f)(X::Vector{$($T)}, Y::Vector{$($T)})`
            Implements element-wise **$($name)** over two **Vector{$($T)}**. Allocates
            memory to store result. *Returns:* **Vector{$($T)}**
            """ ->
            function ($f)(X::Vector{$T}, Y::Vector{$T})
                out = similar(X)
                return $(f!)(out, X, Y)
            end
            @doc """
            `$($f!)(result::Vector{$($T)}, X::Vector{$($T)}, Y::Vector{$($T)})`
            Implements element-wise **$($name)** over two **Vector{$($T)}** and overwrites
            the result vector with computed value. *Returns:* **Vector{$($T)}** `result`
            """ ->
            function ($f!)(out::Vector{$T}, X::Vector{$T}, Y::Vector{$T})
                ccall($(string("v", prefix, fvml), librt),  Void,
                      (Cint, Ptr{$T}, Ptr{$T},  Ptr{$T}),
                      length(out), X, Y,  out)
                return out
            end
        end
    end
end

# Real only returning real - two args
for (T, prefix) in [(Float32, "s"),  (Float64, "d")]
    for (f, fvml, name) in [(:hypot, :Hypot, "hypotenuse"), (:atan2, :Atan2, "atan2")]
        f! = Symbol("$(f)!")
        addfunction(functions, (f, (T,T)), "Vectorize.VML.$f")
        addfunction(functions, (f!, (T,T,T)), "Vectorize.VML.$(f!)")
        @eval begin
            @doc """
            `$($f)(X::Vector{$($T)}, Y::Vector{$($T)})`
            Implements element-wise **$($name)** over two **Vector{$($T)}**. Allocates
            memory to store result. *Returns:* **Vector{$($T)}**
            """ ->
            function ($f)(X::Vector{$T}, Y::Vector{$T})
                out = similar(X)
                return $(f!)(out, X, Y)
            end
            @doc """
            `$($f!)(result::Vector{$($T)}, X::Vector{$($T)}, Y::Vector{$($T)})`
            Implements element-wise **$($name)** over two **Vector{$($T)}** and overwrites
            the result vector with computed value. *Returns:* **Vector{$($T)}** `result`
            """ ->
            function ($f!)(out::Vector{$T}, X::Vector{$T}, Y::Vector{$T})
                ccall($(string("v", prefix, fvml), librt),  Void,
                      (Cint, Ptr{$T}, Ptr{$T},  Ptr{$T}),
                      length(out), X, Y,  out)
                return out
            end
        end
    end
end

# Complex only returning complex - two arg
for (T, prefix) in [(Complex{Float32}, "c"),  (Complex{Float64}, "z")]
    for (f, fvml, name) in [(:mulbyconj, :MulByConj, "multiply-by-conjugate")]
        f! = Symbol("$(f)!")
        addfunction(functions, (f, (T,T)), "Vectorize.VML.$f")
        addfunction(functions, (f!, (T,T,T)), "Vectorize.VML.$(f!)")
        @eval begin
            @doc """
            `$($f)(X::Vector{$($T)}, Y::Vector{$($T)})`
            Implements element-wise **$($name)** over two **Vector{$($T)}**. Allocates
            memory to store result. *Returns:* **Vector{$($T)}**
            """ ->
            function ($f)(X::Vector{$T}, Y::Vector{$T})
                out = similar(X)
                return $(f!)(out, X, Y)
            end
            @doc """
            `$($f!)(result::Vector{$($T)}, X::Vector{$($T)}, Y::Vector{$($T)})`
            Implements element-wise **$($name)** over two **Vector{$($T)}** and overwrites
            the result vector with computed value. *Returns:* **Vector{$($T)}** `result`
            """ ->
            function ($f!)(out::Vector{$T}, X::Vector{$T}, Y::Vector{$T})
                ccall($(string("v", prefix, fvml), librt),  Void,
                      (Cint, Ptr{$T}, Ptr{$T},  Ptr{$T}),
                      length(out), X, Y,  out)
                return out
            end
        end
    end
end

# Basic operations on one arg
for (T, prefix) in [(Float32,  "s"), (Float64, "d"),  (Complex{Float32}, "c"),  (Complex{Float64}, "z")]
    for (f, fvml) in [(:sqrt, :Sqrt), (:exp, :Exp),  (:acos, :Acos), (:asin, :Asin),
                      (:acosh, :Acosh), (:asinh, :Asinh), (:log,  :Ln),
                     (:atan, :Atan), (:cos, :Cos), (:sin, :Sin),
                      (:tan, :Tan), (:cosh, :Cosh), (:sinh, :Sinh), (:tanh, :Tanh), (:log10, :Log10)]
        f! = Symbol("$(f)!")
        name = string(f)
        addfunction(functions, (f, (T,)), "Vectorize.VML.$f")
        addfunction(functions, (f!, (T,T)), "Vectorize.VML.$(f!)")
        @eval begin
            @doc """
            `$($f)(X::Vector{$($T)})`
            Implements element-wise **$($name)** over a **Vector{$($T)}**. Allocates
            memory to store result. *Returns:* **Vector{$($T)}**
            """ ->
            function ($f)(X::Vector{$T})
                out = similar(X)
                return $(f!)(out, X)
            end
            @doc """
            `$($f!)(result::Vector{$($T)}, X::Vector{$($T)})`
            Implements element-wise **$($name)** over a **Vector{$($T)}** and overwrites
            the result vector with computed value. *Returns:* **Vector{$($T)}** `result`
            """ ->
            function ($f!)(out::Vector{$T}, X::Vector{$T})
                ccall($(string("v", prefix, fvml), librt),  Void,
                      (Cint, Ptr{$T}, Ptr{$T}),
                      length(out), X, out)
                return out
            end
        end
    end
end

# Real only basic operations on one arg:
for (T, prefix) in [(Float32,  "s"), (Float64, "d")]
    for (f, fvml) in [(:inv, :Inv), (:invsqrt, :InvSqrt),  (:cbrt,  :Cbrt),
                      (:invcbrt, :InvCbrt), (:pow2o3, :Pow2o3), (:pow3o2, :Pow3o2),
                      (:erf, :Erf),  (:ceil, :Ceil),
                      (:erfc, :Erfc), (:cdfnorm, :CdfNorm),  (:erfinv, :ErfInv),
                      (:erfcinv,  :ErfcInv),  (:cdfnorminv, :CdfNormInv), (:lgamma, :LGamma),
                      (:gamma, :TGamma), (:floor, :Floor), (:trunc, :Trunc),
                      (:round, :Round), (:frac,  :Frac), (:abs, :Abs), (:sqr, :Sqr)]
        f! = Symbol("$(f)!")
        name = string(f)
        addfunction(functions, (f, (T,)), "Vectorize.VML.$f")
        addfunction(functions, (f!, (T,T)), "Vectorize.VML.$(f!)")
        @eval begin
            @doc """
            `$($f)(X::Vector{$($T)})`
            Implements element-wise **$($name)** over a **Vector{$($T)}**. Allocates
            memory to store result. *Returns:* **Vector{$($T)}**
            """ ->
            function ($f)(X::Vector{$T})
                out = similar(X)
                return $(f!)(out, X)
            end
            @doc """
            `$($f!)(result::Vector{$($T)}, X::Vector{$($T)})`
            Implements element-wise **$($name)** over a **Vector{$($T)}** and overwrites
            the result vector with computed value. *Returns:* **Vector{$($T)}** `result`
            """ ->
            function ($f!)(out::Vector{$T}, X::Vector{$T})
                ccall($(string("v", prefix, fvml), librt),  Void,
                      (Cint, Ptr{$T}, Ptr{$T}),
                      length(out), X, out)
                return out
            end
        end
    end
end

# Operations on complex returning complex - one arg
for (T, prefix) in [(Complex{Float32}, "c"),  (Complex{Float64}, "z")]
    for (f, fvml, name) in [(:conj,  :Conj, "conjugation")]
        f! = Symbol("$(f)!")
        addfunction(functions, (f, (T,)), "Vectorize.VML.$f")
        addfunction(functions, (f!, (T,T)), "Vectorize.VML.$(f!)")
        @eval begin
             @doc """
            `$($f)(X::Vector{$($T)})`
            Implements element-wise **$($name)** over a **Vector{$($T)}**. Allocates
            memory to store result. *Returns:* **Vector{$($T)}**
            """ ->
            function ($f)(X::Vector{$T})
                out = similar(X)
                return $(f!)(out, X)
            end
            @doc """
            `$($f!)(result::Vector{$($T)}, X::Vector{$($T)})`
            Implements element-wise **$($name)** over a **Vector{$($T)}** and overwrites
            the result vector with computed value. *Returns:* **Vector{$($T)}** `result`
            """ ->
            function ($f!)(out::Vector{$T}, X::Vector{$T})
                ccall($(string("v", prefix, fvml), librt),  Void,
                      (Cint, Ptr{$T}, Ptr{$T}),
                      length(out), X, out)
                return out
            end
        end
    end
end

# Operations on complex returning real - one arg
for (T, prefix) in [(Complex{Float32}, "c"),  (Complex{Float64}, "z")]
    for (f, fvml, name) in [(:abs, :Abs, "absolute-value"),  (:angle,  :Arg, "complex-argument") ]
        f! = Symbol("$(f)!")
        addfunction(functions, (f, (T,)), "Vectorize.VML.$f")
        addfunction(functions, (f!, (real(T),T)), "Vectorize.VML.$(f!)")
        @eval begin
            @doc """
            `$($f)(X::Vector{$($T)})`
            Calculates the **$($name)** element-wise over a **Vector{$($T)}**. Allocates
            memory to store result. *Returns:* **Vector{$($T)}**
            """ ->
            function ($f)(X::Vector{$T})
                out = Array(real($T), length(X))
                return $(f!)(out, X)
            end
            @doc """
            `$($f!)(result::Vector{$($T)}, X::Vector{$($T)})`
            Calculates the **$($name)** element-wise over a **Vector{$($T)}** and overwrites
            the result vector with computed value. *Returns:* **Vector{$($T)}** `result`
            """ ->
            function ($f!)(out::Vector{real($T)}, X::Vector{$T})
                ccall($(string("v", prefix, fvml), librt),  Void,
                      (Cint, Ptr{$T}, Ptr{real($T)}),
                      length(out), X, out)
                return out
            end
        end
    end
end

end # End Module


text:
function get_standardized_matrix(mat::AbstractArray{<:Real,2})
    m = mat
    Threads.@threads for col in 1:size(m)[2]
        summ = 0.0f0
        rows = size(m)[1]
        for row in 1:rows
            summ += m[row, col]
        end
        mean = summ/rows
        sums = 0.0f0
        for row in 1:rows
            sums += (m[row,col] - mean)^2
        end
        std = sqrt(sums/rows)
        for row in 1:rows
            m[row,col] = (m[row,col]-mean)/std
        end
    end
    return m
end

function get_standardized_matrix_gpu(m::AbstractArray{<:Real,2})
    return (m .- mean(m, dims=1)) ./ std(m, corrected=false, dims=1)
end

using Statistics
using Test

mat = rand(1000, 1000)

correct_std_mat = get_standardized_matrix(mat)

new_std_mat = get_standardized_matrix_gpu(mat)

compare_res = isapprox.(correct_std_mat, new_std_mat, atol=1e-5)

@test sum(compare_res) == prod(size(mat))


text:
using Devectorize
include("incompressible_basis.jl");

  function ns_gradgrad(
    u::Array{Complex128},
    p::Array{Int64},
    order::Int64,
    quadx::Array{Float64},
    quady::Array{Float64},
    quadz::Array{Float64},
    quadw::Array{Float64})

    n=length(u);
    gradgrad=Array(Complex128,(n,));

      function outergrad(i::Int64,u,p,order,quadx,quady,quadz,quadw)
        dim=3;
        n=length(u);
        nq=length(quadw);
        gradgradq=Array(Complex128,(nq,));
       #Loop through quadrature nodes.
        for iq=1:nq
            (i1,i2,i3)=ind2sub(size(quadw),iq);
            gradv=evaluate_curl_basis_gradient(order,p[i],quadx[i1],quady[i2],quadz[i3]);
            gradu=zeros(Complex128,(dim,dim));
            for j=1:n
                tgradu=evaluate_curl_basis_gradient(order,p[j],quadx[i1],quady[i2],quadz[i3]);
                @devec gradu=gradu+u[j].*tgradu;
            end
            grad_dot_grad::Complex128 = 0.0;
            for d1 = 1 : dim
                for d2 = 1 : dim
                    grad_dot_grad=grad_dot_grad+gradu[d1,d2]*conj(gradv[d1,d2]);
                end
            end
            gradgradq[iq]=grad_dot_grad;
        end
        return sum(gradgradq.*quadw[:]);
    end

   return Array{Complex128}(pmap(i->outergrad(i,u,p,order,quadx,quady,quadz,quadw),1:n));
end

  function ns_convection(
    u::Array{Complex128},
    p::Array{Int64},
    order::Int64,
    quadx::Array{Float64},
    quady::Array{Float64},
    quadz::Array{Float64},
    quadw::Array{Float64})

    dim=3;
    n=length(u);
    nq=length(quadw);

    conv=Array(Complex128,(n,));

    function outerconv(i::Int64,u,p,order,quadx,quady,quadz,quadw)
        n=length(u);
        nq=length(quadw);
        dim=3;
        convq=Array(Complex128,(nq,));
        #Loop through "test" degrees of freedom.
            #Loop through quadrature nodes.
            for iq=1:nq
                #Compute test   function.
                (i1,i2,i3)=ind2sub(size(quadw),iq);
                (vx,vy,vz) =evaluate_curl_basis(order,p[i],quadx[i1],quady[i2],quadz[i3]);
                gradu=zeros(Complex128,(dim,dim));
                ux=0.0*im;
                uy=0.0*im;
                uz=0.0*im;
                for j =1:n
                    #Compute gradient of solution.
                    tgradu=evaluate_curl_basis_gradient(order,p[j],quadx[i1],quady[i2],quadz[i3]);
                    @devec gradu=gradu+u[j].*tgradu;
                    (tux,tuy,tuz) =evaluate_curl_basis(order,p[j],quadx[i1],quady[i2],quadz[i3]);
                    ux=ux+u[j]*tux;
                    uy=uy+u[j]*tuy;
                    uz=uz+u[j]*tuz;
                end
                udivu=ux*gradu[:,1]+uy*gradu[:,2]+uz*gradu[:,3];
                convq[iq]=udivu[1]*conj(vx)+udivu[2]*conj(vy)+udivu[3]*conj(vz);
            end
            return sum(convq.*quadw[:]);
        end
    return Array{Complex128}(pmap(i->outerconv(i,u,p,order,quadx,quady,quadz,quadw),1:n));
end

  function ns_eval(
    RTR, #Cholesky factor of mass matrix
    u::Array{Complex128},
    p::Array{Int64},
    order::Int64,
    quadx::Array{Float64},
    quady::Array{Float64},
    quadz::Array{Float64},
    quadw::Array{Float64})

    conv=ns_convection(u,p,order,quadx,quady,quadz,quadw);
    gradgrad=ns_gradgrad(u,p,order,quadx,quady,quadz,quadw);
    return RTR\(gradgrad-conv);
end

function ns_eval(RTR,u::Array{Complex128},V,GV,W)

    dim=3;
    n=length(u);
    gg=zeros(u);
    co=zeros(u);
    #Compute grad-grad term.
    for i=1:dim
      for j=1:dim
          gg[:]=gg[:]+(GV[i,j]')*(W*(GV[i,j]*u));
      end
    end

    #Compute convection term.
    for i=1:dim
      for j = 1:dim
        co[:]=co[:]+V[i]'*(W*((V[j]*u).*(GV[i,j]*u)))
      end
    end

    return RTR\(-gg-co);
end

max_stars_repo_name: ReidAtcheson/incns

max_issues_repo_name: ReidAtcheson/incns

max_forks_repo_name: ReidAtcheson/incns