#include "Geodetics/GeodeticTransform.h"

#include <string> // 如果不在gdal库之前包含此头文件则gdal库会出现编译错误。
#include <gdal/ogr_spatialref.h>
#include <gdal/ogrsf_frmts.h>
#include <gdal/gdal_alg.h>


namespace F1911::Geodetics
{
    const char* const WGS84_WKT(
        "GEOGCS[\"Geographic Coordinate System\",DATUM[\"D_WGS84\",\
SPHEROID[\"WGS84\",6378137,298.257223560493]],PRIMEM[\"Greenwich\",0],\
UNIT[\"Degree\",0.017453292519943295]]");

    const char* const XIAN80_WKT(
        "PROJCS[\"UTM_Zone_51_Northern_Hemisphere\",GEOGCS[\"GCS_XIAN 1980\",\
DATUM[\"D_XIAN 1980\",SPHEROID[\"Xian_1980\",6378140,298.2569978029111]],\
PRIMEM[\"Greenwich\",0],UNIT[\"Degree\",0.017453292519943295]],\
PROJECTION[\"Transverse_Mercator\"],PARAMETER[\"latitude_of_origin\",0],\
PARAMETER[\"central_meridian\",123],PARAMETER[\"scale_factor\",0.9996],\
PARAMETER[\"false_easting\",500000],PARAMETER[\"false_northing\",0],UNIT[\"Meter\",1]]");

    class GeodeticTransformInternal final
    {
    public:
        GeodeticTransformInternal()
        {
            OGRRegisterAll();

            wgs84Reference = OGRSpatialReference(WGS84_WKT);
            xianReference = OGRSpatialReference(XIAN80_WKT);

            localToGeodetic = OGRCreateCoordinateTransformation(&xianReference, &wgs84Reference);
            geodeticToLocal = OGRCreateCoordinateTransformation(&wgs84Reference, &xianReference);
        }

        ~GeodeticTransformInternal()
        {
            OGRCoordinateTransformation::DestroyCT(geodeticToLocal);
            OGRCoordinateTransformation::DestroyCT(localToGeodetic);

            OGRCleanupAll();
        }

        OGRSpatialReference xianReference;
        OGRSpatialReference wgs84Reference;

        OGRCoordinateTransformation* geodeticToLocal = nullptr;
        OGRCoordinateTransformation* localToGeodetic = nullptr;
    };

    GeodeticTransform::GeodeticTransform()
    {
        _i = new GeodeticTransformInternal();
    }

    GeodeticTransform::~GeodeticTransform()
    {
        delete _i;
        _i = nullptr;
    }

    bool GeodeticTransform::localToGeodetic(
        double& longitude, double& latitude, double& altitude, double east, double north, double up) const
    {
        longitude = east - eastOffset;
        latitude = north - northOffset;
        altitude = up - upOffset;
        return _i->localToGeodetic->Transform(1, &longitude, &latitude, &altitude);
    }

    bool GeodeticTransform::geodeticToLocal(
        double& east, double& north, double& up, double longitude, double latitude, double altitude) const
    {
        east = longitude;
        north = latitude;
        up = altitude;
        auto ret = _i->geodeticToLocal->Transform(1, &east, &north, &up);
        east += eastOffset;
        north += northOffset;
        up += upOffset;
        return ret;
    }
}
