/** \file
 *
 *  Contains the EnvSimulator class declaration.
 *
 *  Copyright (c) 2007,2008,2009 MBARI
 *  MBARI Proprietary Information.  All Rights Reserved
 */

#ifndef EnvSimulator_H_
#define EnvSimulator_H_

#include "Simulator.h"
#include "utils/NetCdfReader.h"

/**
 *  The EnvSimulator adds lookup of environmental parameters to the base
 *  Simulator class
 *
 *  \ingroup modules_EnvSimulator
 */
class EnvSimulator: public Simulator
{
public:

    /// Constructor.
    EnvSimulator( bool simulateSensors, int nSteps, bool debug = false );

    /// Destructor.
    virtual ~EnvSimulator()
    {
        uninitialize();
    };

    /// Uninitialize the simulation
    virtual void uninitialize();

protected:

    struct VarData
    {

        // NetCdf variable that contains temperature
        NetCdfReader::NetCdfVar* var_;

        // temperature array data
        float array_[2][2][2][2];

        // preserve indices to cut down on NetCDF reads
        int indices_[4];

        VarData();
    };

    virtual void configureSensors();

    void azimuthalEquidistantToCoordinates( double &Xm, double &Ym, double depLoc, double latDeg, double lonDeg );

    void transverseMercatorToCoordinates( double &Xm, double &Ym, double depLoc, double latDeg, double lonDeg );

    virtual void simulateSensors( double time, double latDeg, double lonDeg, SimResultStruct& results );

    // Gridded data file reader
    NetCdfReader* netCdfReader_;

    // time array
    float* modelTime_;

    // size of time Array
    unsigned int modelTimeSize_;

    // depth array
    float* modelDepth_;

    // size of depth Array
    unsigned int modelDepthSize_;

    // latitude array
    float* modelLatitude_;

    // size of latitude Array
    unsigned int modelLatitudeSize_;

    // longitude array
    float* modelLongitude_;

    /// size of longitude Array
    unsigned int modelLongitudeSize_;

    /// NetCdf variable that contains latitude
    NetCdfReader::NetCdfVar* varLatitude_;

    /// NetCdf variable that contains longitude
    NetCdfReader::NetCdfVar* varLongitude_;

    // projection Y array
    float* modelY_;

    // size of projection Y Array
    unsigned int modelYSize_;

    // projection X array
    float* modelX_;

    // size of projection X Array
    unsigned int modelXSize_;

    /// Variable that contains salinity
    VarData varSalinity_;

    // Variable that contains temperature
    VarData varTemperature_;

    // Variable that contains u
    VarData varEastCurrent_;

    // Variable that contains v
    VarData varNorthCurrent_;

    // Other variables
    VarData* vars_;

    //------------------ Environmental Model interpolation ----------------
    bool interpolate( const float& time, const float& depth, const float& lat, const float& lon,
                      int& timeIndex, int& depthIndex, int& latIndex, int& lonIndex,
                      VarData& var, float& value );

    bool interpolate( const float& time, const float& depth, const float& lat, const float& lon,
                      int& timeIndex, int& depthIndex, int& latIndex, int& lonIndex,
                      int varIndices[4], float varArray[2][2][2][2], NetCdfReader::NetCdfVar* var, float& value );

    /// Interpolates a value on two lines, from (x0, y0) to (x1, y1) to (x2, y2)
    /// Does not extrapolate -- rather, it pins values
    float twoLineEstimate( const float x, const float y0, const float y1, const float y2,
                           const float x0, const float x1, const float x2 );

    enum GridMapping
    {
        GRID_MAPPING_NONE,
        GRID_MAPPING_AZIMUTHAL_EQUIDISTANT,
        GRID_MAPPING_TRANSVERSE_MERCATOR,
    };

    // Coordinate mapping transformation name
    GridMapping gridMapping_;

    // Coordinate mapping parameters
    double scaleCentralMeridian_;
    double lonCentralMeridian_;
    double lonProjectionOrigin_;
    double latProjectionOrigin_;
    double falseEasting_;
    double falseNorthing_;

    // Array to speed decompression of compressed data
    int* decompress_;


private:
    // Note that the copy constructor below is private and not given a body.
    // Any attempt to call it will return a compiler error.
    EnvSimulator( const EnvSimulator& old ); // disallow copy constructor

};

#endif /*EnvSimulator_H_*/
