/*@@@**************************************************************************
** \file  gaussPyramid_inline
* \date   Fri Sep 25 08:35:38 EDT 2009
* \author Hernan Badino
* \notes  
*******************************************************************************
*****          (C) COPYRIGHT Hernan Badino - All Rights Reserved          *****
******************************************************************************/

/* INCLUDES */

#if defined ( _OPENMP )
#include <omp.h>
#endif

#include <math.h>
//#include "logger.h"

template <class ImgDType_>
inline
CImagePyramid<ImgDType_>::CImagePyramid ( )
        : m_images_p (                  NULL ),
          m_levels_ui (                    1 ),
          m_width_ui (                     0 ),
          m_height_ui (                    0 ),
          m_buffer_p (                  NULL ),
          m_alloc0level_b (            false )
{
    createBuffers();
}

template <class ImgDType_>
inline
CImagePyramid<ImgDType_>::CImagePyramid (  unsigned int f_width_ui,
                                           unsigned int f_height_ui,
                                           unsigned int f_levels_ui,
                                           bool         f_allocate0level_b )
        : m_images_p (                    NULL ),
          m_levels_ui (                      1 ),
          m_width_ui (              f_width_ui ),
          m_height_ui (            f_height_ui ),
          m_buffer_p (                    NULL ),
          m_alloc0level_b ( f_allocate0level_b )
{
    createBuffers( f_levels_ui );
}

template <class ImgDType_>
inline
CImagePyramid<ImgDType_>::~CImagePyramid ( )
{
    destroyBuffers ();
}

template <class ImgDType_>
inline bool
CImagePyramid<ImgDType_>::createBuffers ( unsigned int f_levels_ui  )
{
    
    m_levels_ui = std::max(
            std::min ( f_levels_ui, 
                       std::max( (unsigned int)(log2(m_width_ui)), 
                                 (unsigned int)(log2(m_height_ui) ) ) ),
            1u );
    
    m_images_p = new CTypedImage<ImgDType_> * [m_levels_ui];

    
    printf("Creating buffers for level %i and width %i height %i\n",
           m_levels_ui, m_width_ui, m_height_ui );

    if (m_levels_ui == 0) return false;
    
    unsigned int w_ui = m_width_ui, h_ui = m_height_ui;
    
    /// First level point to the original image.
    if ( m_alloc0level_b )
        m_images_p[0] = new CTypedImage<ImgDType_> ( w_ui, h_ui );
    else
        m_images_p[0] = NULL;

    for (unsigned int i = 1; i < f_levels_ui; ++i)
    {
        w_ui = (w_ui + 1)/2;
        h_ui = (h_ui + 1)/2;
        
        printf("Level %i and width %i height %i\n",
               i, w_ui, h_ui );

        m_images_p[i] = new CTypedImage<ImgDType_> ( w_ui, h_ui );
    }

    int bufferSize_i;


    IppStatus ippStatus_i = ippiPyrDownGetBufSize_Gauss5x5( m_width_ui, 
                                                            ipp32f, //getDataType(),
                                                            1, 
                                                            &bufferSize_i );

    if (ippStatus_i != ippStsNoErr)
    {
        printf("IPP failed:\n");
        printIPPError( ippStatus_i );
        return false;
    }

    printf("Allocatin buffer of size %i\n", bufferSize_i );
    
    //bufferSize_i;
    
    m_buffer_p = new unsigned char [ m_width_ui * m_height_ui * 4 ];

    return true;
    
}

template <class ImgDType_>
inline void
CImagePyramid<ImgDType_>::destroyBuffers ()
{
    if ( m_buffer_p )
        delete [] m_buffer_p;

    m_buffer_p = NULL;
    
    if ( m_images_p )
    {
        if ( m_alloc0level_b && m_images_p[0] )
            delete m_images_p[0];

        for (unsigned int i = 1; i < m_levels_ui; ++i)
        {
            if (m_images_p[i])
                delete m_images_p[i];
        }

        printf ("m_images_p = %p m_levels_ui = %i\n", m_images_p, m_levels_ui );
        

        //delete [] m_images_p;
    }
    
    m_images_p = 0;
}

template <class ImgDType_>
inline CTypedImage<ImgDType_> * 
CImagePyramid<ImgDType_>::getLevelImage ( unsigned int f_level_ui ) const
{
    if (f_level_ui < m_levels_ui)
        return m_images_p[f_level_ui];
    
    return NULL;
}

template <class ImgDType_>
inline bool
CImagePyramid<ImgDType_>::setLevels ( unsigned int f_levels_ui )
{
    if ( m_levels_ui != f_levels_ui )
    {
        destroyBuffers();    
        return createBuffers ( f_levels_ui );
    }

    return true;
}

template <class ImgDType_>
inline unsigned int
CImagePyramid<ImgDType_>::getLevels ( ) const
{
    return m_levels_ui;
}


template <class ImgDType_>
inline bool
CImagePyramid<ImgDType_>::setImageSize ( unsigned int f_width_ui,
                                         unsigned int f_height_ui )
{
    if ( m_width_ui != f_width_ui ||
         m_height_ui != f_height_ui )
    {
        m_width_ui  = f_width_ui;
        m_height_ui = f_height_ui;
        
        destroyBuffers();
        return createBuffers( m_levels_ui );
    }

    return true;
}

template <class ImgDType_>
inline bool
CImagePyramid<ImgDType_>::setPyramidParams  ( unsigned int f_width_ui,
                                              unsigned int f_height_ui,
                                              unsigned int f_levels_ui )
{
    if ( m_width_ui != f_width_ui ||
         m_height_ui != f_height_ui ||
         m_levels_ui != f_levels_ui )
    {
        m_width_ui  = f_width_ui;
        m_height_ui = f_height_ui;
        
        destroyBuffers();
        return createBuffers( f_levels_ui );
    }
    
    return true;
}

template <class ImgDType_>
inline unsigned int
CImagePyramid<ImgDType_>::getWidth ( ) const
{
    return m_width_ui;
}

template <class ImgDType_>
inline unsigned int
CImagePyramid<ImgDType_>::getHeight ( ) const
{
    return m_height_ui;
}

template <class ImgDType_>
inline bool
CImagePyramid<ImgDType_>::is0LevelAllocated ( ) const
{
    return m_alloc0level_b;
}


template <class ImgDType_>
inline void
CImagePyramid<ImgDType_>::setAllocated0Level ( bool f_allocate_b )
{
    if ( f_allocate_b == m_alloc0level_b) return;
    
    if ( m_alloc0level_b )
    {
        if ( m_images_p[0] )
            delete m_images_p[0];
    
        m_images_p[0] = NULL;
    }
    else
    {
        m_images_p[0] = new CTypedImage<ImgDType_> ( m_width_ui, 
                                                     m_height_ui );
    }

    m_alloc0level_b = f_allocate_b;    
}


/* ////////////  Version History ///////////////
 *  $Log: imagePyramid_inline.h,v $
 *  Revision 1.2  2009/11/18 15:51:01  badino
 *  badino: documentation added. Some other global changes.
 *
 *//////////////////////////////////////////////
