/*
 * (C) Copyright 1996-2016 ECMWF & INPE.
 *
 * This software is licensed under the terms of the Apache Licence Version 2.0
 * which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
 * In applying this licence, ECMWF does not waive the privileges and immunities
 * granted to it by virtue of its status as an intergovernmental organisation nor
 * does it submit to any jurisdiction.
 */

/*! \file TeDatum.h
    \brief This file contains structures and definitions to support the concept of a planimetric datum
*/

#ifndef __TERRALIB_INTERNAL_DATUM_H
#define __TERRALIB_INTERNAL_DATUM_H

#include <string>
#include "TeUtils.h"

//! Number of supported datum in TerraLib
const int NUM_DATUM = 9;

TL_DLL const char** TeGetDatumList();


//! Implements valid Datum options and related parameters which account for different earth spheroids.
/*! Specifies planimetric TeDatum parameters to be used for defining geodetic
    coordinates, which are necessary to establish a map projection system.
    It encapsulates the following important information regarding
    a planimetric Datum such as:
    \li	Datum name;
    \li	Earth equatorial radius;
    \li	Earth flatenning;
    \li	Datum shifts.

    \author
     Ubirajara Freitas, Julio d'Alge.

    \sa TeDatumFactory
*/
class TL_DLL TeDatum {
private:
    std::string name_;  //!< Planimetric TeDatum name
    double rd_,         //!< Earth equatorial radius (m)
        flt_;           //!< Earth flattening
public:
    double dx_,  //!< TeDatum shift along x axis (m)
        dy_,     //!< TeDatum shift along y axis (m)
        dz_;     //!< TeDatum shift along z axis (m)

    //!	Constructor.
    TeDatum(std::string name = "Spherical", double rd = 6.371000e+06, double flt = 0., double dx = 0., double dy = 0.,
            double dz = 0.) :
        name_(name), rd_(rd), flt_(flt), dx_(dx), dy_(dy), dz_(dz) {}

    //! Copy constructor
    TeDatum(const TeDatum& other);

    //! Operator =
    TeDatum& operator=(const TeDatum& rhs);

    //!	Destructor.
    ~TeDatum() {}

    //! Returns the datum name
    std::string name() const { return name_; }

    //! Sets the datum name
    void name(const std::string& name) { name_ = name; }

    //! Returns Earth equatorial radius (m)
    double radius() const { return rd_; }

    //! Sets Earth equatorial radius (m)
    void radius(const double rd) { rd_ = rd; }

    //! Returns the Earth equatorial radius (m) (m)
    double flattening() const { return flt_; }

    //! Sets the Earth equatorial radius (m) (m)
    void flattening(const double flt) { flt_ = flt; }

    //! Returns the shift along x axis (m)
    double xShift() const { return dx_; }

    //! Returns the shift along y axis (m)
    double yShift() const { return dy_; }

    //! Returns the shift along z axis (m)
    double zShift() const { return dz_; }


    //!		Verifies if current TeDatum is equal to TeDatum& dat.
    bool operator==(const TeDatum& dat) const {
        return (TeFPEquals(rd_, dat.rd_, 0.0000000001) && TeFPEquals(flt_, dat.flt_, 0.0000000001) &&
                TeFPEquals(dx_, dat.dx_, 0.0000000001) && TeFPEquals(dy_, dat.dy_, 0.0000000001) &&
                TeFPEquals(dz_, dat.dz_, 0.0000000001));
    }

    //! Returns the Datum description in PROJ4 format
    string getProj4Description();

    //! Returns the Datum description in WKT format
    string getWKTDescription();
};

//! Produces a Datum accordingly to an specified name
class TL_DLL TeDatumFactory {
public:
    //! Builds a datum from a TerraLib name
    static TeDatum make(const std::string& name);

    //! Builds a datum from its EPSG code
    static TeDatum makeFromEPSGCode(const std::string epsgCode);

    //! Builds a datum from its OGC's WKT description
    static TeDatum makeFromWKT(const std::string wktDatumDescription);
};

/*!
   \fn   findDatum(double semiMajor, double flatenning, TeDatum& datum)
   \brief Tries to find the a TeDatum according to givem semi major axis and earth flattening
 */
TL_DLL bool findDatum(double semiMajor, double flatenning, TeDatum& datum);

#endif
