/* \file
 *
 * Contains the test cases for the Datum class
 *
 * Copyright (c) 2007,2008,2009 MBARI
 * MBARI Proprietary Information.  All Rights Reserved
 *
 */

#ifndef _DATUM_TEST_H_
#define _DATUM_TEST_H_

#include "utils/Datum.h"

#include <cxxtest/TestSuite.h>

const double UTMFUDGE = 10.0;
const double LATLONFUDGE = 0.01;

// Test data.
struct DatumDataStruct
{
    unsigned int zone;
    double northings, eastings;
    double lat, lon;
};

/// The original test data set was generated using the spreadsheet at:
/// http://www.uwgb.edu/dutchs/UsefulData/UTMFormulas.HTM
/// originally as a utm-to-latlon and latlon-to-utm set (should
/// be easy to tell apart based on the round numbers).
/// Testing with the data raised some suspicions, so the
/// first half of the data (originally UTM-to-Latlon) re-converted using
/// http://home.hiwaay.net/~taylorc/toolbox/geography/geoutm.html
DatumDataStruct testData[] =
{
    {9, 3637397.3, 504490.29, 32.8747, -128.952}, // This gave a UTM easting error at one time
    {13, 7020000.00, 601000.00, 63.29460, -102.98545},
    {45, 4041000.00, 310000.00, -53.74495, 84.11865},
    {30, 1000000.00, 320000.00, 9.04290, -4.63762},
    {1, 2006662.71, 536362.95, -72.036631, -175.94358},
    {22, 3000000.00, 340000.00, 27.11319, -52.61415},
    {43, 4000000.00, 350000.00, -54.12621, 72.704513},
    {32, 5000000.00, 360000.00, 45.13959, 7.21936},
    {51, 6000000.00, 370000.00, -36.136002, 121.55516},
    {23, 7000000.00, 380000.00, 63.1093989, -47.378387},
    {27, 8000000.00, 390000.00, -18.085908, -22.039540},
    {18, 1000000.00, 400000.00, 9.0454332, -75.909879},
    {52, 2000000.00, 410000.00, -72.08165, 126.37834},
    {37, 3000000.00, 420000.00, 27.1201503, 38.19282790},
    {28, 3000000.00, 430000.00, -63.1225521, -16.3878649},
    {19, 4000000.00, 440000.00, 36.142861187, -69.66692297},
    {16, 5002000.00, 450000.00, -45.1337036, -87.6358752},
    {10, 6653097.435007, 611544.041980, 60, -121},  // This one is one the boundary between 10 and 11, which can cause the utm->latlon->utm conversion to fail
    {9, 3988112.0, 770420.7, 36, -126.00001},  // This one is one the easting boundaries between 9 and 10, which can cause the utm->latlon->utm conversion to fail
    {10, 3988112.0, 229587.58, 36, -125.9999},  // This one is one the easting boundaries between 9 and 10, which can cause the utm->latlon->utm conversion to fail
    {16, 3319206.291, 403549.8474, 30, -88},
    {27, 1879826.693, 393552.2529, 17, -22},
    {43, 3320469.355, 692915.1064, 30, 77},
    {51, 6653097.504, 388455.9545, 60, 121},
    {55, 4429673.051, 670725.4996, 40, 149},
    {53, 5792297.556, 324396.6244, -38, 133},
    {36, 5127641.036, 419825.74, -44, 32},
    {54, 1453013.284, 525110.2007, -77, 142},
    {7, 2791172.394, 452844.8776, -65, -142},
    {27, 8894421.383, 609600.7722, -10, -20},
    {17, 3903379.219, 627928.1961, -55, -79},
    {31, 0, 500000, 0, 3},
    {31, 0, 166021.5497, 0, 0},
    {0, 0, 0, 0, 0}
};


/**
 * %Units tests for class Datum
 *
 * \ingroup utils
 */
class Datum_Test : public CxxTest::TestSuite
{
public:

    void testLatLonToUtm( void )
    {
        unsigned int zone = 0;
        double northings = 0.0, eastings = 0.0;
        bool northernHemi = true;
        char message[80];

        for( int i = 0; testData[i].zone != 0; i++ )
        {
            long error = Wgs84::LatLonToUtm( D2R( testData[i].lat ),
                                             D2R( testData[i].lon ),
                                             northings, eastings, zone, northernHemi );

            snprintf( message, 79, "Testing lat/long %.3lf,%.3lf", testData[i].lat, testData[i].lon );
            TSM_ASSERT_EQUALS( message, error, 0 );
            TSM_ASSERT_EQUALS( message, zone, testData[i].zone );
            TSM_ASSERT_DELTA( message, northings, testData[i].northings, UTMFUDGE );
            TSM_ASSERT_DELTA( message, eastings, testData[i].eastings, UTMFUDGE );
            TSM_ASSERT_EQUALS( message, northernHemi, ( testData[i].lat >= 0 ) );

            double lat = 0.0, lon = 0.0;

            // Now test reverse calculation
            error = Wgs84::UtmToLatLon( northings,
                                        eastings,
                                        zone,
                                        northernHemi,
                                        lat, lon );
            lat = R2D( lat );
            lon = R2D( lon );
            TSM_ASSERT_EQUALS( message, error, 0 );
            TSM_ASSERT_DELTA( message, lat, testData[i].lat, LATLONFUDGE );
            TSM_ASSERT_DELTA( message, lon, testData[i].lon, LATLONFUDGE );
        }

    }


    void testUtmToLatLon( void )
    {

        for( int i = 0; testData[i].zone != 0; i++ )
        {
            double lat = 0.0, lon = 0.0;
            char message[80];
            // I'm going to cheat a little since I don't have the N/S
            // hemi info in the table .. just get the answer from the
            // lat

            long error = Wgs84::UtmToLatLon( testData[i].northings,
                                             testData[i].eastings,
                                             testData[i].zone,
                                             testData[i].lat >= 0,
                                             lat, lon );
            lat = R2D( lat );
            lon = R2D( lon );
            snprintf( message, 79, "Testing N/E %.3lf,%.3lf", testData[i].northings, testData[i].eastings );
            TSM_ASSERT_EQUALS( message, error, 0 );
            TSM_ASSERT_DELTA( message, lat, testData[i].lat, LATLONFUDGE );
            TSM_ASSERT_DELTA( message, lon, testData[i].lon, LATLONFUDGE );

            // Now test the reverse calculation
            double northings = 0.0, eastings = 0.0;
            unsigned int zone = 0;
            bool northernHemi = true;

            error = Wgs84::LatLonToUtm( D2R( lat ), D2R( lon ),
                                        northings, eastings, zone, northernHemi );

            TSM_ASSERT_EQUALS( message, error, 0 );
            TSM_ASSERT_EQUALS( message, zone, testData[i].zone );
            TSM_ASSERT_DELTA( message, northings, testData[i].northings, UTMFUDGE );
            TSM_ASSERT_DELTA( message, eastings, testData[i].eastings, UTMFUDGE );
            TSM_ASSERT_EQUALS( message, northernHemi, ( testData[i].lat >= 0 ) );

        }

    }

};



#endif // _DATUM_TEST_H
