use nalgebra as na;
use super::ierstable::IERSTable;
use crate::astrotime::{AstroTime, Scale};
use crate::frametransform::{qrot_ycoord, qrot_zcoord};
type Quat = na::UnitQuaternion<f64>;
type Delaunay = na::SVector<f64, 14>;
use std::f64::consts::PI;
use once_cell::sync::OnceCell;
fn table5a_singleton() -> &'static IERSTable {
static INSTANCE: OnceCell<IERSTable> = OnceCell::new();
INSTANCE.get_or_init(|| IERSTable::from_file("tab5.2a.txt").unwrap())
}
fn table5b_singleton() -> &'static IERSTable {
static INSTANCE: OnceCell<IERSTable> = OnceCell::new();
INSTANCE.get_or_init(|| IERSTable::from_file("tab5.2b.txt").unwrap())
}
fn table5d_singleton() -> &'static IERSTable {
static INSTANCE: OnceCell<IERSTable> = OnceCell::new();
INSTANCE.get_or_init(|| IERSTable::from_file("tab5.2d.txt").unwrap())
}
pub fn qcirs2gcrs_dxdy(tm: &AstroTime, dxdy: Option<(f64, f64)>) -> Quat {
let t_tt = (tm.to_mjd(Scale::TT) - 51544.5) / 36525.0;
const ASEC2RAD: f64 = PI / 180.0 / 3600.0;
let mut delaunay = Delaunay::zeros();
delaunay[0] = ASEC2RAD
* (3600.0 * 134.96340251
+ t_tt * (1717915923.2178 + t_tt * (31.8792 + t_tt * (0.051635 + t_tt * -0.00024470))));
delaunay[1] = ASEC2RAD
* (3600.0 * 357.52910918
+ t_tt * (129596581.0481 + t_tt * (-0.5532 + t_tt * (0.000136 + t_tt * -0.00001149))));
delaunay[2] = ASEC2RAD
* (3600.0 * 93.27209062
+ t_tt
* (1739527262.8478 + t_tt * (-12.7512 + t_tt * (-0.001037 + t_tt * 0.00000417))));
delaunay[3] = ASEC2RAD
* (3600.0 * 297.85019547
+ t_tt
* (1602961601.2090 + t_tt * (-6.37006 + t_tt * (0.006593 + t_tt * -0.00003169))));
delaunay[4] = ASEC2RAD
* (3600.0 * 125.04455501
+ t_tt * (-6962890.5431 + t_tt * (7.4722 + t_tt * (0.007702 + t_tt * -0.00005939))));
delaunay[5] = 4.402608842 + 2608.7903141574 * t_tt;
delaunay[6] = 3.176146697 + 1021.3285546211 * t_tt;
delaunay[7] = 1.753470314 + 628.3075849991 * t_tt;
delaunay[8] = 6.203480913 + 334.0612426700 * t_tt;
delaunay[9] = 0.599546497 + 52.9690962641 * t_tt;
delaunay[10] = 0.874016757 + 21.3299104960 * t_tt;
delaunay[11] = 5.481293872 + 7.4781598567 * t_tt;
delaunay[12] = 5.311886287 + 3.8133035638 * t_tt;
delaunay[13] = t_tt * (0.02438175 + t_tt * 0.00000538691);
let x0 = -0.016617
+ t_tt
* (2004.191898
+ t_tt
* (-0.4297829
+ t_tt * (-0.19861834 + t_tt * (0.000007578 + t_tt * 0.0000059285))));
let y0 = -0.006951
+ t_tt
* (-0.025896
+ t_tt
* (-22.4072747
+ t_tt * (0.00190059 + t_tt * (0.001112526 + t_tt * 0.0000001358))));
let s0 = 94.0
+ t_tt * (3808.65 + t_tt * (-122.68 + t_tt * (-72574.11 + t_tt * (27.98 + t_tt * 15.62))));
let xsums = table5a_singleton().compute(t_tt, &delaunay);
let ysums = table5b_singleton().compute(t_tt, &delaunay);
let ssums = table5d_singleton().compute(t_tt, &delaunay);
let mut x = (x0 + xsums * 1.0e-6) * ASEC2RAD;
let mut y = (y0 + ysums * 1.0e-6) * ASEC2RAD;
if dxdy.is_some() {
let (dx, dy) = dxdy.unwrap();
x += dx * 1e-3 * ASEC2RAD;
y += dy * 1e-3 * ASEC2RAD;
}
let s = (s0 + ssums) * 1.0e-6 * ASEC2RAD - x * y / 2.0;
let e = f64::atan2(y, x);
let d = f64::asin(f64::sqrt(x * x + y * y));
qrot_zcoord(-e) * qrot_ycoord(-d) * qrot_zcoord(e + s)
}
pub fn qcirs2gcrs(tm: &AstroTime) -> Quat {
let dxdy: Option<(f64, f64)> = match crate::earth_orientation_params::get(&tm) {
None => None,
Some(v) => Some((v[4], v[5])),
};
qcirs2gcrs_dxdy(tm, dxdy)
}