/** \file
 *
 *  Specifies the interface details for the HFRCMSpaceInterpolator
 *  component in the EstimationModule.
 *
 *  HFRCMSpaceInterpolator.h should only be included by
 *  HFRCMSpaceInterpolator.cpp
 *  Other classes should include HFRCMSpaceInterpolatorIF.h
 *
 *  Copyright (c) 2013, 2014 MBARI
 *  MBARI Proprietary Information.  All Rights Reserved
 */

#ifndef HFRCMSPACEINTERPOLATOR_H_
#define HFRCMSPACEINTERPOLATOR_H_

#include "component/SyncComponent.h"
#include "data/Mtx.h"
#include "HFRadarCompactModelForecaster.h" // for MAX_EOFS, etc.

class UniversalDataReader;

/**
 *  Specifies the interface details for the HFRCMSpaceInterpolator
 *  component in the EstimationModule.
 *
 *  HFRCMSpaceInterpolator.h should only be included by
 *  HFRCMSpaceInterpolator.cpp
 *  Other classes should include HFRCMSpaceInterpolatorIF.h
 *
 *  \ingroup modules_estimation
 */

class HFRCMSpaceInterpolator : public SyncEstimationComponent
{
public:
    HFRCMSpaceInterpolator( const Module* module );
    virtual ~HFRCMSpaceInterpolator();

    /// Initialize function
    void initialize( void );

    /// The actual "payload" of the component
    void run();

    /// Return the singleton
    static HFRCMSpaceInterpolator* Instance()
    {
        return Instance_;
    }

    /// interpolate EOFs at specified location
    bool lookupEmpiricalOrthogonalFunctions( Mtx& eastEOFs, Mtx& northEOFs, float& eastEM,  float& northEM, float& eastSF,  float& northSF, const float latDeg, const float lonDeg ); // TODO: Is there a reason that I should not make this a static function so that user components to not need to store the pointer to the singleton in order to call the function?
    /// TODO: should these public methods be defined in the IF header?

protected:
    int verbosity_;
    const Mtx eofs_;
    const Mtx ensMean_;
    const Mtx gridIdxRev_;
    const Mtx gridLon_;
    const Mtx gridLat_;
    const Mtx scalingFactors_;
    Mtx gridIdx_;
    const int numLocations_, numModes_;

    // readers & writers
    UniversalDataReader* latitudeReader_;
    UniversalDataReader* longitudeReader_;
    ConfigReader* verbosityLevelConfigReader_;

    bool getLowerLeftCorner( int &latitude_index, int &longitude_index, const float latitude_degrees, const float longitude_degrees );

    float interpolateRaveledTwoDimensionalGrid( const Mtx z, const float latitude_degrees, const float longitude_degrees, const int latitude_index, const int longitude_index, const int starting_offset = 0, const int layer = 0 );

    static HFRCMSpaceInterpolator* Instance_;

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

};

#endif /* HFRCMSPACEINTERPOLATOR_H_ */
