#define PJ_LIB_

#include <errno.h>
#include <math.h>

#include "proj.h"
#include "proj_internal.h"

namespace { // anonymous namespace
struct pj_opaque {
    double phi1;
    double fxa;
    double fxb;
    int mode;
};
} // anonymous namespace

PROJ_HEAD(rpoly, "Rectangular Polyconic")
"\n\tConic, Sph, no inv\n\tlat_ts=";

#define EPS 1e-9

static PJ_XY rpoly_s_forward(PJ_LP lp, PJ *P) { /* Spheroidal, forward */
    PJ_XY xy = {0.0, 0.0};
    struct pj_opaque *Q = static_cast<struct pj_opaque *>(P->opaque);
    double fa;

    if (Q->mode)
        fa = tan(lp.lam * Q->fxb) * Q->fxa;
    else
        fa = 0.5 * lp.lam;
    if (fabs(lp.phi) < EPS) {
        xy.x = fa + fa;
        xy.y = -P->phi0;
    } else {
        xy.y = 1. / tan(lp.phi);
        fa = 2. * atan(fa * sin(lp.phi));
        xy.x = sin(fa) * xy.y;
        xy.y = lp.phi - P->phi0 + (1. - cos(fa)) * xy.y;
    }
    return xy;
}

PJ *PROJECTION(rpoly) {
    struct pj_opaque *Q =
        static_cast<struct pj_opaque *>(calloc(1, sizeof(struct pj_opaque)));
    if (nullptr == Q)
        return pj_default_destructor(P, PROJ_ERR_OTHER /*ENOMEM*/);
    P->opaque = Q;

    Q->phi1 = fabs(pj_param(P->ctx, P->params, "rlat_ts").f);
    Q->mode = Q->phi1 > EPS;
    if (Q->mode) {
        Q->fxb = 0.5 * sin(Q->phi1);
        Q->fxa = 0.5 / Q->fxb;
    }
    P->es = 0.;
    P->fwd = rpoly_s_forward;

    return P;
}
