package ballistics.orbitalPoints

import ballistics.orbitalPoints.timeStepper.AbstractStepper
import ballistics.orbitalPoints.timeStepper.TLEStepper
import ballistics.types.BallisticsError
import ballistics.types.EarthType
import ballistics.types.OrbitalPoint
import ballistics.utils.math.equations.AbstractEquationCalculator
import ballistics.utils.math.equations.EquationCalculatorSpan
import kotlin.math.abs

internal class OrbitalPointsTLE(str1: String, str2: String, earthType: EarthType) :
    AbstractOrbPointsCalculator(earthType) {
    val stepper = TLEStepper(str1, str2, earthType)
    private var vit = 0

    override fun calculate(
        tbegin: Double,
        tend: Double,
    ): BallisticsError {
        points.clear()
        revolutions.clear()

        val equationCalculator: AbstractEquationCalculator = EquationCalculatorSpan()
        equationCalculator.delta = 0.001

        vit = stepper.satellite.orbit.orbitNum
        var t = stepper.baseEpoch.toDouble()
        var p = stepper.calculate(t)
        var pn: OrbitalPoint
        if (abs(p.r.z) < 0.00001 && p.t >= tbegin) {
            addRevolution(p.t)
        }

        try {
            while (t <= tend) {
                t = t + step
                pn = stepper.calculate(t)
                if (p.r.z < 0 && pn.r.z >= 0) {
                    ++vit
                    val tvuz = equationCalculator.calculate(t - step, t + step, this::equation)
                    tvuz?.let {
                        if (tvuz >= tbegin) {
                            addRevolution(it)
                        }
                    }
                }
                if (t >= tbegin) {
                    pn.vit = vit
                    points.add(pn)
                }
                p = pn
            }
        }catch (ex : Exception){
            return BallisticsError.STEPPER_ERROR
        }

        return BallisticsError.OK
    }

    override fun getStepper(): AbstractStepper {
        return stepper
    }

    override fun fastStep(t: Double): OrbitalPoint {
        val op = stepper.calculate(t)
        op.vit = vit
        return op
    }
}
