-- pg_orrery 0.7.0 -> 0.8.0 migration
--
-- Adds orbital_elements type for comets/asteroids, MPC MPCORB.DAT parser,
-- and small_body_observe()/small_body_heliocentric() observation functions.

-- ============================================================
-- orbital_elements type
-- ============================================================

CREATE TYPE orbital_elements;

CREATE FUNCTION orbital_elements_in(cstring) RETURNS orbital_elements
    AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;

CREATE FUNCTION orbital_elements_out(orbital_elements) RETURNS cstring
    AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;

CREATE FUNCTION orbital_elements_recv(internal) RETURNS orbital_elements
    AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;

CREATE FUNCTION orbital_elements_send(orbital_elements) RETURNS bytea
    AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;

CREATE TYPE orbital_elements (
    INPUT = orbital_elements_in,
    OUTPUT = orbital_elements_out,
    RECEIVE = orbital_elements_recv,
    SEND = orbital_elements_send,
    INTERNALLENGTH = 72,
    ALIGNMENT = double,
    STORAGE = plain
);

COMMENT ON TYPE orbital_elements IS
    'Classical Keplerian orbital elements for comets and asteroids (epoch, q, e, inc, omega, Omega, tp, H, G). 72 bytes, fixed-size.';


-- ============================================================
-- Accessor functions
-- ============================================================

CREATE FUNCTION oe_epoch(orbital_elements) RETURNS float8
    AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
COMMENT ON FUNCTION oe_epoch(orbital_elements) IS 'Osculation epoch (Julian date)';

CREATE FUNCTION oe_perihelion(orbital_elements) RETURNS float8
    AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
COMMENT ON FUNCTION oe_perihelion(orbital_elements) IS 'Perihelion distance q (AU)';

CREATE FUNCTION oe_eccentricity(orbital_elements) RETURNS float8
    AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
COMMENT ON FUNCTION oe_eccentricity(orbital_elements) IS 'Eccentricity';

CREATE FUNCTION oe_inclination(orbital_elements) RETURNS float8
    AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
COMMENT ON FUNCTION oe_inclination(orbital_elements) IS 'Inclination (degrees)';

CREATE FUNCTION oe_arg_perihelion(orbital_elements) RETURNS float8
    AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
COMMENT ON FUNCTION oe_arg_perihelion(orbital_elements) IS 'Argument of perihelion (degrees)';

CREATE FUNCTION oe_raan(orbital_elements) RETURNS float8
    AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
COMMENT ON FUNCTION oe_raan(orbital_elements) IS 'Longitude of ascending node (degrees)';

CREATE FUNCTION oe_tp(orbital_elements) RETURNS float8
    AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
COMMENT ON FUNCTION oe_tp(orbital_elements) IS 'Time of perihelion passage (Julian date)';

CREATE FUNCTION oe_h_mag(orbital_elements) RETURNS float8
    AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
COMMENT ON FUNCTION oe_h_mag(orbital_elements) IS 'Absolute magnitude H (NaN if unknown)';

CREATE FUNCTION oe_g_slope(orbital_elements) RETURNS float8
    AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
COMMENT ON FUNCTION oe_g_slope(orbital_elements) IS 'Slope parameter G (NaN if unknown)';

CREATE FUNCTION oe_semi_major_axis(orbital_elements) RETURNS float8
    AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
COMMENT ON FUNCTION oe_semi_major_axis(orbital_elements) IS 'Semi-major axis a = q/(1-e) in AU. NULL for parabolic/hyperbolic orbits (e >= 1).';

CREATE FUNCTION oe_period_years(orbital_elements) RETURNS float8
    AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
COMMENT ON FUNCTION oe_period_years(orbital_elements) IS 'Orbital period in years = a^1.5 (Kepler third law). NULL for parabolic/hyperbolic orbits (e >= 1).';


-- ============================================================
-- MPC MPCORB.DAT parser
-- ============================================================

CREATE FUNCTION oe_from_mpc(text) RETURNS orbital_elements
    AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
COMMENT ON FUNCTION oe_from_mpc(text) IS
    'Parse one MPCORB.DAT fixed-width line into orbital_elements. Converts MPC packed epoch, computes perihelion distance and tp from (a, e, M).';


-- ============================================================
-- Observation functions
-- ============================================================

CREATE FUNCTION small_body_heliocentric(orbital_elements, timestamptz) RETURNS heliocentric
    AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
COMMENT ON FUNCTION small_body_heliocentric(orbital_elements, timestamptz) IS
    'Heliocentric ecliptic J2000 position of a comet/asteroid from its orbital elements at a given time.';

CREATE FUNCTION small_body_observe(orbital_elements, observer, timestamptz) RETURNS topocentric
    AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
COMMENT ON FUNCTION small_body_observe(orbital_elements, observer, timestamptz) IS
    'Observe a comet/asteroid from orbital elements. Auto-fetches Earth via VSOP87. Returns topocentric az/el with geocentric range in km.';
