package basic

import (
	"math"

	. "b612.me/astro/tools"
)

/*
 * 坐标变换，黄道转赤道
 */
func LoToRa(jde, lo, bo float64) float64 {
	ra := math.Atan2(Sin(lo)*Cos(TrueObliquity(jde))-Tan(bo)*Sin(TrueObliquity(jde)), Cos(lo))
	ra = ra * 180 / math.Pi
	if ra < 0 {
		ra += 360
	}
	return ra
}

func BoToDec(jde, lo, bo float64) float64 {
	dec := ArcSin(Sin(bo)*Cos(TrueObliquity(jde)) + Cos(bo)*Sin(TrueObliquity(jde))*Sin(lo))
	return dec
}

func LoBoToRaDec(jde, lo, bo float64) (float64, float64) {
	dec := ArcSin(Sin(bo)*Cos(TrueObliquity(jde)) + Cos(bo)*Sin(TrueObliquity(jde))*Sin(lo))
	ra := math.Atan2(Sin(lo)*Cos(TrueObliquity(jde))-Tan(bo)*Sin(TrueObliquity(jde)), Cos(lo))
	ra = ra * 180 / math.Pi
	if ra < 0 {
		ra += 360
	}
	return ra, dec
}

func RaDecToLoBo(jde, ra, dec float64) (float64, float64) {
	//tan(λ) = (sin(α)*cos(ε) + tan(δ)*sin(ε)) / cos(α)
	//sin(β)=sin(δ)*cos(ε)-cos(δ)*sin(ε)*sin(α)
	eps := TrueObliquity(jde)
	sinBo := Sin(dec)*Cos(eps) - Cos(dec)*Sin(eps)*Sin(ra)
	lo := math.Atan2((Sin(ra)*Cos(eps) + Tan(dec)*Sin(eps)), Cos(ra))
	lo = Limit360(lo * 180 / math.Pi)
	return lo, ArcSin(sinBo)
}

func RaToLo(jde, ra, dec float64) float64 {
	//tan(λ) = (sin(α)*cos(ε) + tan(δ)*sin(ε)) / cos(α)
	//sin(β)=sin(δ)*cos(ε)-cos(δ)*sin(ε)*sin(α)
	eps := TrueObliquity(jde)
	lo := math.Atan2((Sin(ra)*Cos(eps) + Tan(dec)*Sin(eps)), Cos(ra))
	lo = Limit360(lo * 180 / math.Pi)
	return lo
}

func DecToBo(jde, ra, dec float64) float64 {
	//tan(λ) = (sin(α)*cos(ε) + tan(δ)*sin(ε)) / cos(α)
	//sin(β)=sin(δ)*cos(ε)-cos(δ)*sin(ε)*sin(α)
	eps := TrueObliquity(jde)
	sinBo := Sin(dec)*Cos(eps) - Cos(dec)*Sin(eps)*Sin(ra)
	return ArcSin(sinBo)
}

/*
 * 地心坐标转站心坐标，参数分别为，地心赤经赤纬 纬度经度，jde，离地心位置au
 */
func pcosi(lat, h float64) float64 {
	b := 6356.755
	a := 6378.14
	u := ArcTan(b / a * Tan(lat))
	//psin=b/a*Sin(u)+h/6378140*Sin(lat);
	pcos := Cos(u) + h/6378140.0*Cos(lat)
	return pcos
}
func psini(lat, h float64) float64 {
	b := 6356.755
	a := 6378.14
	u := ArcTan(b / a * Tan(lat))
	psin := b/a*Sin(u) + h/6378140*Sin(lat)
	//pcos=Cos(u)+h/6378140*Cos(lat);
	return psin
}

func TopocentricRaDec(ra, dec, lat, lon, jd, au, h float64) (float64, float64) {
	sinpi := Sin(0.0024427777777) / au
	pcosi := pcosi(lat, h)
	psini := psini(lat, h)
	tH := Limit360(ApparentSiderealTime(jd)*15 + lon - ra)
	nra := math.Atan2(-pcosi*sinpi*Sin(tH), (Cos(dec)-pcosi*sinpi*Cos(tH))) * 180 / math.Pi

	ndec := math.Atan2((Sin(dec)-psini*sinpi)*Cos(nra), (Cos(dec)-pcosi*sinpi*Cos(tH))) * 180 / math.Pi
	return ra + nra, ndec
}

func TopocentricRa(ra, dec, lat, lon, jd, au, h float64) float64 { //jd为格林尼治标准时
	topocentricRA, _ := TopocentricRaDec(ra, dec, lat, lon, jd, au, h)
	return topocentricRA
}
func TopocentricDec(ra, dec, lat, lon, jd, au, h float64) float64 { //jd为格林尼治标准时
	_, topocentricDec := TopocentricRaDec(ra, dec, lat, lon, jd, au, h)
	return topocentricDec
}

func TopocentricLo(lo, bo, lat, lon, jd, au, h float64) float64 { //jd为格林尼治标准时
	c := pcosi(lat, h)
	s := psini(lat, h)
	sinpi := Sin(0.0024427777777) / au
	ra := LoToRa(jd, lo, bo)
	tH := Limit360(ApparentSiderealTime(jd)*15 + lon - ra)
	n := Cos(lo)*Cos(bo) - c*sinpi*Cos(tH)
	nlo := math.Atan2(Sin(lo)*Cos(bo)-sinpi*(s*Sin(TrueObliquity(jd))+c*Cos(TrueObliquity(jd))*Sin(tH)), n) * 180 / math.Pi
	return nlo
}

func TopocentricBo(lo, bo, lat, lon, jd, au, h float64) float64 { //jd为格林尼治标准时
	c := pcosi(lat, h)
	s := psini(lat, h)
	sinpi := Sin(0.0024427777777) / au
	ra := LoToRa(jd, lo, bo)
	tH := Limit360(ApparentSiderealTime(jd)*15 + lon - ra)
	n := Cos(lo)*Cos(bo) - c*sinpi*Cos(tH)
	nlo := math.Atan2(Sin(lo)*Cos(bo)-sinpi*(s*Sin(TrueObliquity(jd))+c*Cos(TrueObliquity(jd))*Sin(tH)), n) * 180 / math.Pi
	nbo := math.Atan2(Cos(nlo)*(Sin(bo)-sinpi*(s*Cos(TrueObliquity(jd))-c*Sin(TrueObliquity(jd))*Sin(tH))), n) * 180 / math.Pi
	return nbo
}

func GXCLo(lo, bo, jd float64) float64 { //光行差修正
	k := 20.49552
	sunlo := SunTrueLo(jd)
	e := Earthe(jd)
	epi := EarthPI(jd)
	tmp := (-k*Cos(sunlo-lo) + e*k*Cos(epi-lo)) / Cos(bo)
	return tmp
}

func GXCBo(lo, bo, jd float64) float64 {
	k := 20.49552
	sunlo := SunTrueLo(jd)
	e := Earthe(jd)
	epi := EarthPI(jd)
	tmp := -k * Sin(bo) * (Sin(sunlo-lo) - e*Sin(epi-lo))
	return tmp
}
