#ifndef __PYRDYNPROG_H
#define __PYRDYNPROG_H

/*@@@*************************************************************************/
/** \file  dynProg.h
 * \date   Wed March 7 16:51 CET 2007
 * \author Hernan Badino
 * \notes  
*******************************************************************************
******************************************************************************/

/* INCLUDES */
//#include "dynProg.h"
#include <vector>
#include "floatImage.h"
#include "dynProgOp.h"

/* CONSTANTS */
#define PDP_MAX_LEVELS 15

/* PROTOTYPES */

/* ******************************** CLASS ********************************** */
/**
 * Pyramidal implementation of the dynamic programming algorithm. The
 * measured improvement in the speed factor for 5 levels is about 27!
 *
 * \brief    Pyramidal implementation of the dynamic programming algorithm.
 * \author   Hernan Badino
 * \date     20.11.2007
 * \note     -
 * \sa       -
 *
 *************************************************************************** */
namespace VIC
{

    /* PROTOTYPES */
    
    
    class CPyramidalDynProg
    {
    public:
        /******************************/
        /*  DATA TYPES and CONSTANTS  */
        /******************************/

    public:
    
        /******************************/
        /*  Constructors/Destructor   */
        /******************************/

        CPyramidalDynProg(  );

        CPyramidalDynProg( const int f_width_i,
                           const int f_height_i,
                           const int f_levels_i );

        virtual ~CPyramidalDynProg( );
    
        /******************************/
        /*    COMPUTE METHODS         */
        /******************************/
    
        virtual bool compute ( const CFloatImage      & f_costImg,
                               std::vector<int>       & fr_vecRes_v,
                               const std::vector<int> & f_followPath    = std::vector<int>(0),
                               const std::vector<int> & f_pathTolVector = std::vector<int>(0) );
    
        /******************************/
        /*    SET GET METHODS         */
        /******************************/
    
        void setPyramidParams ( const int f_width_i,
                                const int f_height_i,
                                const int f_levels_i );
    
        int getMaxLevel ( ) const { return m_maxLevel_i; }
    
        const CDynamicProgrammingOp *  getDynProgObj ( const int f_level_i ) const
        {
            if (f_level_i >= PDP_MAX_LEVELS) return 0;
            return m_dynProgObj_p[f_level_i];
        }
    
    
        void  setDistanceCost ( const float f_distCost_f );
        float getDistanceCost ( ) const { return m_dynProgObj_p[0] -> getDistanceCost ( ); }

        void  setDistanceTh ( const float f_distTh_f );
        float getDistanceTh ( ) const { return m_dynProgObj_p[0] -> getDistanceTh ( ); }

        void  setPredictionCost ( const float f_predCost_f );
        float getPredictionCost ( ) const { return m_dynProgObj_p[0] -> getPredictionCost ( ); }

        void  setPredictionTh ( const float f_predTh_f );
        float getPredictionTh ( ) const { return m_dynProgObj_p[0] -> getPredictionTh ( ); }

        void  setInitialCost ( const float f_initialCost_f );
        float getInitialCost ( ) const { return m_dynProgObj_p[0] -> getInitialCost ( ); }

        void  setMinCostValue ( const float f_minCost_f );
        float getMinCostValue ( ) const { return m_dynProgObj_p[0] -> getMinCostValue ( ); }

        void  setMaxCostValue ( const float f_maxCost_f );
        float getMaxCostValue ( ) const { return m_dynProgObj_p[0] -> getMaxCostValue ( ); }

        void  setApplyMedianFilter ( const bool f_apply_b );
        bool  getApplyMedianFilter ( ) const { return m_dynProgObj_p[0] -> getApplyMedianFilter ( ); }

        void  setApplyMedianFilterAllLevels ( const bool f_applyMFAllLevels_b );
        bool  getApplyMedianFilterAllLevels ( ) const { return m_applyMFAllLevels_b; }

        void  setMedFiltKernelSize ( const int f_size_i );
        int   getMedFiltKernelSize ( ) const { return m_dynProgObj_p[0] -> getMedFiltKernelSize ( ); }

        void  setFollowPathTolerance ( const int f_tol_i );
        int   getFollowPathTolerance ( ) const { return m_dynProgObj_p[0] -> getFollowPathTolerance ( ); }
    
        int   getWidth()  const { return m_dynProgObj_p[0] -> getWidth(); }
        int   getHeight() const { return m_dynProgObj_p[0] -> getHeight(); }
    
        void  setExpectedGradient ( const float * const f_vec_p );
        const float * getExpectedGradient ( ) const { return m_dynProgObj_p[0] -> getExpectedGradient ( ); }

        void  setDistCostVector ( std::vector <float> * const f_vec_p );
        const std::vector <float> * getDistCostVector ( ) const { return m_dynProgObj_p[0] -> getDistCostVector ( ); }

        /******************************/
        /*    PROTECTED METHODS       */
        /******************************/
    protected:

        bool computePyramidImgs ( const CFloatImage * const f_costImg_p );
    
        void create( const int f_width_i,
                     const int f_height_i,
                     const int f_levels_i );
    
        void destroy ( );
    
        /******************************/
        /*    PROTECTED MEMBERS       */
        /******************************/
    protected:

        /// Vector for storing intermediate pyramid results.
        std::vector<int>                  m_currPath_v;

        /// Other vector for storing intermediate pyramid results.
        std::vector<int>                  m_levelVecRes_v;

        /// Vector for storing the follow path converted to the last pyramid level.
        std::vector<int>                  m_levelFollowPath_v;
        
        /// Vector for storing the path tolerance converted to the last pyramid level.
        std::vector<int>                  m_levelPathTolVec_v;

        /// Vector for storing expected gradient at each position.
        float *                           m_expectedGradient_p[PDP_MAX_LEVELS];

        /// Number of pyramid levels ( 0 means only original image).
        int                               m_maxLevel_i;

        /// Pyramids.
        CFloatImage *                     m_pyrImg_p[PDP_MAX_LEVELS];

        /// Dynamic Programming Objects.
        CDynamicProgrammingOp *           m_dynProgObj_p[PDP_MAX_LEVELS];

        /// Apply median filter to all levels?
        bool                              m_applyMFAllLevels_b;

    };
}

#endif // __PYRDYNPROG_H

