#ifndef __TYPEDIMAGE_H
#define __TYPEDIMAGE_H

/**
 *******************************************************************************
 *
 * @file typedImage.h
 *
 * \class CTypedImage
 * \date  Tue Oct 13, 2009
 * \author Hernan Badino (hernan.badino@gmail.com)
 *
 * \brief Provides a templated interface for typed images.
 *
 * The class is derived from CImageBase, specifying new methods
 * for accessing raw data content ( getData(), getScanline(unsigned int) ).
 * The virtual method initializeTypedImage() is called from the constructors
 * to initialize the bytes per pixel of the data type, the data type format and
 * the image format. Specific instantiations of the template must implement this
 * function to override default values. The instantianted type must be a raw data
 * type or a class having a copy operator (=) and the equality comparison 
 * operator (==).
 *
 *
 *******************************************************************************/


/* INCLUDES */
#include "imageBase.h"

/* CONSTANTS */

namespace VIC
{
    template <class _Type>
    class CTypedImage : public CImageBase
    {
    /// Constructors/Destructor
    public:
        
        /// Default constructor.
        CTypedImage ( );

        /// Constructor with size.
        CTypedImage (  unsigned int f_width_ui,
                       unsigned int f_height_ui );

        /// Constructor with size.
        CTypedImage ( S2D<unsigned int> f_size );

        /// Copy constructor.
        CTypedImage ( const CImageBase & f_other );

        /// Copy constructor.
        CTypedImage ( const CImageBase & f_other, bool f_allocate_b );

        /// Destructor.
        virtual ~CTypedImage ( );

    /// Gets/Sets
    public:
        /// Get Data.
        virtual _Type *   getData ( ) const;

        /// Get Scanline
        virtual _Type *   getScanline ( unsigned int i ) const;

        /// Get Scanline
        virtual _Type *   operator[] ( unsigned int i ) const;

        /// Set Data.
        virtual void      setData( _Type *  f_data_p );


    /// Help methods.
    public:
        /// Clear image.
        virtual void      fill ( const _Type f_val );

    /// Operators
    public:
       /// Operator =.
        CTypedImage<_Type>  &
                     operator = ( const CImageBase & f_other );
    /// Gets/Sets
    protected:
        virtual void initializeTypedImage();
    };
    

    /// Default constructor.
    template < class _Type >
    CTypedImage<_Type>::CTypedImage ( )
            : CImageBase ( )
    {
        initializeTypedImage();
    }
    
    
    /// Constructor with size.
    template < class _Type >
    CTypedImage<_Type>::CTypedImage ( unsigned int f_width_ui,
                                      unsigned int f_height_ui )
            : CImageBase ( )
    {
        m_width_ui  = f_width_ui;
        m_height_ui = f_height_ui;
        
        initializeTypedImage();
        ensureAllocation();
    }
    

    /// Constructor with size.
    template < class _Type >
    CTypedImage<_Type>::CTypedImage ( S2D<unsigned int> size )
            : CImageBase ( )
    {
        m_width_ui  = size.width;
        m_height_ui = size.height;
        
        initializeTypedImage();
        ensureAllocation();
    }
    
    /// Copy constructor.
    template < class _Type >
    CTypedImage<_Type>::CTypedImage ( const CImageBase & f_other )
            : CImageBase ( f_other )
    {
    }
    
    
    /// Copy constructor.
    template < class _Type >
    CTypedImage<_Type>::CTypedImage ( const CImageBase & f_other, 
                                      bool               f_allocate_b )
            : CImageBase ( f_other, f_allocate_b )
    {
    }

    /// Set Data.
    template < class _Type >
    inline void
    CTypedImage<_Type>::initializeTypedImage()
    {
        setBytesPerPixel ( sizeof(_Type) );
        setDataType ( IDT_OTHER );
        setImageFormat ( CImageBase::IF_OTHER );
    }
    

    /// Destructor.
    template < class _Type >
    CTypedImage<_Type>::~CTypedImage ( )
    {
    }
    
    /// Get Typed Data.
    template < class _Type >
    inline _Type *
    CTypedImage<_Type>::getData( ) const
    {
        return (_Type *) m_data_p;
    }
    

    /// Get Scanline
    template < class _Type >
    inline _Type *
    CTypedImage<_Type>::getScanline ( unsigned int i ) const
    {
        return ((_Type *) m_data_p) + i * m_width_ui;   
    }
    
    /// Get Scanline with [] operator
    template < class _Type >
    inline _Type *
    CTypedImage<_Type>::operator [] ( unsigned int i ) const
    {
        return ((_Type *) m_data_p) + i * m_width_ui;   
    }
 
    /// Set Data.
    template < class _Type >
    inline void
    CTypedImage<_Type>::setData( _Type *  f_data_p )
    {
        CImageBase::setData ( (uint8_t *) f_data_p );
    }

    /// Operator =.
    template < class _Type >
    inline CTypedImage<_Type> &
    CTypedImage<_Type>::operator = ( const CImageBase & f_other )
    {
        CImageBase::operator = ( f_other );
        return *this;
    }
    
    /// Fill image with constant
    template < class _Type >
    inline void
    CTypedImage<_Type>::fill ( const _Type f_val)
    {    
        if ( m_data_p == NULL )
            return;
        
        _Type *  data_p = (_Type *) m_data_p;
        _Type *  end_p  = ((_Type *) (data_p)) + m_width_ui * m_height_ui;  
        for (; data_p < end_p; ++data_p)
        {
            *data_p = f_val;   
        }
    }
}


#endif // __TYPEDIMAGE_H

/* ////////////  Version History ///////////////
 *  $Log: typedImage.h,v $
 *  Revision 1.3  2009/11/18 15:51:01  badino
 *  badino: documentation added. Some other global changes.
 *
 *  Revision 1.2  2009/10/13 19:52:26  badino
 *  badino: added documentation.
 *
 *//////////////////////////////////////////////
