#include "geotiff.h"
#include "geotiff_def.h"
#include "logger.h"

namespace geotiff
{
    bool try_write_geotiff(TIFF *tif, proj::projection_t *proj)
    {
        bool debug = true;

        // Bunch of checks
        if (proj->type == proj::ProjType_Invalid)
        {
            if (debug)
                printf("Projection is invalid!\n");
            return true;
        }

        if (!(proj->type == proj::ProjType_Equirectangular ||
              proj->type == proj::ProjType_Stereographic ||
              proj->type == proj::ProjType_UniversalTransverseMercator ||
              proj->type == proj::ProjType_WebMerc))
        {
            if (debug)
                printf("Unsupported projection!\n");
            return true;
        }

        // Register the tags we need
        char tag_pixelScale[] = "ModelPixelScaleTag";
        // char tag_geoTransform[] = "GeoTransformationMatrix";
        char tag_tiepoint[] = "ModelTiepointTag";
        char tag_geoKeyDirectory[] = "GeoKeyDirectoryTag";
        char tag_geoKeyDoubles[] = "GeoKeysDoubles";
        // char tag_ASCIIParams[] = "GeoASCIIParams";

        static const TIFFFieldInfo xtiffFieldInfo[] = {
            //
            {GEOTIFFTAG_ModelPixelScaleTag, -1, -1, TIFF_DOUBLE, FIELD_CUSTOM, true, true, tag_pixelScale},
            //  {TIFFTAG_GEOTRANSMATRIX, -1, -1, TIFF_DOUBLE, FIELD_CUSTOM, TRUE, TRUE, tag_geoTransform},
            {GEOTIFFTAG_ModelTiepointTag, -1, -1, TIFF_DOUBLE, FIELD_CUSTOM, true, true, tag_tiepoint},
            {GEOTIFFTAG_GeoKeyDirectoryTag, -1, -1, TIFF_SHORT, FIELD_CUSTOM, true, true, tag_geoKeyDirectory},
            {GEOTIFFTAG_GeoKeysDoubles, -1, -1, TIFF_DOUBLE, FIELD_CUSTOM, true, true, tag_geoKeyDoubles},
            //  {TIFFTAG_GEOASCIIPARAMS, -1, -1, TIFF_ASCII, FIELD_CUSTOM, TRUE, FALSE, tag_ASCIIParams}
            //
        };
#define N(a) (sizeof(a) / sizeof(a[0]))
        TIFFMergeFieldInfo(tif, xtiffFieldInfo, N(xtiffFieldInfo));

        // Start by writing tiepoints
        double tiepoints[6] = {0.0, 0.0, 0.0, proj->proj_offset_x, proj->proj_offset_y, 0.0};
        TIFFSetField(tif, GEOTIFFTAG_ModelTiepointTag, 6, &tiepoints);

        // Then write pixel scales
        double pixelscales[3] = {proj->proj_scalar_x, -proj->proj_scalar_y, 0.0};
        TIFFSetField(tif, GEOTIFFTAG_ModelPixelScaleTag, 3, &pixelscales);

        // Finally, the GeoKeys
        std::vector<uint16_t> geoskeys(4);
        geoskeys[0] = 1; // KeyDirectoryVersion
        geoskeys[1] = 1; // KeyRevision
        geoskeys[2] = 0; // MinorRevision
        geoskeys[3] = 0; // NumberOfKeys

        std::vector<double> doublekeys;
        int keysn = 0;
        {
            // Model Type
            geoskeys.push_back(GTModelTypeGeoKey);
            geoskeys.push_back(0);
            geoskeys.push_back(1);
            if (proj->type == proj::ProjType_Equirectangular)
                geoskeys.push_back(ModelTypeGeographic);
            else
                geoskeys.push_back(ModelTypeProjected);
            keysn++;

            // Projected model type
            if (proj->type == proj::ProjType_UniversalTransverseMercator)
            { // UTM Mercator
                int value = 0;

                printf("ZONE IS %d\n", proj->params.zone);
                if (proj->params.south)
                    value = PCS_WGS84_UTM_zone_1S - 1 + proj->params.zone;
                else
                    value = PCS_WGS84_UTM_zone_1N - 1 + proj->params.zone;

                geoskeys.push_back(ProjectedCSTypeGeoKey);
                geoskeys.push_back(0);
                geoskeys.push_back(1);
                geoskeys.push_back(value);
                keysn++;
            }
            else if (proj->type == proj::ProjType_Stereographic)
            { // Stereographic
                geoskeys.push_back(ProjCoordTransGeoKey);
                geoskeys.push_back(0);
                geoskeys.push_back(1);
                geoskeys.push_back(CT_Stereographic);
                keysn++;
            }
            else if (proj->type == proj::ProjType_WebMerc)
            {
                geoskeys.push_back(ProjectedCSTypeGeoKey);
                geoskeys.push_back(0);
                geoskeys.push_back(1);
                geoskeys.push_back(3857);
                keysn++;
            }

            // Longitude/Latitude of origin
            if (proj->lam0 != 0)
            { // Longitude is not 0
                doublekeys.push_back(proj->lam0 * RAD2DEG);
                geoskeys.push_back(ProjCenterLongGeoKey);
                geoskeys.push_back(GEOTIFFTAG_GeoKeysDoubles);
                geoskeys.push_back(1);
                geoskeys.push_back(doublekeys.size() - 1);
                keysn++;
            }
            if (proj->phi0 != 0)
            { // Latitude is not 0
                doublekeys.push_back(proj->phi0 * RAD2DEG);
                geoskeys.push_back(ProjCenterLatGeoKey);
                geoskeys.push_back(GEOTIFFTAG_GeoKeysDoubles);
                geoskeys.push_back(1);
                geoskeys.push_back(doublekeys.size() - 1);
                keysn++;
            }

            // Angular unit. Always degree for us
            if (proj->type == proj::ProjType_Equirectangular ||
                proj->lam0 != 0 ||
                proj->phi0 != 0)
            {
                geoskeys.push_back(GeogAngularUnitsGeoKey);
                geoskeys.push_back(0);
                geoskeys.push_back(1);
                geoskeys.push_back(Angular_Degree);
                keysn++;
            }

            // Ellipsoid model. Always WGS84 for us!
            {
                geoskeys.push_back(GeographicTypeGeoKey);
                geoskeys.push_back(0);
                geoskeys.push_back(1);
                geoskeys.push_back(GCS_WGS_84);
                keysn++;
            }
        }

        geoskeys[3] = keysn;

        uint16_t *geokeys_ptr = geoskeys.data();
        TIFFSetField(tif, GEOTIFFTAG_GeoKeyDirectoryTag, geoskeys.size(), geokeys_ptr);

        if (doublekeys.size() > 0)
        {
            double *doublekeys_ptr = doublekeys.data();
            TIFFSetField(tif, GEOTIFFTAG_GeoKeysDoubles, doublekeys.size(), doublekeys_ptr);
        }

        return false;
    }
}
