#ifndef __PYRDPSTEREO_H
#define __PYRDPSTEREO_H

/*@@@**************************************************************************
 ** \file  pyrDPStereo
 * \date   Mon Sep 28 10:39:47 EDT 2009
 * \author Hernan Badino
 * \notes  
*******************************************************************************
*****          (C) COPYRIGHT Hernan Badino - All Rights Reserved          *****
******************************************************************************/

/* INCLUDES */
#include "floatImage.h"
#include "standardTypes.h"
#include "gaussianPyramid.h"
#include "dynProgOp.h"
#include "dsi.h"


/* CONSTANTS */

namespace VIC
{
    class CParameterSet;

    class CPyramidalDynProgStereo
    {
        
    public:
        CPyramidalDynProgStereo( unsigned int f_imageWidth_ui,
                                 unsigned int f_imageHeight_ui,
                                 unsigned int f_levels_ui );

        virtual ~CPyramidalDynProgStereo( );

    /// Computation.
    public:

        bool              compute ( const CFloatImage &f_leftImg,
                                    const CFloatImage &f_rightImg );
        
        
        /// Get/Set
    public:
        /// Get parameter set.
        CParameterSet *   getParameterSet ( );

    /// Get/Set
    public:
        CFloatImage *     getDisparityImage () const;
        
        bool              setPyramidParams ( unsigned int f_imageWidth_ui,
                                             unsigned int f_imageHeight_ui,
                                             unsigned int f_levels_ui );
                       
        bool              setLevels ( unsigned int f_levels_ui );
        unsigned int      getLevels ( ) const;

        bool              setDisparityRange ( S2D<int> f_dispRange );
        S2D<int>          getDisparityRange ( ) const;
        
        bool              setKernelSize ( S2D<unsigned int> f_kernelSize );
        S2D<unsigned int> getKernelSize ( ) const;

    /// Get/Set by level
    public:
        
        struct SDynProgLevelParam
        {
            SDynProgLevelParam() { memset(this, 0, sizeof(SDynProgLevelParam)); }
            
            CDynamicProgrammingOp * dp_p;

            bool   setDistanceCost ( float val ) { distCost_f = val; if (dp_p) dp_p->setDistanceCost ( val ); return true; }
            float  getDistanceCost ( ) const { if (dp_p) return dp_p->getDistanceCost ( ); return distCost_f; }

            bool   setMaxCostDist ( float val ) { maxCostDist_f = val; if (dp_p) dp_p->setDistanceTh ( val ); return true; }
            float  getMaxCostDist ( ) const { if (dp_p) return dp_p->getDistanceTh ( ); return maxCostDist_f; }
            
            bool   setPredictionCost ( float val ) { predictionCost_f = val;  if (dp_p) dp_p->setDistanceCost ( val ); return true; }
            float  getPredictionCost ( ) const { if (dp_p) return dp_p->getDistanceCost ( ); return predictionCost_f; }
            
            bool   setMaxPredictionDist ( float val ) { maxPredCost_f = val; if (dp_p) dp_p->setPredictionTh ( val ); return true; }
            float  getMaxPredictionDist ( ) const { if (dp_p) return dp_p->getPredictionTh ( ); return maxPredCost_f; }
            
            bool   setInitialCost ( float val ) { initialCost_f = val; if (dp_p) dp_p->setInitialCost ( val ); return true; }
            float  getInitialCost ( ) const { if (dp_p) return dp_p->getInitialCost ( ); return initialCost_f; }
            
            bool   setMinCost ( float val ) { minCost_f = val; if (dp_p) dp_p->setMinCostValue ( val ); return true; }
            float  getMinCost ( ) const { if (dp_p) return dp_p->getMinCostValue ( ); return minCost_f; }

            bool   setMaxCost ( float val ) { maxCost_f = val; if (dp_p) dp_p->setMaxCostValue ( val ); return true; }
            float  getMaxCost ( ) const { if (dp_p) return dp_p->getMaxCostValue ( ); return maxCost_f; }
            
            bool   setApplyMedianFilter ( bool val ) { applyMF_b = val; if (dp_p) dp_p->setApplyMedianFilter ( val ); return true; }
            bool   getApplyMedianFilter ( ) const { if (dp_p) return dp_p->getApplyMedianFilter ( ); return applyMF_b; }
            
            bool   setFollowPathTolerance ( int val ) { followPathTol_i = val; if (dp_p) dp_p->setFollowPathTolerance ( val ); return true; }
            int    getFollowPathTolerance ( ) const { if (dp_p) return dp_p->getFollowPathTolerance ( ); return followPathTol_i; }

            void   applyParametersToObject()
            {
                if (!dp_p) return;
                dp_p->setDistanceCost        ( distCost_f ); 
                dp_p->setDistanceTh          ( maxCostDist_f ); 
                dp_p->setPredictionCost      ( predictionCost_f ); 
                dp_p->setPredictionTh        ( maxPredCost_f ); 
                dp_p->setInitialCost         ( initialCost_f ); 
                dp_p->setMinCostValue        ( minCost_f ); 
                dp_p->setMaxCostValue        ( maxCost_f ); 
                dp_p->setApplyMedianFilter   ( applyMF_b ); 
                dp_p->setFollowPathTolerance ( followPathTol_i ); 
            }
            

            float distCost_f;
            float maxCostDist_f;
            float predictionCost_f;
            float maxPredCost_f;
            float initialCost_f;
            float minCost_f;
            float maxCost_f;
            bool  applyMF_b;
            int   followPathTol_i;
        };

    /// Help Methods.
    protected:

        void              updateParamDsi();
        void              updateParamDynProgOp();
        bool              transferLevel ( int f_level_ui );
        bool              computeDynProg ( int f_level_ui );

    /// Const Static Methods.
    protected:
#define m_maxLevels_si 6u

    /// Members
    protected:

        typedef CDispSpaceImageOp<float, float> CTestFloatDSI_t;

        /// Left image pyramid.
        CGaussianPyramid<float> m_pyrLeft;

        /// Right image pyramid.
        CGaussianPyramid<float> m_pyrRight;
        
        /// Disparity image pyramid.
        CImagePyramid<float>    m_pyrDisp;

        /// DSI operator.
        CTestFloatDSI_t *       m_dsi_p;

        /// Dynammic Programming operators.
        CDynamicProgrammingOp * m_dynProg_p;

        /// Levels
        unsigned int            m_levels_ui;
        
        /// Range of disparities.
        S2D<int>                m_dispRange;

        /// Disparity depth.
        //int                     m_dispDepth_i;

        /// Range of disparities.
        S2D<unsigned int>       m_kernelSize;

        /// Dynamic programming parameters.
        SDynProgLevelParam      m_dpParams_p[m_maxLevels_si];
    };
}


#endif // __PYRDPSTEREO_H
