#pragma once

// Ported from de.varylab.discreteconformal.util.DiscreteEllipticUtility (Java).
// Only the pure-math subset (no HDS required).

#include <complex>
#include <cmath>

namespace conformallab {

// Move tau into the fundamental domain of the modular group SL(2,Z):
//   |Re(tau)| <= 0.5,  Im(tau) >= 0,  Re(tau) >= 0,  |tau| >= 1
//
// Algorithm: iteratively apply
//   1. T-shift:   Re > 0.5 or Re < 0  →  Re -= sign(Re)
//   2. Im-flip:   Im < 0              →  Im = -Im
//   3. Re-flip:   Re < 0              →  Re = -Re
//   4. S-invert:  |tau| < 1           →  tau = 1/tau
//
// Corresponds to Java DiscreteEllipticUtility.normalizeModulus(Complex).
inline std::complex<double> normalizeModulus(std::complex<double> tau) {
    int maxIter = 100;
    while (--maxIter > 0) {
        double re = tau.real();
        double im = tau.imag();
        // exit when all conditions satisfied
        if (std::abs(re) <= 0.5 && im >= 0.0 && re >= 0.0 && std::abs(tau) >= 1.0)
            break;

        if (std::abs(re) > 0.5)
            re -= (re > 0.0 ? 1.0 : -1.0);   // signum shift
        if (im < 0.0)
            im = -im;
        if (re < 0.0)
            re = -re;
        tau = std::complex<double>(re, im);
        if (std::abs(tau) < 1.0)
            tau = 1.0 / tau;                  // S-transformation: invert
    }
    return tau;
}

} // namespace conformallab
